From 3317085a7f483d7e3b1c1344f2c086ad326dffa2 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 10 Nov 2021 19:57:10 +0530 Subject: [PATCH 001/109] wip Signed-off-by: Abhishek Kumar --- .../configuration/ConfigurationService.java | 6 + .../java/com/cloud/dc/PodGuestIp6Prefix.java | 30 ++++ .../com/cloud/dc/PodManagementIp6Range.java | 38 +++++ .../main/java/com/cloud/event/EventTypes.java | 3 + .../Ip6GuestPrefixSubnetNetworkMap.java | 36 ++++ .../com/cloud/offering/NetworkOffering.java | 25 ++- .../apache/cloudstack/api/ApiConstants.java | 5 + .../CreateGuestNetworkIp6PrefixCmd.java | 112 ++++++++++++ .../CreateManagementNetworkIpRangeCmd.java | 21 ++- .../network/CreateNetworkOfferingCmd.java | 10 ++ .../api/response/IpRangeResponse.java | 27 ++- .../cloudstack/api/response/PodResponse.java | 20 +++ .../configuration/ConfigurationManager.java | 5 +- .../orchestration/NetworkOrchestrator.java | 20 +-- .../com/cloud/dc/PodGuestIp6PrefixVO.java | 107 ++++++++++++ .../com/cloud/dc/PodManagementIp6RangeVO.java | 160 ++++++++++++++++++ .../cloud/dc/dao/PodGuestIp6PrefixDao.java | 30 ++++ .../dc/dao/PodGuestIp6PrefixDaoImpl.java | 50 ++++++ .../dc/dao/PodManagementIp6RangeDao.java | 30 ++++ .../dc/dao/PodManagementIp6RangeDaoImpl.java | 50 ++++++ .../main/java/com/cloud/dc/dao/VlanDao.java | 2 + .../java/com/cloud/dc/dao/VlanDaoImpl.java | 15 ++ .../Ip6GuestPrefixSubnetNetworkMapVO.java | 103 +++++++++++ .../Ip6GuestPrefixSubnetNetworkMapDao.java | 26 +++ ...Ip6GuestPrefixSubnetNetworkMapDaoImpl.java | 67 ++++++++ .../offerings/dao/NetworkOfferingDao.java | 2 + .../offerings/dao/NetworkOfferingDaoImpl.java | 11 ++ ...spring-engine-schema-core-daos-context.xml | 3 + .../META-INF/db/schema-41610to41700.sql | 45 +++++ .../management/ContrailManagerImpl.java | 22 +-- .../java/com/cloud/api/ApiResponseHelper.java | 27 ++- .../ConfigurationManagerImpl.java | 91 ++++++++-- .../com/cloud/network/NetworkServiceImpl.java | 62 +++++++ .../cloud/server/ManagementServerImpl.java | 10 +- .../vpc/MockConfigurationManagerImpl.java | 9 +- .../CreateNetworkOfferingTest.java | 20 +-- ui/public/locales/en.json | 6 + .../views/infra/network/IpRangesTabGuest.vue | 150 +++++++++++++++- .../infra/network/IpRangesTabManagement.vue | 120 ++++++++++++- .../views/infra/network/IpRangesTabPublic.vue | 120 +++++++++---- ui/src/views/offering/AddNetworkOffering.vue | 18 ++ 41 files changed, 1610 insertions(+), 104 deletions(-) create mode 100644 api/src/main/java/com/cloud/dc/PodGuestIp6Prefix.java create mode 100644 api/src/main/java/com/cloud/dc/PodManagementIp6Range.java create mode 100644 api/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMap.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIp6PrefixCmd.java create mode 100644 engine/schema/src/main/java/com/cloud/dc/PodGuestIp6PrefixVO.java create mode 100644 engine/schema/src/main/java/com/cloud/dc/PodManagementIp6RangeVO.java create mode 100644 engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDao.java create mode 100644 engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDaoImpl.java create mode 100644 engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDao.java create mode 100644 engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDaoImpl.java create mode 100644 engine/schema/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMapVO.java create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDao.java create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDaoImpl.java diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index 38d9d3243cf3..d0207d5bad80 100644 --- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java +++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java @@ -19,6 +19,7 @@ import java.util.List; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; +import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIp6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; @@ -213,6 +214,11 @@ public interface ConfigurationService { */ void updatePodIpRange(UpdatePodManagementNetworkIpRangeCmd cmd) throws ConcurrentOperationException; + /** + * ToDo + */ + Pod createPodGuestIp6Prefix(CreateGuestNetworkIp6PrefixCmd cmd); + /** * Edits a pod in the database. Will not allow you to edit pods that are being used anywhere in the system. * diff --git a/api/src/main/java/com/cloud/dc/PodGuestIp6Prefix.java b/api/src/main/java/com/cloud/dc/PodGuestIp6Prefix.java new file mode 100644 index 000000000000..38dfddd32d6d --- /dev/null +++ b/api/src/main/java/com/cloud/dc/PodGuestIp6Prefix.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.dc; + +import org.apache.cloudstack.acl.InfrastructureEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface PodGuestIp6Prefix extends InfrastructureEntity, InternalIdentity, Identity { + Long getDataCenterId(); + + Long getPodId(); + + String getPrefix(); +} diff --git a/api/src/main/java/com/cloud/dc/PodManagementIp6Range.java b/api/src/main/java/com/cloud/dc/PodManagementIp6Range.java new file mode 100644 index 000000000000..ef3416adb3e3 --- /dev/null +++ b/api/src/main/java/com/cloud/dc/PodManagementIp6Range.java @@ -0,0 +1,38 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.dc; + +import org.apache.cloudstack.acl.InfrastructureEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface PodManagementIp6Range extends InfrastructureEntity, InternalIdentity, Identity { + Long getDataCenterId(); + + Long getPodId(); + + String getGateway(); + + String getCidr(); + + Integer getVlan(); + + String getStartIp(); + + String getEndIp(); +} \ No newline at end of file diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 7533e58d4f34..1e9fef212be2 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -330,6 +330,9 @@ public class EventTypes { public static final String EVENT_MANAGEMENT_IP_RANGE_DELETE = "MANAGEMENT.IP.RANGE.DELETE"; public static final String EVENT_MANAGEMENT_IP_RANGE_UPDATE = "MANAGEMENT.IP.RANGE.UPDATE"; + public static final String EVENT_PUBLIC_IP6_PREFIX_CREATE = "PUBLIC.IP6.PREFIX.CREATE"; + public static final String EVENT_PUBLIC_IP6_PREFIX_DELETE = "PUBLIC.IP6.PREFIX.DELETE"; + public static final String EVENT_STORAGE_IP_RANGE_CREATE = "STORAGE.IP.RANGE.CREATE"; public static final String EVENT_STORAGE_IP_RANGE_DELETE = "STORAGE.IP.RANGE.DELETE"; public static final String EVENT_STORAGE_IP_RANGE_UPDATE = "STORAGE.IP.RANGE.UPDATE"; diff --git a/api/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMap.java b/api/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMap.java new file mode 100644 index 000000000000..3b764b1b8269 --- /dev/null +++ b/api/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMap.java @@ -0,0 +1,36 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface Ip6GuestPrefixSubnetNetworkMap extends Identity, InternalIdentity { + enum State { + Allocated, // The subnet is in use. + Free // The subnet is ready to be allocated. + } + + long getPrefixId(); + + String getSubnet(); + + Long getNetworkId(); + + State getState(); +} diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java index 594938775c8d..738f0a55ed10 100644 --- a/api/src/main/java/com/cloud/offering/NetworkOffering.java +++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java @@ -16,15 +16,17 @@ // under the License. package com.cloud.offering; +import java.util.Date; + import org.apache.cloudstack.acl.InfrastructureEntity; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; +import org.apache.commons.lang3.StringUtils; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network.GuestType; import com.cloud.network.Networks.TrafficType; -import java.util.Date; - /** * Describes network offering * @@ -40,7 +42,24 @@ public enum State { } public enum Detail { - InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RelatedNetworkOffering, domainid, zoneid, pvlanType + InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RelatedNetworkOffering, domainid, zoneid, pvlanType, internetProtocol + } + + public enum InternetProtocol { + IPv4, IPv6, DualStack; + + public static InternetProtocol fromValue(String protocol) { + if (StringUtils.isBlank(protocol)) { + return null; + } else if (protocol.equalsIgnoreCase("IPv4")) { + return IPv4; + } else if (protocol.equalsIgnoreCase("IPv6")) { + return IPv6; + } else if (protocol.equalsIgnoreCase("DualStack")) { + return DualStack; + } + throw new InvalidParameterValueException("Unexpected Internet Protocol : " + protocol); + } } public final static String SystemPublicNetwork = "System-Public-Network"; diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index b19819c36f1a..510adbc6aaea 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -192,12 +192,14 @@ public class ApiConstants { public static final String ID = "id"; public static final String IDS = "ids"; public static final String INDEX = "index"; + public static final String PREFIX = "prefix"; public static final String PREVIOUS_ACL_RULE_ID = "previousaclruleid"; public static final String NEXT_ACL_RULE_ID = "nextaclruleid"; public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash"; public static final String IMAGE_PATH = "imagepath"; public static final String INTERNAL_DNS1 = "internaldns1"; public static final String INTERNAL_DNS2 = "internaldns2"; + public static final String INTERNET_PROTOCOL = "internetprotocol"; public static final String INTERVAL_TYPE = "intervaltype"; public static final String LOCATION_TYPE = "locationtype"; public static final String IOPS_READ_RATE = "iopsreadrate"; @@ -532,6 +534,7 @@ public class ApiConstants { public static final String SECURITY_GROUP_EANBLED = "securitygroupenabled"; public static final String LOCAL_STORAGE_ENABLED = "localstorageenabled"; public static final String GUEST_IP_TYPE = "guestiptype"; + public static final String GUEST_IP6_PREFIX = "guestip6prefix"; public static final String XENSERVER_NETWORK_LABEL = "xennetworklabel"; public static final String KVM_NETWORK_LABEL = "kvmnetworklabel"; public static final String VMWARE_NETWORK_LABEL = "vmwarenetworklabel"; @@ -573,6 +576,8 @@ public class ApiConstants { public static final String KEYWORD = "keyword"; public static final String LIST_ALL = "listall"; public static final String IP_RANGES = "ipranges"; + public static final String IP6_RANGE = "ip6range"; + public static final String IP6_RANGES = "ip6ranges"; public static final String SPECIFY_IP_RANGES = "specifyipranges"; public static final String IS_SOURCE_NAT = "issourcenat"; public static final String IS_STATIC_NAT = "isstaticnat"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIp6PrefixCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIp6PrefixCmd.java new file mode 100644 index 000000000000..89a781d0acdf --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIp6PrefixCmd.java @@ -0,0 +1,112 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.network; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.PodResponse; +import org.apache.log4j.Logger; + +import com.cloud.dc.Pod; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; + +@APICommand(name = CreateGuestNetworkIp6PrefixCmd.APINAME, + description = "Creates a Guest network IPv6 prefix.", + responseObject = PodResponse.class, + since = "4.17.0.0", + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, + authorized = {RoleType.Admin}) +public class CreateGuestNetworkIp6PrefixCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(CreateGuestNetworkIp6PrefixCmd.class); + + public static final String APINAME = "createGuestNetworkIp6Prefix"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name = ApiConstants.POD_ID, + type = CommandType.UUID, + entityType = PodResponse.class, + required = true, + description = "UUID of POD, where the IP range belongs to.", + validations = {ApiArgValidator.PositiveNumber}) + private Long podId; + + @Parameter(name = ApiConstants.PREFIX, + type = CommandType.STRING, + required = true, + description = "The /56 or higher IPv6 CIDR for network prefix.") + private String prefix; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getPodId() { + return podId; + } + + public String getPrefix() { + return prefix; + } + @Override + public String getEventType() { + return EventTypes.EVENT_PUBLIC_IP6_PREFIX_CREATE; + } + + @Override + public String getEventDescription() { + return "Creating public IPv6 prefix " + getPrefix() + " for pod=" + getPodId(); + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, + ResourceAllocationException { + Pod result = _configService.createPodGuestIp6Prefix(this); + if (result != null) { + PodResponse response = _responseGenerator.createPodResponse(result, false); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Pod Public IP6 prefix."); + } + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + +} \ No newline at end of file diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java index 3d4013c8bc70..0fc6d019579a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java @@ -67,10 +67,14 @@ public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.NETMASK, type = CommandType.STRING, - required = true, description = "The netmask for the management network.") private String netmask; + @Parameter(name = ApiConstants.CIDR, + type = CommandType.STRING, + description = "The CIDR for the management network.") + private String cidr; + @Parameter(name = ApiConstants.START_IP, type = CommandType.STRING, required = true, @@ -89,9 +93,14 @@ public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.VLAN, type = CommandType.STRING, - description = "Optional. The vlan id the ip range sits on, default to Null when it is not specificed which means you network is not on any Vlan") + description = "Optional. The vlan id the ip range sits on, default to Null when it is not specified which means you network is not on any Vlan") private String vlan; + @Parameter(name = ApiConstants.IP6_RANGE, + type = CommandType.BOOLEAN, + description = "Optional. Specify if the range is for IPv6. Default value is false") + private Boolean ip6Range; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -108,6 +117,10 @@ public String getNetmask() { return netmask; } + public String getCidr() { + return cidr; + } + public String getStartIp() { return startIp; } @@ -127,6 +140,10 @@ public String getVlan() { return vlan; } + public boolean isIp6Range() { + return Boolean.TRUE.equals(ip6Range); + } + @Override public String getEventType() { return EventTypes.EVENT_MANAGEMENT_IP_RANGE_CREATE; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index 7172633f5f92..3d2f7b0c6fcb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -92,6 +92,12 @@ public class CreateNetworkOfferingCmd extends BaseCmd { @Parameter(name = ApiConstants.GUEST_IP_TYPE, type = CommandType.STRING, required = true, description = "guest type of the network offering: Shared or Isolated") private String guestIptype; + @Parameter(name = ApiConstants.INTERNET_PROTOCOL, + type = CommandType.STRING, + description = "The internet protocol of network offering. Options are ipv4, ipv6 and dualstack. Default is ipv4", + since = "4.17.0") + private String internetProtocol; + @Parameter(name = ApiConstants.SUPPORTED_SERVICES, type = CommandType.LIST, collectionType = CommandType.STRING, @@ -211,6 +217,10 @@ public String getGuestIpType() { return guestIptype; } + public String getInternetProtocol() { + return internetProtocol; + } + public Boolean getSpecifyIpRanges() { return specifyIpRanges == null ? false : specifyIpRanges; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/IpRangeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/IpRangeResponse.java index c1d3061bce38..364c19f2df0b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/IpRangeResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/IpRangeResponse.java @@ -16,16 +16,23 @@ // under the License. package org.apache.cloudstack.api.response; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; @SuppressWarnings("unused") public class IpRangeResponse extends BaseResponse { + @SerializedName(ApiConstants.GATEWAY) + @Param(description = "the gateway for the range") + private String gateway; + + @SerializedName(ApiConstants.CIDR) + @Param(description = "the CIDR for the range") + private String cidr; + @SerializedName(ApiConstants.START_IP) @Param(description = "the starting IP for the range") private String startIp; @@ -42,6 +49,22 @@ public class IpRangeResponse extends BaseResponse { @Param(description = "indicates Vlan ID for the range") private String vlanId; + public String getGateway() { + return gateway; + } + + public void setGateway(String gateway) { + this.gateway = gateway; + } + + public String getCidr() { + return cidr; + } + + public void setCidr(String cidr) { + this.cidr = cidr; + } + public String getStartIp() { return startIp; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/PodResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/PodResponse.java index 587fabfae8db..4af8fc52e1b2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/PodResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/PodResponse.java @@ -57,6 +57,10 @@ public class PodResponse extends BaseResponseWithAnnotations { @Param(description = "the IP ranges for the Pod", responseObject = IpRangeResponse.class, since = "4.16.0") private List ipRanges; + @SerializedName(ApiConstants.IP6_RANGES) + @Param(description = "the IPv6 ranges for the Pod", responseObject = IpRangeResponse.class, since = "4.17.0") + private List ip6Ranges; + @Deprecated(since = "4.16") @SerializedName(ApiConstants.START_IP) @Param(description = "the starting IP for the Pod. This parameter is deprecated, please use 'startip' from ipranges parameter.") @@ -85,6 +89,10 @@ public class PodResponse extends BaseResponseWithAnnotations { @Param(description = "the capacity of the Pod", responseObject = CapacityResponse.class) private List capacities; + @SerializedName(ApiConstants.GUEST_IP6_PREFIX) + @Param(description = "the guest IPv6 prefixes for the Pod", since = "4.17.0") + private List publicIp6Prefixes; + public String getId() { return id; } @@ -137,6 +145,10 @@ public void setIpRanges(List ipRanges) { this.ipRanges = ipRanges; } + public void setIp6Ranges(List ip6Ranges) { + this.ip6Ranges = ip6Ranges; + } + public List getStartIp() { return startIp; } @@ -184,4 +196,12 @@ public List getCapacities() { public void setCapacities(List capacities) { this.capacities = capacities; } + + public List getPublicIp6Prefixes() { + return publicIp6Prefixes; + } + + public void setPublicIp6Prefixes(List publicIp6Prefixes) { + this.publicIp6Prefixes = publicIp6Prefixes; + } } diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 66772002b5f8..d1e7dadd97c7 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -214,7 +214,8 @@ DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, Integer networkRate, Map> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, - Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, List domainIds, List zoneIds, boolean enableOffering); + Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, + List domainIds, List zoneIds, boolean enableOffering, final NetworkOffering.InternetProtocol internetProtocol); Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) @@ -252,7 +253,7 @@ Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetwor * @throws * @throws */ - Pod editPod(long id, String name, String startIp, String endIp, String gateway, String netmask, String allocationStateStr); + Pod editPod(long id, String name, String startIp, String endIp, String gateway, String netmask, String allocationState); void checkPodCidrSubnets(long zoneId, Long podIdToBeSkipped, String cidr); diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 1c303ad7f259..bcd52a0d1dad 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -54,6 +54,7 @@ import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.commons.lang.BooleanUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -242,7 +243,6 @@ import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; -import org.apache.commons.lang3.StringUtils; /** * NetworkManagerImpl implements NetworkManager. @@ -476,21 +476,21 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap>(), true, Network.GuestType.Shared, false, null, true, null, true, - false, null, false, null, true, false, null, null, true); + false, null, false, null, true, false, null, null, true, null); } //#2 - SG enabled network offering if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, null, null, true); + null, true, false, null, false, null, true, false, null, null, true, null); } //#3 - shared network offering with no SG service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null, false, - null, true, false, null, null, true); + null, true, false, null, null, true, null); } //#4 - default isolated offering with Source nat service @@ -498,14 +498,14 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, - true, false, null, null, true); + true, false, null, null, true, null); } //#5 - default vpc offering with LB service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, - defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, true); + defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, true, null); } //#6 - default vpc offering with no LB service @@ -514,14 +514,14 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { defaultVPCOffProviders.remove(Service.Lb); offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, - null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, true); + null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, true, null); } //#7 - isolated offering with source nat disabled if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, - true, null, true, false, null, false, null, true, false, null, null, true); + true, null, true, false, null, false, null, true, false, null, null, true, null); } //#8 - network offering with internal lb service @@ -543,7 +543,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB, "Offering for Isolated VPC networks with Internal Lb support", TrafficType.Guest, null, false, Availability.Optional, null, internalLbOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, true); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, true, null); offering.setInternalLb(true); offering.setPublicLb(false); _networkOfferingDao.update(offering.getId(), offering); @@ -574,7 +574,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, null, - netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, null, null, true); + netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, null, null, true, null); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); } diff --git a/engine/schema/src/main/java/com/cloud/dc/PodGuestIp6PrefixVO.java b/engine/schema/src/main/java/com/cloud/dc/PodGuestIp6PrefixVO.java new file mode 100644 index 000000000000..dd90cafd023b --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/dc/PodGuestIp6PrefixVO.java @@ -0,0 +1,107 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.dc; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +@Entity +@Table(name = "pod_ip6_guest_prefix") +public class PodGuestIp6PrefixVO implements PodGuestIp6Prefix { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "uuid") + String uuid; + + @Column(name = "data_center_id") + private long dataCenterId; + + @Column(name = "pod_id") + private long podId; + + @Column(name = "prefix") + private String prefix; + + @Column(name = "created") + @Temporal(value = TemporalType.TIMESTAMP) + private Date created = null; + + public PodGuestIp6PrefixVO(long dcId, long podId, String prefix) { + this(); + this.dataCenterId = dcId; + this.podId = podId; + this.prefix = prefix; + this.created = new Date(); + } + + protected PodGuestIp6PrefixVO() { + this.uuid = UUID.randomUUID().toString(); + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public Long getDataCenterId() { + return dataCenterId; + } + + public void setDataCenterId(long dcId) { + this.dataCenterId = dcId; + } + + @Override + public Long getPodId() { + return podId; + } + + public void setPodId(long podId) { + this.podId = podId; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public Date getCreated() { + return created; + } +} diff --git a/engine/schema/src/main/java/com/cloud/dc/PodManagementIp6RangeVO.java b/engine/schema/src/main/java/com/cloud/dc/PodManagementIp6RangeVO.java new file mode 100644 index 000000000000..f06f594fcc97 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/dc/PodManagementIp6RangeVO.java @@ -0,0 +1,160 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.dc; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +@Entity +@Table(name = "pod_ip6_range") +public class PodManagementIp6RangeVO implements PodManagementIp6Range { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "uuid") + String uuid; + + @Column(name = "data_center_id") + private long dataCenterId; + + @Column(name = "pod_id") + private long podId; + + @Column(name = "gateway") + private String gateway; + + @Column(name = "cidr") + private String cidr; + + @Column(name = "vlan") + private Integer vlan; + + @Column(name = "start_ip") + private String startIp; + + @Column(name = "end_ip") + private String endIp; + + @Column(name = "created") + @Temporal(value = TemporalType.TIMESTAMP) + private Date created = null; + + public PodManagementIp6RangeVO(long dcId, long podId, String gateway, String cidr, Integer vlan, String startIp, String endIp) { + this(); + this.dataCenterId = dcId; + this.podId = podId; + this.gateway = gateway; + this.cidr = cidr; + this.vlan = vlan; + this.startIp = startIp; + this.endIp = endIp; + this.created = new Date(); + } + + protected PodManagementIp6RangeVO() { + this.uuid = UUID.randomUUID().toString(); + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public Long getDataCenterId() { + return dataCenterId; + } + + public void setDataCenterId(long dcId) { + this.dataCenterId = dcId; + } + + @Override + public Long getPodId() { + return podId; + } + + public void setPodId(long podId) { + this.podId = podId; + } + + @Override + public String getGateway() { + return this.gateway; + } + + public void setGateway(String gateway) { + this.gateway = gateway; + } + + @Override + public String getCidr() { + return cidr; + } + + public void setCidr(String cidr) { + this.cidr = cidr; + } + + @Override + public Integer getVlan() { + return vlan; + } + + public void setVlan(int vlan) { + this.vlan = vlan; + } + + @Override + public String getStartIp() { + return startIp; + } + + public void setStartIp(String start) { + this.startIp = start; + } + + @Override + public String getEndIp() { + return endIp; + } + + public void setEndIp(String end) { + this.endIp = end; + } + + public Date getCreated() { + return created; + } +} \ No newline at end of file diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDao.java new file mode 100644 index 000000000000..17e0427b748a --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDao.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.dc.dao; + +import java.util.List; + +import com.cloud.dc.PodGuestIp6PrefixVO; +import com.cloud.utils.db.GenericDao; + +public interface PodGuestIp6PrefixDao extends GenericDao { + + List listByPodId(long podId); + + List listByDataCenterId(long dcId); +} diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDaoImpl.java new file mode 100644 index 000000000000..050720085f37 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDaoImpl.java @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.dc.dao; + +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.cloud.dc.PodGuestIp6PrefixVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.QueryBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@DB +public class PodGuestIp6PrefixDaoImpl extends GenericDaoBase implements PodGuestIp6PrefixDao { + + public PodGuestIp6PrefixDaoImpl() { + } + + @Override + public List listByPodId(long podId) { + QueryBuilder sc = QueryBuilder.create(PodGuestIp6PrefixVO.class); + sc.and(sc.entity().getPodId(), SearchCriteria.Op.EQ, podId); + return sc.list(); + } + + @Override + public List listByDataCenterId(long dcId) { + QueryBuilder sc = QueryBuilder.create(PodGuestIp6PrefixVO.class); + sc.and(sc.entity().getDataCenterId(), SearchCriteria.Op.EQ, dcId); + return sc.list(); + } +} diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDao.java new file mode 100644 index 000000000000..81bf4ae41eb8 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDao.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.dc.dao; + +import java.util.List; + +import com.cloud.dc.PodManagementIp6RangeVO; +import com.cloud.utils.db.GenericDao; + +public interface PodManagementIp6RangeDao extends GenericDao { + + List listByPodId(long podId); + + List listByDataCenterId(long dcId); +} diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDaoImpl.java new file mode 100644 index 000000000000..13fda5ec26fd --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDaoImpl.java @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.dc.dao; + +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.cloud.dc.PodManagementIp6RangeVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.QueryBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@DB +public class PodManagementIp6RangeDaoImpl extends GenericDaoBase implements PodManagementIp6RangeDao { + + public PodManagementIp6RangeDaoImpl() { + } + + @Override + public List listByPodId(long podId) { + QueryBuilder sc = QueryBuilder.create(PodManagementIp6RangeVO.class); + sc.and(sc.entity().getPodId(), SearchCriteria.Op.EQ, podId); + return sc.list(); + } + + @Override + public List listByDataCenterId(long dcId) { + QueryBuilder sc = QueryBuilder.create(PodManagementIp6RangeVO.class); + sc.and(sc.entity().getDataCenterId(), SearchCriteria.Op.EQ, dcId); + return sc.list(); + } +} diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java index a3e3c60210c4..4f7bdda2aac5 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java @@ -60,4 +60,6 @@ public interface VlanDao extends GenericDao { List listVlansByNetworkIdAndGateway(long networkid, String gateway); List listDedicatedVlans(long accountId); + + List listVlansWithIpV6RangeByPhysicalNetworkId(long physicalNetworkId); } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java index 7b3ca130cd84..67ee05d1f756 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java @@ -62,6 +62,7 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao protected SearchBuilder ZoneWideNonDedicatedVlanSearch; protected SearchBuilder VlanGatewaysearch; protected SearchBuilder DedicatedVlanSearch; + protected SearchBuilder PhysicalNetworkVlanIp6Search; protected SearchBuilder AccountVlanMapSearch; protected SearchBuilder DomainVlanMapSearch; @@ -255,6 +256,13 @@ public boolean configure(String name, Map params) throws Configu DedicatedVlanSearch.done(); AccountVlanMapSearch.done(); + PhysicalNetworkVlanIp6Search = createSearchBuilder(); + PhysicalNetworkVlanIp6Search.and("physicalNetworkId", PhysicalNetworkVlanIp6Search.entity().getPhysicalNetworkId(), SearchCriteria.Op.EQ); + PhysicalNetworkVlanIp6Search.and("ip6Gateway", PhysicalNetworkVlanIp6Search.entity().getIp6Gateway(), SearchCriteria.Op.NNULL); + PhysicalNetworkVlanIp6Search.and("ip6Cidr", PhysicalNetworkVlanIp6Search.entity().getIp6Cidr(), SearchCriteria.Op.NNULL); + PhysicalNetworkVlanIp6Search.and("ip6range", PhysicalNetworkVlanIp6Search.entity().getIpRange(), SearchCriteria.Op.NNULL); + PhysicalNetworkVlanIp6Search.done(); + return result; } @@ -387,4 +395,11 @@ public List listDedicatedVlans(long accountId) { return listBy(sc); } + @Override + public List listVlansWithIpV6RangeByPhysicalNetworkId(long physicalNetworkId) { + SearchCriteria sc = PhysicalNetworkVlanIp6Search.create(); + sc.setParameters("physicalNetworkId", physicalNetworkId); + return listBy(sc); + } + } diff --git a/engine/schema/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMapVO.java b/engine/schema/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMapVO.java new file mode 100644 index 000000000000..2317b8b436a8 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMapVO.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = "ip6_guest_prefix_subnet_network_map") +public class Ip6GuestPrefixSubnetNetworkMapVO implements Ip6GuestPrefixSubnetNetworkMap { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "prefix_id") + private Long prefixId; + + @Column(name = "subnet") + private String subnet; + + @Column(name = "network_id") + private Long networkId; + + @Column(name = "state") + private State state; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + @Column(name= GenericDao.REMOVED_COLUMN) + private Date removed; + + protected Ip6GuestPrefixSubnetNetworkMapVO() { + uuid = UUID.randomUUID().toString(); + } + + protected Ip6GuestPrefixSubnetNetworkMapVO(long prefixId, String subnet, Long networkId, State state) { + this.prefixId = prefixId; + this.subnet = subnet; + this.networkId = networkId; + this.state = state; + uuid = UUID.randomUUID().toString(); + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public long getPrefixId() { + return prefixId; + } + + @Override + public String getSubnet() { + return subnet; + } + + @Override + public Long getNetworkId() { + return networkId; + } + + @Override + public State getState() { + return state; + } +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDao.java b/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDao.java new file mode 100644 index 000000000000..6c9b64442886 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDao.java @@ -0,0 +1,26 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network.dao; + +import com.cloud.network.Ip6GuestPrefixSubnetNetworkMapVO; +import com.cloud.utils.db.GenericDao; + +public interface Ip6GuestPrefixSubnetNetworkMapDao extends GenericDao { + Ip6GuestPrefixSubnetNetworkMapVO findFirstAvailable(long prefixId); + Ip6GuestPrefixSubnetNetworkMapVO findLast(long prefixId); +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDaoImpl.java new file mode 100644 index 000000000000..6fea25e3c1a0 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDaoImpl.java @@ -0,0 +1,67 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network.dao; + +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Component; + +import com.cloud.network.Ip6GuestPrefixSubnetNetworkMap; +import com.cloud.network.Ip6GuestPrefixSubnetNetworkMapVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@DB +public class Ip6GuestPrefixSubnetNetworkMapDaoImpl extends GenericDaoBase implements Ip6GuestPrefixSubnetNetworkMapDao { + + protected SearchBuilder FreeSubnetSearch; + protected SearchBuilder PrefixIdSearch; + + @PostConstruct + public void init() { + FreeSubnetSearch = createSearchBuilder(); + FreeSubnetSearch.and("prefixId", FreeSubnetSearch.entity().getPrefixId(), SearchCriteria.Op.EQ); + FreeSubnetSearch.and("state", FreeSubnetSearch.entity().getState(), SearchCriteria.Op.EQ); + FreeSubnetSearch.done(); + PrefixIdSearch = createSearchBuilder(); + PrefixIdSearch.and("prefixId", FreeSubnetSearch.entity().getPrefixId(), SearchCriteria.Op.EQ); + PrefixIdSearch.done(); + } + + @Override + public Ip6GuestPrefixSubnetNetworkMapVO findFirstAvailable(long prefixId) { + SearchCriteria sc = FreeSubnetSearch.create(); + sc.setParameters("prefixId", prefixId); + sc.setParameters("state", Ip6GuestPrefixSubnetNetworkMap.State.Free); + return findOneBy(sc); + } + + @Override + public Ip6GuestPrefixSubnetNetworkMapVO findLast(long prefixId) { + SearchCriteria sc = PrefixIdSearch.create(); + sc.setParameters("prefixId", prefixId); + List list = listBy(sc); + return CollectionUtils.isNotEmpty(list) ? list.get(list.size() - 1) : null; + } +} diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java index 238a191bd770..52a547b48bdf 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java @@ -69,4 +69,6 @@ public interface NetworkOfferingDao extends GenericDao * Create default L2 network offerings */ void persistDefaultL2NetworkOfferings(); + + boolean isIpv6Supported(Long offeringId); } diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java index 93fe2480bbeb..7d13b7b5d989 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java @@ -17,6 +17,7 @@ package com.cloud.offerings.dao; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -51,6 +52,9 @@ public class NetworkOfferingDaoImpl extends GenericDaoBase AvailabilitySearch; final SearchBuilder AllFieldsSearch; private final GenericSearchBuilder UpgradeSearch; + + private final List ipv6EnabledProtocols = Arrays.asList(NetworkOffering.InternetProtocol.IPv6, NetworkOffering.InternetProtocol.DualStack); + @Inject NetworkOfferingDetailsDao _detailsDao; @Inject @@ -269,4 +273,11 @@ public void persistDefaultL2NetworkOfferings() { "Offering for L2 networks with config drive user data VLAN", true, true); } + + @Override + public boolean isIpv6Supported(Long offeringId) { + String internetProtocolStr = _detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol); + NetworkOffering.InternetProtocol internetProtocol = NetworkOffering.InternetProtocol.fromValue(internetProtocolStr); + return ipv6EnabledProtocols.contains(internetProtocol); + } } diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 508b01c2b573..c66f093d1336 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -108,6 +108,7 @@ + @@ -197,6 +198,8 @@ + + diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql index e28fe4329ddf..8a9716d6d6f0 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql @@ -21,3 +21,48 @@ -- PR#5668 Change the type of the 'ipsec_psk' field to allow large PSK. ALTER TABLE cloud.remote_access_vpn MODIFY ipsec_psk text NOT NULL; + +-- For IPv6 guest prefixes. +CREATE TABLE `cloud`.`pod_ip6_guest_prefix` ( + `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', + `uuid` varchar(40) DEFAULT NULL, + `data_center_id` bigint(20) unsigned NOT NULL COMMENT 'zone it belongs to', + `pod_id` bigint(20) unsigned DEFAULT NULL COMMENT 'pod it belongs to', + `prefix` varchar(255) NOT NULL COMMENT 'prefix of the ipv6 network', + `created` datetime default NULL, + `removed` datetime default NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_pod_ip6_guest_prefix__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`), + CONSTRAINT `fk_pod_ip6_guest_prefix__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `host_pod_ref`(`id`), + CONSTRAINT `uc_pod_ip6_guest_prefix__uuid` UNIQUE (`uuid`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`ip6_guest_prefix_subnet_network_map` ( + `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', + `uuid` varchar(40) DEFAULT NULL, + `prefix_id` bigint(20) unsigned NOT NULL COMMENT 'ip6 guest prefix to which subnet belongs to', + `subnet` varchar(255) NOT NULL COMMENT 'subnet of the ipv6 network', + `network_id` bigint(20) unsigned DEFAULT NULL COMMENT 'network to which subnet is associated to', + `state` varchar(255) NOT NULL COMMENT 'state of the subnet network', + `created` datetime default NULL, + `removed` datetime default NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_ip6_guest_prefix_subnet_network_map__prefix_id` FOREIGN KEY (`prefix_id`) REFERENCES `pod_ip6_guest_prefix`(`id`), + CONSTRAINT `fk_ip6_guest_prefix_subnet_network_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `network`(`id`), + CONSTRAINT `uc_ip6_guest_prefix_subnet_network_map__uuid` UNIQUE (`uuid`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`public_ip6_address_network_map` ( + `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', + `uuid` varchar(40) DEFAULT NULL, + `vlan_db_id` bigint(20) unsigned NOT NULL COMMENT 'id of the vlan to which this address belong to', + `public_ip_address` varchar(255) NOT NULL COMMENT 'ipv6 address', + `network_id` bigint(20) unsigned DEFAULT NULL COMMENT 'network to which this address is associated to', + `state` varchar(255) NOT NULL COMMENT 'state of the address', + `created` datetime default NULL, + `removed` datetime default NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_public_ip6_address_network_map__prefix_id` FOREIGN KEY (`vlan_db_id`) REFERENCES `vlan`(`id`), + CONSTRAINT `fk_public_ip6_address_network_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `network`(`id`), + CONSTRAINT `uc_public_ip6_address_network_map__uuid` UNIQUE (`uuid`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java index 1ba4dd3faed0..494a235dd4c9 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java @@ -34,15 +34,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import net.juniper.contrail.api.ApiConnector; -import net.juniper.contrail.api.ApiConnectorFactory; -import net.juniper.contrail.api.ApiPropertyBase; -import net.juniper.contrail.api.ObjectReference; -import net.juniper.contrail.api.types.FloatingIp; -import net.juniper.contrail.api.types.FloatingIpPool; -import net.juniper.contrail.api.types.NetworkPolicy; -import net.juniper.contrail.api.types.VirtualNetwork; - import org.apache.cloudstack.network.contrail.model.FloatingIpModel; import org.apache.cloudstack.network.contrail.model.FloatingIpPoolModel; import org.apache.cloudstack.network.contrail.model.ModelController; @@ -99,6 +90,15 @@ import com.cloud.vm.dao.VMInstanceDao; import com.google.common.collect.ImmutableList; +import net.juniper.contrail.api.ApiConnector; +import net.juniper.contrail.api.ApiConnectorFactory; +import net.juniper.contrail.api.ApiPropertyBase; +import net.juniper.contrail.api.ObjectReference; +import net.juniper.contrail.api.types.FloatingIp; +import net.juniper.contrail.api.types.FloatingIpPool; +import net.juniper.contrail.api.types.NetworkPolicy; +import net.juniper.contrail.api.types.VirtualNetwork; + public class ContrailManagerImpl extends ManagerBase implements ContrailManager { @Inject public ConfigurationService _configService; @@ -219,7 +219,7 @@ private NetworkOffering locatePublicNetworkOffering(String offeringName, ConfigurationManager configMgr = (ConfigurationManager) _configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Public, null, true, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, null, null, true); + Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, null, null, true, null); long id = voffer.getId(); _networkOfferingDao.update(id, voffer); return _networkOfferingDao.findById(id); @@ -254,7 +254,7 @@ private NetworkOffering locateNetworkOffering(String offeringName, ConfigurationManager configMgr = (ConfigurationManager)_configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Guest, null, false, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), null, null, true); + Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), null, null, true, null); if (offeringName.equals(vpcRouterOfferingName)) { voffer.setInternalLb(true); } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 44757798b755..32b443195f01 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -34,7 +34,6 @@ import javax.inject.Inject; -import com.cloud.server.ResourceIcon; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.affinity.AffinityGroup; @@ -223,10 +222,12 @@ import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; +import com.cloud.dc.PodGuestIp6PrefixVO; import com.cloud.dc.StorageNetworkIpRange; import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.PodGuestIp6PrefixDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.event.Event; @@ -304,6 +305,7 @@ import com.cloud.projects.ProjectInvitation; import com.cloud.region.ha.GlobalLoadBalancerRule; import com.cloud.resource.RollingMaintenanceManager; +import com.cloud.server.ResourceIcon; import com.cloud.server.ResourceTag; import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.service.ServiceOfferingVO; @@ -413,6 +415,8 @@ public class ApiResponseHelper implements ResponseGenerator { private AnnotationDao annotationDao; @Inject private UserStatisticsDao userStatsDao; + @Inject + PodGuestIp6PrefixDao podGuestIp6PrefixDao; @Override public UserResponse createUserResponse(User user) { @@ -846,7 +850,7 @@ private boolean isForSystemVms(long vlanId){ SearchCriteria sc = sb.create(); sc.setParameters("vlanId", vlanId); IPAddressVO userIpAddresVO = userIpAddressDao.findOneBy(sc); - return userIpAddresVO.isForSystemVms(); + return userIpAddresVO != null ? userIpAddresVO.isForSystemVms() : false; } @Override @@ -1122,6 +1126,18 @@ public PodResponse createPodResponse(Pod pod, Boolean showCapacities) { } } + List ip6Ranges = podManagementIp6RangeDao.listByPodId(pod.getId()); + List ip6RangesResponses = new ArrayList<>(); + for (PodManagementIp6RangeVO ip6Range : ip6Ranges) { + IpRangeResponse response = new IpRangeResponse(); + response.setGateway(ip6Range.getGateway()); + response.setCidr(ip6Range.getCidr()); + response.setVlanId(ip6Range.getVlan() != null ? BroadcastDomainType.Vlan.toUri(String.valueOf(ip6Range.getVlan())).toString() : BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED).toString()); + response.setStartIp(ip6Range.getStartIp()); + response.setEndIp(ip6Range.getEndIp()); + ip6RangesResponses.add(response); + } + PodResponse podResponse = new PodResponse(); podResponse.setId(pod.getUuid()); podResponse.setName(pod.getName()); @@ -1132,6 +1148,9 @@ public PodResponse createPodResponse(Pod pod, Boolean showCapacities) { } podResponse.setNetmask(NetUtils.getCidrNetmask(pod.getCidrSize())); podResponse.setIpRanges(ipRanges); + if (CollectionUtils.isNotEmpty(ip6Ranges)) { + podResponse.setIp6Ranges(ip6RangesResponses); + } podResponse.setStartIp(startIps); podResponse.setEndIp(endIps); podResponse.setForSystemVms(forSystemVms); @@ -1164,6 +1183,10 @@ public PodResponse createPodResponse(Pod pod, Boolean showCapacities) { capacityResponses.addAll(getStatsCapacityresponse(null, null, pod.getId(), pod.getDataCenterId())); podResponse.setCapacities(new ArrayList(capacityResponses)); } + + List ip6Prefixes = podGuestIp6PrefixDao.listByPodId(pod.getId()); + podResponse.setPublicIp6Prefixes(ip6Prefixes.stream().map(PodGuestIp6PrefixVO::getPrefix).collect(Collectors.toList())); + podResponse.setHasAnnotation(annotationDao.hasAnnotations(pod.getUuid(), AnnotationService.EntityType.POD.name(), _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId()))); podResponse.setObjectName("pod"); diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index a17d8b44caf4..9a1e3181b19d 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -41,7 +41,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.googlecode.ipv6.IPv6Address; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupService; @@ -52,6 +51,7 @@ import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; +import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIp6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; @@ -112,6 +112,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -135,6 +136,7 @@ import com.cloud.dc.DomainVlanMapVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; +import com.cloud.dc.PodGuestIp6PrefixVO; import com.cloud.dc.PodVlanMapVO; import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; @@ -148,6 +150,7 @@ import com.cloud.dc.dao.DedicatedResourceDao; import com.cloud.dc.dao.DomainVlanMapDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.dc.dao.PodGuestIp6PrefixDao; import com.cloud.dc.dao.PodVlanMapDao; import com.cloud.dc.dao.VlanDao; import com.cloud.dc.dao.VsphereStoragePolicyDao; @@ -264,8 +267,8 @@ import com.google.common.base.Enums; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; -import org.apache.commons.lang3.StringUtils; import com.google.common.collect.Sets; +import com.googlecode.ipv6.IPv6Address; public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable { public static final Logger s_logger = Logger.getLogger(ConfigurationManagerImpl.class); @@ -412,6 +415,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati private AnnotationDao annotationDao; @Inject UserIpv6AddressDao _ipv6Dao; + @Inject + PodGuestIp6PrefixDao podGuestIp6PrefixDao; // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? @Inject @@ -1297,6 +1302,8 @@ public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) { final String gateway = cmd.getGateWay(); final String netmask = cmd.getNetmask(); final String startIp = cmd.getStartIp(); + final String ip6Cidr = cmd.getCidr(); + final boolean isIp6Range = cmd.isIp6Range(); String endIp = cmd.getEndIp(); final boolean forSystemVms = cmd.isForSystemVms(); String vlan = cmd.getVlan(); @@ -1315,11 +1322,11 @@ public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) { final long zoneId = pod.getDataCenterId(); - if(!NetUtils.isValidIp4(gateway)) { + if(!NetUtils.isValidIp4(gateway) && !NetUtils.isValidIp6(gateway)) { throw new InvalidParameterValueException("The gateway IP address is invalid."); } - if(!NetUtils.isValidIp4Netmask(netmask)) { + if(!isIp6Range && !NetUtils.isValidIp4Netmask(netmask)) { throw new InvalidParameterValueException("The netmask IP address is invalid."); } @@ -1327,12 +1334,20 @@ public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) { endIp = startIp; } - final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask); + final String cidr = isIp6Range ? ip6Cidr : NetUtils.ipAndNetMaskToCidr(gateway, netmask); - if(!NetUtils.isValidIp4Cidr(cidr)) { + if(!isIp6Range && !NetUtils.isValidIp4Cidr(cidr)) { throw new InvalidParameterValueException("The CIDR is invalid " + cidr); } + if(isIp6Range && !NetUtils.isValidIp6Cidr(cidr)) { + throw new InvalidParameterValueException("The CIDR is invalid " + cidr); + } + + if (isIp6Range) { + return createPodIp6Range(pod, gateway, cidr, startIp, endIp, cmd.getVlan()); + } + final String cidrAddress = pod.getCidrAddress(); final long cidrSize = pod.getCidrSize(); @@ -1424,6 +1439,20 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { return pod; } + private Pod createPodIp6Range(HostPodVO pod, String gateway, String cidr, String startIp, String endIp, String vlan) { + Integer vlanId = null; + if (vlan != null && !vlan.equalsIgnoreCase("untagged")) { + try { + vlanId = Integer.valueOf(vlan); + } catch (NumberFormatException nfe) { + throw new InvalidParameterValueException("The VLAN is invalid"); + } + } + PodManagementIp6RangeVO ip6RangeVO = new PodManagementIp6RangeVO(pod.getDataCenterId(), pod.getId(), gateway, cidr, vlanId, startIp, endIp); + podManagementIp6RangeDao.persist(ip6RangeVO); + return pod; + } + @Override @DB public void deletePodIpRange(final DeleteManagementNetworkIpRangeCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException { @@ -1709,6 +1738,34 @@ private void checkIpRangeContainsTakenAddresses(final HostPodVO pod,final String } } + @Override + @DB + public Pod createPodGuestIp6Prefix(final CreateGuestNetworkIp6PrefixCmd cmd) throws ConcurrentOperationException { + final long podId = cmd.getPodId(); + final HostPodVO pod = _podDao.findById(podId); + if (pod == null) { + throw new InvalidParameterValueException("Unable to find pod by id: " + podId); + } + + final String prefix = cmd.getPrefix(); + + try { + + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(final TransactionStatus status) { + final long zoneId = pod.getDataCenterId(); + PodGuestIp6PrefixVO podGuestIp6PrefixVO = new PodGuestIp6PrefixVO(zoneId, podId, prefix); + podGuestIp6PrefixDao.persist(podGuestIp6PrefixVO); + } + }); + } catch (final Exception e) { + s_logger.error("Unable to update Pod " + podId + " IP range due to " + e.getMessage(), e); + throw new CloudRuntimeException("Failed to update Pod " + podId + " IP range. Please contact Cloud Support."); + } + return pod; + } + @Override public Pod editPod(final UpdatePodCmd cmd) { return editPod(cmd.getId(), cmd.getPodName(), null, null, cmd.getGateway(), cmd.getNetmask(), cmd.getAllocationState()); @@ -3823,9 +3880,9 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In zoneId = network.getDataCenterId(); physicalNetworkId = network.getPhysicalNetworkId(); } - } else if (ipv6) { + }/* else if (ipv6) { throw new InvalidParameterValueException("Only support IPv6 on extending existed network"); - } + }*/ // Verify that zone exists final DataCenterVO zone = _zoneDao.findById(zoneId); @@ -3833,11 +3890,11 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In throw new InvalidParameterValueException("Unable to find zone by id " + zoneId); } - if (ipv6) { - if (network.getGuestType() != GuestType.Shared || zone.isSecurityGroupEnabled()) { - throw new InvalidParameterValueException("Only support IPv6 on extending existed share network without SG"); - } - } +// if (ipv6) { +// if (network.getGuestType() != GuestType.Shared || zone.isSecurityGroupEnabled()) { +// throw new InvalidParameterValueException("Only support IPv6 on extending existed share network without SG"); +// } +// } // verify that physical network exists PhysicalNetworkVO pNtwk = null; if (physicalNetworkId != null) { @@ -5330,6 +5387,7 @@ public void checkZoneAccess(final Account caller, final DataCenter zone) { public NetworkOffering createNetworkOffering(final CreateNetworkOfferingCmd cmd) { final String name = cmd.getNetworkOfferingName(); final String displayText = cmd.getDisplayText(); + final NetworkOffering.InternetProtocol internetProtocol = NetworkOffering.InternetProtocol.fromValue(cmd.getInternetProtocol()); final String tags = cmd.getTags(); final String trafficTypeString = cmd.getTraffictype(); final boolean specifyVlan = cmd.getSpecifyVlan(); @@ -5623,7 +5681,7 @@ public NetworkOffering createNetworkOffering(final CreateNetworkOfferingCmd cmd) } final NetworkOfferingVO offering = createNetworkOffering(name, displayText, trafficType, tags, specifyVlan, availability, networkRate, serviceProviderMap, false, guestType, false, - serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, domainIds, zoneIds, enable); + serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, domainIds, zoneIds, enable, internetProtocol); CallContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name); return offering; } @@ -5761,7 +5819,7 @@ public NetworkOfferingVO createNetworkOffering(final String name, final String d final Long serviceOfferingId, final boolean conserveMode, final Map> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent, final Map details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc, - final List domainIds, final List zoneIds, final boolean enableOffering) { + final List domainIds, final List zoneIds, final boolean enableOffering, final NetworkOffering.InternetProtocol internetProtocol) { String servicePackageUuid; String spDescription = null; @@ -6014,6 +6072,9 @@ public NetworkOfferingVO doInTransaction(final TransactionStatus status) { detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.zoneid, String.valueOf(zoneId), false)); } } + if (internetProtocol != null) { + detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.internetProtocol, String.valueOf(internetProtocol), true)); + } if (!detailsVO.isEmpty()) { networkOfferingDetailsDao.saveDetails(detailsVO); } diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index f1bc68135385..1a2e9d5f9631 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -30,6 +30,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -61,6 +62,7 @@ import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; @@ -72,10 +74,12 @@ import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenterVnetVO; +import com.cloud.dc.PodGuestIp6PrefixVO; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterVnetDao; +import com.cloud.dc.dao.PodGuestIp6PrefixDao; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DeployDestination; import com.cloud.domain.Domain; @@ -112,6 +116,7 @@ import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.Ip6GuestPrefixSubnetNetworkMapDao; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.NetworkAccountDao; import com.cloud.network.dao.NetworkDao; @@ -206,6 +211,8 @@ import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import com.googlecode.ipv6.IPv6Network; +import com.googlecode.ipv6.IPv6NetworkMask; /** * NetworkServiceImpl implements NetworkService. @@ -332,6 +339,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C NetworkAccountDao _networkAccountDao; @Inject VirtualMachineManager vmManager; + @Inject + PodGuestIp6PrefixDao podGuestIp6PrefixDao; + @Inject + Ip6GuestPrefixSubnetNetworkMapDao ip6GuestPrefixSubnetNetworkMapDao; int _cidrLimit; boolean _allowSubdomainNetworkAccess; @@ -1339,6 +1350,15 @@ public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapac validateRouterIps(routerIp, routerIpv6, startIP, endIP, gateway, netmask, startIPv6, endIPv6, ip6Cidr); + if (zone.getNetworkType() == NetworkType.Advanced && ntwkOff.getGuestType() == GuestType.Isolated) { + ipv6 = _networkOfferingDao.isIpv6Supported(ntwkOff.getId()); + if (ipv6) { + Pair ip6GatewayCidr = getIp6GatewayCidr(ntwkOff.getId(), zoneId, owner.getId()); + ip6Gateway = ip6GatewayCidr.first(); + ip6Cidr = ip6GatewayCidr.second(); + } + } + if (StringUtils.isNotBlank(isolatedPvlan) && (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() == GuestType.Isolated)) { throw new InvalidParameterValueException("Can only support create Private VLAN network with advanced shared or L2 network!"); } @@ -4742,4 +4762,46 @@ public ConfigKey[] getConfigKeys() { return new ConfigKey[] {AllowDuplicateNetworkName, AllowEmptyStartEndIpAddress}; } + + private Pair getGuestNetworkIp6GatewayAndCidr(long physicalNetworkId) throws ResourceAllocationException { + List vlans = _vlanDao.listVlansWithIpV6RangeByPhysicalNetworkId(physicalNetworkId); + if (CollectionUtils.isEmpty(vlans)) { + throw new ResourceAllocationException("Unable to allocate IPv6 vlan network", Resource.ResourceType.network); + } + for (VlanVO vlan : vlans) { + vlan. + } + List prefixes = podGuestIp6PrefixDao.listByPodId(1); + if (CollectionUtils.isEmpty(prefixes)) { + throw new ResourceAllocationException("Unable to allocate IPv6 network", Resource.ResourceType.network); + } + Ip6GuestPrefixSubnetNetworkMapVO ip6Subnet = null; + for (PodGuestIp6PrefixVO prefix : prefixes) { + ip6Subnet = ip6GuestPrefixSubnetNetworkMapDao.findFirstAvailable(prefix.getId()); + if (ip6Subnet == null) { + Ip6GuestPrefixSubnetNetworkMapVO last = ip6GuestPrefixSubnetNetworkMapDao.findLast(prefix.getId()); + String lastUsedSubnet = last != null ? last.getSubnet() : null; + final IPv6Network ip6Prefix = IPv6Network.fromString(prefix.getPrefix()); + Iterator splits = ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(64)); + while (splits.hasNext()) { + IPv6Network i = splits.next(); + if (lastUsedSubnet == null) { + ip6Subnet = new Ip6GuestPrefixSubnetNetworkMapVO(prefix.getId(), i.toString(), null, Ip6GuestPrefixSubnetNetworkMap.State.Allocated); + break; + } + if (i.toString().equals(lastUsedSubnet)) { + lastUsedSubnet = null; + } + } + } + if (ip6Subnet != null) { + break; + } + } + if (ip6Subnet == null) { + throw new ResourceAllocationException("Unable to allocate IPv6 guest subnet for the network", Resource.ResourceType.network); + } + return new Pair<>(vlanip6Subnet.getSubnet()); + } + } diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 08ae0ad13f43..2243ad03cf26 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -35,8 +35,6 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; - - import java.util.stream.Collectors; import javax.crypto.Mac; @@ -44,8 +42,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.dc.DomainVlanMapVO; -import com.cloud.dc.dao.DomainVlanMapDao; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.affinity.AffinityGroupProcessor; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; @@ -121,6 +117,7 @@ import org.apache.cloudstack.api.command.admin.management.ListMgmtsCmd; import org.apache.cloudstack.api.command.admin.network.AddNetworkDeviceCmd; import org.apache.cloudstack.api.command.admin.network.AddNetworkServiceProviderCmd; +import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIp6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkCmdByAdmin; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; @@ -604,6 +601,7 @@ import com.cloud.dc.AccountVlanMapVO; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenterVO; +import com.cloud.dc.DomainVlanMapVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; import com.cloud.dc.PodVlanMapVO; @@ -613,6 +611,7 @@ import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.DomainVlanMapDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.PodVlanMapDao; import com.cloud.dc.dao.VlanDao; @@ -662,9 +661,9 @@ import com.cloud.network.dao.LoadBalancerVO; import com.cloud.network.dao.NetworkAccountDao; import com.cloud.network.dao.NetworkAccountVO; +import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkDomainDao; import com.cloud.network.dao.NetworkDomainVO; -import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.org.Cluster; @@ -3475,6 +3474,7 @@ public List> getCommands() { cmdList.add(AcquirePodIpCmdByAdmin.class); cmdList.add(ReleasePodIpCmdByAdmin.class); cmdList.add(CreateManagementNetworkIpRangeCmd.class); + cmdList.add(CreateGuestNetworkIp6PrefixCmd.class); cmdList.add(DeleteManagementNetworkIpRangeCmd.class); cmdList.add(UploadTemplateDirectDownloadCertificateCmd.class); cmdList.add(RevokeTemplateDirectDownloadCertificateCmd.class); diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index 112d20ba8472..88024a98ad40 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -24,6 +24,7 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; +import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIp6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; @@ -213,6 +214,11 @@ public void updatePodIpRange(final UpdatePodManagementNetworkIpRangeCmd cmd) thr return; } + @Override + public Pod createPodGuestIp6Prefix(CreateGuestNetworkIp6PrefixCmd cmd) { + return null; + } + /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationService#editPod(org.apache.cloudstack.api.commands.UpdatePodCmd) */ @@ -507,7 +513,8 @@ public void checkDiskOfferingAccess(Account caller, DiskOffering dof, DataCenter public NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, Integer networkRate, Map> serviceProviderMap, boolean isDefault, GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, - Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, List domainIds, List zoneIds, boolean enableOffering) { + Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, + List domainIds, List zoneIds, boolean enableOffering, NetworkOffering.InternetProtocol internetProtocol) { // TODO Auto-generated method stub return null; } diff --git a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index c05b732042eb..f91252932fdc 100644 --- a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -132,7 +132,7 @@ public void tearDown() { public void createSharedNtwkOffWithVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, null, null, false); + null, false, null, true, false, null, false, null, true, false, null, null, false, null); assertNotNull("Shared network offering with specifyVlan=true failed to create ", off); } @@ -140,7 +140,7 @@ public void createSharedNtwkOffWithVlan() { public void createSharedNtwkOffWithNoVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, false, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, true, false, null, false, null, true, false, null, null, false); + false, null, false, null, true, false, null, false, null, true, false, null, null, false, null); assertNull("Shared network offering with specifyVlan=false was created", off); } @@ -148,7 +148,7 @@ public void createSharedNtwkOffWithNoVlan() { public void createSharedNtwkOffWithSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, null, null, false); + null, false, null, true, false, null, false, null, true, false, null, null, false, null); assertNotNull("Shared network offering with specifyIpRanges=true failed to create ", off); } @@ -157,7 +157,7 @@ public void createSharedNtwkOffWithSpecifyIpRanges() { public void createSharedNtwkOffWithoutSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, false, false, null, false, null, true, false, null, null, false); + false, null, false, null, false, false, null, false, null, true, false, null, null, false, null); assertNull("Shared network offering with specifyIpRanges=false was created", off); } @@ -170,7 +170,7 @@ public void createIsolatedNtwkOffWithNoVlan() { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, null, null, false, null); assertNotNull("Isolated network offering with specifyIpRanges=false failed to create ", off); } @@ -183,7 +183,7 @@ public void createIsolatedNtwkOffWithVlan() { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, null, null, false, null); assertNotNull("Isolated network offering with specifyVlan=true wasn't created", off); } @@ -196,7 +196,7 @@ public void createIsolatedNtwkOffWithSpecifyIpRangesAndSourceNat() { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, null, null, false, null); assertNull("Isolated network offering with specifyIpRanges=true and source nat service enabled, was created", off); } @@ -207,7 +207,7 @@ public void createIsolatedNtwkOffWithSpecifyIpRangesAndNoSourceNat() { Set vrProvider = new HashSet(); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, null, null, false, null); assertNotNull("Isolated network offering with specifyIpRanges=true and with no sourceNatService, failed to create", off); } @@ -225,7 +225,7 @@ public void createVpcNtwkOff() { serviceProviderMap.put(Network.Service.Lb, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, false, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc provider ", off); } @@ -245,7 +245,7 @@ public void createVpcNtwkOffWithNetscaler() { serviceProviderMap.put(Network.Service.Lb, lbProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, false, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off); } diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 4111e0a74149..e7f08baaa7a4 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -857,6 +857,7 @@ "label.dpd": "Dead Peer Detection", "label.drag.new.position": "Drag to new position", "label.driver": "Driver", +"label.dual.stack": "Dual Stack", "label.duration.in.sec": "Duration (in sec)", "label.dynamicscalingenabled": "Dynamic Scaling Enabled", "label.dynamicscalingenabled.tooltip": "VM can dynamically scale only when dynamic scaling is enabled on template, service offering and global setting", @@ -1138,6 +1139,7 @@ "label.internallb.name.description": "Unique name for Internal LB", "label.internallb.sourceip.description": "Brief description of the Internal LB", "label.internallbvm": "InternalLbVm", +"label.internet.protocol": "Internet Protocol", "label.interval": "Polling Interval (in sec)", "label.intervaltype": "Interval Type", "label.introduction.to.cloudstack": "Introduction to CloudStackâ„¢", @@ -1148,6 +1150,9 @@ "label.invite.to": "Invite to", "label.invited.accounts": "Invited accounts", "label.ip": "IP Address", +"label.ip.range.type": "IP Range Type", +"label.ip.v4": "IPv4", +"label.ip.v6": "IPv6", "label.ip.allocations": "IP Allocations", "label.ip.or.fqdn": "IP or FQDN", "label.ip.range": "IP Range", @@ -1678,6 +1683,7 @@ "label.powerflex.storage.pool": "Storage Pool", "label.powerstate": "Power State", "label.preferred": "Prefered", +"label.prefix": "Prefix", "label.presetup": "PreSetup", "label.prev": "Prev", "label.previous": "Previous", diff --git a/ui/src/views/infra/network/IpRangesTabGuest.vue b/ui/src/views/infra/network/IpRangesTabGuest.vue index 416026814a31..b6f151ef18fd 100644 --- a/ui/src/views/infra/network/IpRangesTabGuest.vue +++ b/ui/src/views/infra/network/IpRangesTabGuest.vue @@ -17,6 +17,28 @@ @@ -129,9 +191,24 @@ export default { title: this.$t('label.ip6cidr'), dataIndex: 'ip6cidr' } - ] + ], + ip6Prefixes: [], + ip6Columns: [ + { + title: this.$t('label.podid'), + dataIndex: 'name' + }, + { + title: this.$t('label.prefix'), + dataIndex: 'prefix' + } + ], + addIp6PrefixModal: false } }, + beforeCreate () { + this.form = this.$form.createForm(this) + }, created () { this.fetchData() }, @@ -160,6 +237,36 @@ export default { }).finally(() => { this.componentLoading = false }) + this.fetchPodData() + }, + fetchPodData () { + // this.componentLoading = true + api('listPods', { + zoneid: this.resource.zoneid, + page: this.page, + pagesize: this.pageSize + }).then(response => { + this.items = [] + this.ip6Prefixes = [] + this.total = response.listpodsresponse.count || 0 + this.pods = response.listpodsresponse.pod ? response.listpodsresponse.pod : [] + for (const pod of this.pods) { + if (pod && pod.guestip6prefix && pod.guestip6prefix.length > 0) { + for (var guestip6prefix of pod.guestip6prefix) { + this.ip6Prefixes.push({ + id: pod.id, + name: pod.name, + prefix: guestip6prefix + }) + } + } + } + }).catch(error => { + console.log(error) + this.$notifyError(error) + }).finally(() => { + // this.componentLoading = false + }) }, handleOpenShowCreateForm () { this.showCreateForm = true @@ -176,6 +283,47 @@ export default { this.page = currentPage this.pageSize = pageSize this.fetchData() + }, + handleAddIp6Prefix (e) { + if (this.componentLoading) return + this.form.validateFields((error, values) => { + if (error) return + + this.componentLoading = true + this.addIp6PrefixModal = false + var params = { + podid: values.pod, + prefix: values.prefix + } + api('createGuestNetworkIp6Prefix', params).then(response => { + this.$pollJob({ + jobId: response.createguestnetworkip6prefixresponse.jobid, + title: this.$t('label.add.ip.range'), + description: values.pod, + successMessage: this.$t('message.success.add.iprange'), + successMethod: () => { + this.componentLoading = false + this.fetchData() + }, + errorMessage: this.$t('message.add.failed'), + errorMethod: () => { + this.componentLoading = false + this.fetchData() + }, + loadingMessage: this.$t('message.add.iprange.processing'), + catchMessage: this.$t('error.fetching.async.job.result'), + catchMethod: () => { + this.componentLoading = false + this.fetchData() + } + }) + }).catch(error => { + this.$notifyError(error) + }).finally(() => { + this.componentLoading = false + this.fetchData() + }) + }) } } } diff --git a/ui/src/views/infra/network/IpRangesTabManagement.vue b/ui/src/views/infra/network/IpRangesTabManagement.vue index f8a75d8b4c4e..f2158b9d813d 100644 --- a/ui/src/views/infra/network/IpRangesTabManagement.vue +++ b/ui/src/views/infra/network/IpRangesTabManagement.vue @@ -22,7 +22,7 @@ type="dashed" icon="plus" style="margin-bottom: 20px; width: 100%" - @click="handleOpenAddIpRangeModal"> + @click="handleOpenAddIp4RangeModal"> {{ $t('label.add.ip.range') }} @@ -66,6 +66,42 @@ +
+
+ IPv6 Ranges + + + {{ $t('Add IPv6 Range') }} + + + + + + - + + + + + @@ -118,7 +159,7 @@ v-decorator="['endip', { rules: [{ required: true, message: `${$t('label.required')}` }] }]"> - + @@ -200,7 +241,42 @@ export default { title: this.$t('label.action'), scopedSlots: { customRender: 'actions' } } - ] + ], + ip6Ranges: [], + ip6Columns: [ + { + title: this.$t('label.podid'), + dataIndex: 'name' + }, + { + title: this.$t('label.gateway'), + dataIndex: 'gateway' + }, + { + title: this.$t('label.cidr'), + dataIndex: 'cidr' + }, + { + title: this.$t('label.vlan'), + dataIndex: 'vlanid', + scopedSlots: { customRender: 'vlan' } + }, + { + title: this.$t('label.startip'), + dataIndex: 'startip', + scopedSlots: { customRender: 'startip' } + }, + { + title: this.$t('label.endip'), + dataIndex: 'endip', + scopedSlots: { customRender: 'endip' } + }, + { + title: this.$t('label.action'), + scopedSlots: { customRender: 'actions' } + } + ], + addingIp6Range: false } }, beforeCreate () { @@ -226,6 +302,7 @@ export default { pagesize: this.pageSize }).then(response => { this.items = [] + this.ip6Ranges = [] this.total = response.listpodsresponse.count || 0 this.pods = response.listpodsresponse.pod ? response.listpodsresponse.pod : [] for (const pod of this.pods) { @@ -243,6 +320,19 @@ export default { }) } } + if (pod && pod.ip6ranges && pod.ip6ranges.length > 0) { + for (var ip6range of pod.ip6ranges) { + this.ip6Ranges.push({ + id: pod.id, + name: pod.name, + gateway: ip6range.gateway, + cidr: ip6range.cidr, + vlanid: ip6range.vlanid, + startip: ip6range.startip, + endip: ip6range.endip + }) + } + } } }).catch(error => { console.log(error) @@ -261,6 +351,14 @@ export default { } }, 200) }, + handleOpenAddIp4RangeModal () { + this.addIpRangeModal = false + this.handleOpenAddIpRangeModal() + }, + handleOpenAddIp6RangeModal () { + this.addingIp6Range = true + this.handleOpenAddIpRangeModal() + }, handleDeleteIpRange (record) { this.componentLoading = true api('deleteManagementNetworkIpRange', { @@ -303,15 +401,21 @@ export default { this.componentLoading = true this.addIpRangeModal = false - api('createManagementNetworkIpRange', { + var params = { podid: values.pod, gateway: values.gateway, - netmask: values.netmask, startip: values.startip, endip: values.endip, - forsystemvms: values.vms, vlan: values.vlan || null - }).then(response => { + } + if (this.addingIp6Range) { + params.ip6range = true + params.cidr = values.cidr + } else { + params.forsystemvms = values.vms + params.netmask = values.netmask + } + api('createManagementNetworkIpRange', params).then(response => { this.$pollJob({ jobId: response.createmanagementnetworkiprangeresponse.jobid, title: this.$t('label.add.ip.range'), diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index ff1976f71e61..2fa415d92050 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -34,6 +34,15 @@ :rowKey="record => record.id" :pagination="false" > + + + @@ -164,6 +173,21 @@ layout="vertical" class="form" > + + + + {{ $t('label.ip.v4') }} + + + {{ $t('label.ip.v6') }} + + + {{ pod.name }} - - - - - - - - - - - - - - - - +
+ + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + +
{{ $t('label.set.reservation') }}
@@ -342,29 +391,34 @@ export default { columns: [ { title: this.$t('label.gateway'), - dataIndex: 'gateway' + scopedSlots: { customRender: 'gateway' } }, { - title: this.$t('label.netmask'), + title: this.$t('label.ip4netmask'), dataIndex: 'netmask' }, + { + title: this.$t('label.ip6cidr'), + dataIndex: 'ip6cidr' + }, { title: this.$t('label.vlan'), dataIndex: 'vlan' }, { title: this.$t('label.startip'), - dataIndex: 'startip' + scopedSlots: { customRender: 'startip' } }, { title: this.$t('label.endip'), - dataIndex: 'endip' + scopedSlots: { customRender: 'endip' } }, { title: this.$t('label.action'), scopedSlots: { customRender: 'actions' } } - ] + ], + addFormIpType: '' } }, beforeCreate () { @@ -372,7 +426,7 @@ export default { }, created () { if (!this.basicGuestNetwork) { - this.columns.splice(5, 0, + this.columns.splice(6, 0, { title: this.$t('label.account'), scopedSlots: { customRender: 'account' } @@ -521,11 +575,13 @@ export default { this.componentLoading = true this.addIpRangeModal = false - var params = { - gateway: values.gateway, - netmask: values.netmask, - startip: values.startip, - endip: values.endip + var ipRangeKeys = ['gateway', 'netmask', 'startip', 'endip'] + if (values.iptype === 'ip6') { + ipRangeKeys = ['ip6gateway', 'ip6cidr', 'startipv6', 'endipv6'] + } + var params = {} + for (const key of ipRangeKeys) { + params[key] = values[key] } if (!this.basicGuestNetwork) { params.zoneId = this.resource.zoneid diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue index 7b2350ee543e..21a0086f04af 100644 --- a/ui/src/views/offering/AddNetworkOffering.vue +++ b/ui/src/views/offering/AddNetworkOffering.vue @@ -73,6 +73,24 @@ + + + + + {{ $t('label.ip.v4') }} + + + {{ $t('label.ip.v6') }} + + + {{ $t('label.dual.stack') }} + + + From ef44c3476d727d3acc81784a1c35ddcdba6186d5 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 Oct 2021 08:39:28 +0200 Subject: [PATCH 002/109] IPv6: configure VR of isolated networks --- scripts/vm/network/vnet/modifyvlan.sh | 6 ++++ systemvm/debian/etc/radvd.conf.tmpl | 11 +++++++ systemvm/debian/opt/cloud/bin/setup/common.sh | 31 +++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 systemvm/debian/etc/radvd.conf.tmpl diff --git a/scripts/vm/network/vnet/modifyvlan.sh b/scripts/vm/network/vnet/modifyvlan.sh index 25008b154290..30efc9071111 100755 --- a/scripts/vm/network/vnet/modifyvlan.sh +++ b/scripts/vm/network/vnet/modifyvlan.sh @@ -34,6 +34,7 @@ addVlan() { if [ ! -d /sys/class/net/$vlanDev ] then ip link add link $pif name $vlanDev type vlan id $vlanId > /dev/null + echo 1 > /proc/sys/net/ipv6/conf/$vlanDev/disable_ipv6 ip link set $vlanDev up if [ $? -gt 0 ] @@ -47,12 +48,15 @@ addVlan() { fi fi + # disable IPv6 + echo 1 > /proc/sys/net/ipv6/conf/$vlanDev/disable_ipv6 # is up? ip link set $vlanDev up > /dev/null 2>/dev/null if [ ! -d /sys/class/net/$vlanBr ] then ip link add name $vlanBr type bridge + echo 1 > /proc/sys/net/ipv6/conf/$vlanBr/disable_ipv6 ip link set $vlanBr up if [ $? -gt 0 ] @@ -80,6 +84,8 @@ addVlan() { fi fi fi + # disable IPv6 + echo 1 > /proc/sys/net/ipv6/conf/$vlanBr/disable_ipv6 # is vlanBr up? ip link set $vlanBr up > /dev/null 2>/dev/null diff --git a/systemvm/debian/etc/radvd.conf.tmpl b/systemvm/debian/etc/radvd.conf.tmpl new file mode 100644 index 000000000000..247a877644ab --- /dev/null +++ b/systemvm/debian/etc/radvd.conf.tmpl @@ -0,0 +1,11 @@ +interface {{ GUEST_INTERFACE }} +{ + AdvSendAdvert on; + MinRtrAdvInterval 5; + MaxRtrAdvInterval 15; + prefix {{ IPV6_CIDR }} + { + AdvOnLink on; + AdvAutonomous on; + }; +}; diff --git a/systemvm/debian/opt/cloud/bin/setup/common.sh b/systemvm/debian/opt/cloud/bin/setup/common.sh index 60b88754bee3..1b4de011c658 100755 --- a/systemvm/debian/opt/cloud/bin/setup/common.sh +++ b/systemvm/debian/opt/cloud/bin/setup/common.sh @@ -272,12 +272,18 @@ setup_common() { if [ -n "$ETH0_IP6" ] then setup_interface_ipv6 "0" $ETH0_IP6 $ETH0_IP6_PRELEN + rm -rf /etc/radvd.conf + setup_radvd "0" $ETH0_IP6 $ETH0_IP6_PRELEN fi setup_interface "1" $ETH1_IP $ETH1_MASK $GW if [ -n "$ETH2_IP" ] then setup_interface "2" $ETH2_IP $ETH2_MASK $GW fi + if [ -n "$ETH2_IP6" ] + then + setup_interface_ipv6 "2" $ETH2_IP6 $ETH2_IP6_PRELEN + fi echo $NAME > /etc/hostname echo 'AVAHI_DAEMON_DETECT_LOCAL=0' > /etc/default/avahi-daemon @@ -352,6 +358,25 @@ setup_common() { fi } +setup_radvd() { + log_it "Setting up radvd" + + local intfnum=$1 + local ipv6="$2" + local prelen="$3" + + local intf=eth${intfnum} + local ip6cidr="$ipv6/$prelen" + + cp /etc/radvd.conf.tmpl /etc/radvd.conf.$intf + sed -i "s,{{ GUEST_INTERFACE }},$intf,g" /etc/radvd.conf.$intf + sed -i "s,{{ IPV6_CIDR }},$ip6cidr,g" /etc/radvd.conf.$intf + cat /etc/radvd.conf.$intf >> /etc/radvd.conf + + systemctl enable radvd + echo "radvd" >> /var/cache/cloud/enabled_svcs +} + setup_dnsmasq() { log_it "Setting up dnsmasq" @@ -654,6 +679,12 @@ parse_cmd_line() { eth0ip6prelen) export ETH0_IP6_PRELEN=$VALUE ;; + eth2ip6) + export ETH2_IP6=$VALUE + ;; + eth2ip6prelen) + export ETH2_IP6_PRELEN=$VALUE + ;; internaldns1) export internalNS1=$VALUE ;; From 8bc0e036853d82049eb1bfcaa5c89e9f6f3d79dd Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 Oct 2021 08:40:10 +0200 Subject: [PATCH 003/109] IPv6: add default IPv6 route in VR of isolated networks --- systemvm/debian/opt/cloud/bin/cs/CsAddress.py | 3 ++ systemvm/debian/opt/cloud/bin/cs/CsDatabag.py | 15 ++++++ systemvm/debian/opt/cloud/bin/cs/CsRoute.py | 50 +++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py index 0bc5d44ac531..ac997e320804 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py @@ -328,6 +328,9 @@ def post_configure(self, address): if(self.cl.get_gateway()): route.add_defaultroute(self.cl.get_gateway()) + if self.config.is_router() and self.cl.get_ip6gateway(): + route.add_defaultroute_v6(self.cl.get_ip6gateway()) + def set_mark(self): cmd = "-A PREROUTING -i %s -m state --state NEW -j CONNMARK --set-xmark %s/0xffffffff" % \ (self.getDevice(), self.dnum) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsDatabag.py b/systemvm/debian/opt/cloud/bin/cs/CsDatabag.py index aa738dfe805c..0f27500d5120 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsDatabag.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsDatabag.py @@ -158,3 +158,18 @@ def get_advert_int(self): if 'advert_int' in self.idata(): return self.idata()['advert_int'] return 1 + + def get_ip6gateway(self): + if "ip6gateway" in self.idata(): + return self.idata()['ip6gateway'] + return False + + def get_eth0_ip6(self): + if "eth0ip6" in self.idata(): + return self.idata()['eth0ip6'] + return False + + def get_eth2_ip6(self): + if "eth2ip6" in self.idata(): + return self.idata()['eth2ip6'] + return False diff --git a/systemvm/debian/opt/cloud/bin/cs/CsRoute.py b/systemvm/debian/opt/cloud/bin/cs/CsRoute.py index a77a62572ad8..d5df611df300 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsRoute.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsRoute.py @@ -127,3 +127,53 @@ def findRule(self, rule): if rule in i.strip(): return True return False + + def set_route_v6(self, cmd, method="add"): + """ Add a IPv6 route if it is not already defined """ + found = False + search = cmd + for i in CsHelper.execute("ip -6 route show " + search): + found = True + if not found and method == "add": + logging.info("Add " + cmd) + cmd = "ip -6 route add " + cmd + elif found and method == "delete": + logging.info("Delete " + cmd) + cmd = "ip -6 route delete " + cmd + else: + return + CsHelper.execute(cmd) + + def add_defaultroute_v6(self, gateway): + """ Add a default route + # for example, ip -6 route add default via fd80:20:20:20::1 + :param str gateway + :return: bool + """ + if not gateway: + raise Exception("Gateway cannot be None.") + + logging.info("Checking if default ipv6 route is present") + route_found = CsHelper.execute("ip -6 route list default") + if len(route_found) > 0: + logging.info("Default IPv6 route found: " + route_found[0]) + return False + else: + cmd = "default via " + gateway + logging.info("Adding default IPv6 route") + self.set_route_v6(cmd) + return True + + def add_network_route_v6(self, dev, address): + """ Wrapper method that adds table name and device to route statement """ + # ip -6 route add dev eth1 2021:10:10:10::1/64 + logging.info("Adding IPv6 route: dev " + dev + " network: " + address + " if not present") + cmd = "%s dev %s proto kernel" % (address, dev) + self.set_route_v6(cmd) + + def delete_network_route_v6(self, dev, address): + """ Wrapper method that deletes table name and device from route statement """ + # ip -6 route del dev eth1 2021:10:10:10::1/64 + logging.info("Deleting IPv6 route: dev " + dev + " network: " + address + " if present") + cmd = "%s dev %s" % (address, dev) + self.set_route_v6(cmd, method="delete") From 1cfe54c478da06d261e6798fc357bd18f0a48b0a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 Oct 2021 08:40:29 +0200 Subject: [PATCH 004/109] Reformat server/src/main/java/com/cloud/network/NetworkServiceImpl.java --- .../com/cloud/network/NetworkServiceImpl.java | 516 +++++++++--------- 1 file changed, 258 insertions(+), 258 deletions(-) diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index 1a2e9d5f9631..406b4406021d 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -2345,298 +2345,298 @@ public Network updateGuestNetwork(final UpdateNetworkCmd cmd) { ? _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), network.getPhysicalNetworkId()) : new HashMap(); - // don't allow to modify network domain if the service is not supported - if (domainSuffix != null) { - // validate network domain - if (!NetUtils.verifyDomainName(domainSuffix)) { - throw new InvalidParameterValueException( - "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " - + "and the hyphen ('-'); can't start or end with \"-\""); - } - - long offeringId = oldNetworkOfferingId; - if (networkOfferingId != null) { - offeringId = networkOfferingId; - } + // don't allow to modify network domain if the service is not supported + if (domainSuffix != null) { + // validate network domain + if (!NetUtils.verifyDomainName(domainSuffix)) { + throw new InvalidParameterValueException( + "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'); can't start or end with \"-\""); + } - Map dnsCapabilities = getNetworkOfferingServiceCapabilities(_entityMgr.findById(NetworkOffering.class, offeringId), Service.Dns); - String isUpdateDnsSupported = dnsCapabilities.get(Capability.AllowDnsSuffixModification); - if (isUpdateDnsSupported == null || !Boolean.valueOf(isUpdateDnsSupported)) { - // TBD: use uuid instead of networkOfferingId. May need to hardcode tablename in call to addProxyObject(). - throw new InvalidParameterValueException("Domain name change is not supported by the network offering id=" + networkOfferingId); - } + long offeringId = oldNetworkOfferingId; + if (networkOfferingId != null) { + offeringId = networkOfferingId; + } - network.setNetworkDomain(domainSuffix); - // have to restart the network - restartNetwork = true; - } + Map dnsCapabilities = getNetworkOfferingServiceCapabilities(_entityMgr.findById(NetworkOffering.class, offeringId), Service.Dns); + String isUpdateDnsSupported = dnsCapabilities.get(Capability.AllowDnsSuffixModification); + if (isUpdateDnsSupported == null || !Boolean.valueOf(isUpdateDnsSupported)) { + // TBD: use uuid instead of networkOfferingId. May need to hardcode tablename in call to addProxyObject(). + throw new InvalidParameterValueException("Domain name change is not supported by the network offering id=" + networkOfferingId); + } - //IP reservation checks - // allow reservation only to Isolated Guest networks - DataCenter dc = _dcDao.findById(network.getDataCenterId()); - String networkCidr = network.getNetworkCidr(); + network.setNetworkDomain(domainSuffix); + // have to restart the network + restartNetwork = true; + } - if (guestVmCidr != null) { - if (dc.getNetworkType() == NetworkType.Basic) { - throw new InvalidParameterValueException("Guest VM CIDR can't be specified for zone with " + NetworkType.Basic + " networking"); - } - if (network.getGuestType() != GuestType.Isolated) { - throw new InvalidParameterValueException("Can only allow IP Reservation in networks with guest type " + GuestType.Isolated); - } - if (networkOfferingChanged) { - throw new InvalidParameterValueException("Cannot specify this nework offering change and guestVmCidr at same time. Specify only one."); - } - if (!(network.getState() == Network.State.Implemented)) { - throw new InvalidParameterValueException("The network must be in " + Network.State.Implemented + " state. IP Reservation cannot be applied in " + network.getState() + " state"); - } - if (!NetUtils.isValidIp4Cidr(guestVmCidr)) { - throw new InvalidParameterValueException("Invalid format of Guest VM CIDR."); - } - if (!NetUtils.validateGuestCidr(guestVmCidr)) { - throw new InvalidParameterValueException("Invalid format of Guest VM CIDR. Make sure it is RFC1918 compliant. "); - } + //IP reservation checks + // allow reservation only to Isolated Guest networks + DataCenter dc = _dcDao.findById(network.getDataCenterId()); + String networkCidr = network.getNetworkCidr(); - // If networkCidr is null it implies that there was no prior IP reservation, so the network cidr is network.getCidr() - // But in case networkCidr is a non null value (IP reservation already exists), it implies network cidr is networkCidr - if (networkCidr != null) { - if (!NetUtils.isNetworkAWithinNetworkB(guestVmCidr, networkCidr)) { - throw new InvalidParameterValueException("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR should be a subset of network CIDR : " + networkCidr); - } - } else { - if (!NetUtils.isNetworkAWithinNetworkB(guestVmCidr, network.getCidr())) { - throw new InvalidParameterValueException("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR should be a subset of network CIDR : " + network.getCidr()); - } - } + if (guestVmCidr != null) { + if (dc.getNetworkType() == NetworkType.Basic) { + throw new InvalidParameterValueException("Guest VM CIDR can't be specified for zone with " + NetworkType.Basic + " networking"); + } + if (network.getGuestType() != GuestType.Isolated) { + throw new InvalidParameterValueException("Can only allow IP Reservation in networks with guest type " + GuestType.Isolated); + } + if (networkOfferingChanged) { + throw new InvalidParameterValueException("Cannot specify this nework offering change and guestVmCidr at same time. Specify only one."); + } + if (!(network.getState() == Network.State.Implemented)) { + throw new InvalidParameterValueException("The network must be in " + Network.State.Implemented + " state. IP Reservation cannot be applied in " + network.getState() + " state"); + } + if (!NetUtils.isValidIp4Cidr(guestVmCidr)) { + throw new InvalidParameterValueException("Invalid format of Guest VM CIDR."); + } + if (!NetUtils.validateGuestCidr(guestVmCidr)) { + throw new InvalidParameterValueException("Invalid format of Guest VM CIDR. Make sure it is RFC1918 compliant. "); + } - // This check makes sure there are no active IPs existing outside the guestVmCidr in the network - String[] guestVmCidrPair = guestVmCidr.split("\\/"); - Long size = Long.valueOf(guestVmCidrPair[1]); - List nicsPresent = _nicDao.listByNetworkId(networkId); - - String cidrIpRange[] = NetUtils.getIpRangeFromCidr(guestVmCidrPair[0], size); - s_logger.info("The start IP of the specified guest vm cidr is: " + cidrIpRange[0] + " and end IP is: " + cidrIpRange[1]); - long startIp = NetUtils.ip2Long(cidrIpRange[0]); - long endIp = NetUtils.ip2Long(cidrIpRange[1]); - long range = endIp - startIp + 1; - s_logger.info("The specified guest vm cidr has " + range + " IPs"); - - for (NicVO nic : nicsPresent) { - long nicIp = NetUtils.ip2Long(nic.getIPv4Address()); - //check if nic IP is outside the guest vm cidr - if ((nicIp < startIp || nicIp > endIp) && nic.getState() != Nic.State.Deallocating) { - throw new InvalidParameterValueException("Active IPs like " + nic.getIPv4Address() + " exist outside the Guest VM CIDR. Cannot apply reservation "); - } - } + // If networkCidr is null it implies that there was no prior IP reservation, so the network cidr is network.getCidr() + // But in case networkCidr is a non null value (IP reservation already exists), it implies network cidr is networkCidr + if (networkCidr != null) { + if (!NetUtils.isNetworkAWithinNetworkB(guestVmCidr, networkCidr)) { + throw new InvalidParameterValueException("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR should be a subset of network CIDR : " + networkCidr); + } + } else { + if (!NetUtils.isNetworkAWithinNetworkB(guestVmCidr, network.getCidr())) { + throw new InvalidParameterValueException("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR should be a subset of network CIDR : " + network.getCidr()); + } + } - // In some scenarios even though guesVmCidr and network CIDR do not appear similar but - // the IP ranges exactly matches, in these special cases make sure no Reservation gets applied - if (network.getNetworkCidr() == null) { - if (NetUtils.isSameIpRange(guestVmCidr, network.getCidr()) && !guestVmCidr.equals(network.getCidr())) { - throw new InvalidParameterValueException("The Start IP and End IP of guestvmcidr: " + guestVmCidr + " and CIDR: " + network.getCidr() + " are same, " - + "even though both the cidrs appear to be different. As a precaution no IP Reservation will be applied."); - } - } else { - if (NetUtils.isSameIpRange(guestVmCidr, network.getNetworkCidr()) && !guestVmCidr.equals(network.getNetworkCidr())) { - throw new InvalidParameterValueException("The Start IP and End IP of guestvmcidr: " + guestVmCidr + " and Network CIDR: " + network.getNetworkCidr() + " are same, " - + "even though both the cidrs appear to be different. As a precaution IP Reservation will not be affected. If you want to reset IP Reservation, " - + "specify guestVmCidr to be: " + network.getNetworkCidr()); - } - } + // This check makes sure there are no active IPs existing outside the guestVmCidr in the network + String[] guestVmCidrPair = guestVmCidr.split("\\/"); + Long size = Long.valueOf(guestVmCidrPair[1]); + List nicsPresent = _nicDao.listByNetworkId(networkId); - // When reservation is applied for the first time, network_cidr will be null - // Populate it with the actual network cidr - if (network.getNetworkCidr() == null) { - network.setNetworkCidr(network.getCidr()); - } + String cidrIpRange[] = NetUtils.getIpRangeFromCidr(guestVmCidrPair[0], size); + s_logger.info("The start IP of the specified guest vm cidr is: " + cidrIpRange[0] + " and end IP is: " + cidrIpRange[1]); + long startIp = NetUtils.ip2Long(cidrIpRange[0]); + long endIp = NetUtils.ip2Long(cidrIpRange[1]); + long range = endIp - startIp + 1; + s_logger.info("The specified guest vm cidr has " + range + " IPs"); - // Condition for IP Reservation reset : guestVmCidr and network CIDR are same - if (network.getNetworkCidr().equals(guestVmCidr)) { - s_logger.warn("Guest VM CIDR and Network CIDR both are same, reservation will reset."); - network.setNetworkCidr(null); - } - // Finally update "cidr" with the guestVmCidr - // which becomes the effective address space for CloudStack guest VMs - network.setCidr(guestVmCidr); - _networksDao.update(networkId, network); - s_logger.info("IP Reservation has been applied. The new CIDR for Guests Vms is " + guestVmCidr); + for (NicVO nic : nicsPresent) { + long nicIp = NetUtils.ip2Long(nic.getIPv4Address()); + //check if nic IP is outside the guest vm cidr + if ((nicIp < startIp || nicIp > endIp) && nic.getState() != Nic.State.Deallocating) { + throw new InvalidParameterValueException("Active IPs like " + nic.getIPv4Address() + " exist outside the Guest VM CIDR. Cannot apply reservation "); } + } - ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount); - // 1) Shutdown all the elements and cleanup all the rules. Don't allow to shutdown network in intermediate - // states - Shutdown and Implementing - int resourceCount = 1; - if (updateInSequence && restartNetwork && _networkOfferingDao.findById(network.getNetworkOfferingId()).isRedundantRouter() - && (networkOfferingId == null || _networkOfferingDao.findById(networkOfferingId).isRedundantRouter()) && network.getVpcId() == null) { - _networkMgr.canUpdateInSequence(network, forced); - NetworkDetailVO networkDetail = new NetworkDetailVO(network.getId(), Network.updatingInSequence, "true", true); - _networkDetailsDao.persist(networkDetail); - _networkMgr.configureUpdateInSequence(network); - resourceCount = _networkMgr.getResourceCount(network); + // In some scenarios even though guesVmCidr and network CIDR do not appear similar but + // the IP ranges exactly matches, in these special cases make sure no Reservation gets applied + if (network.getNetworkCidr() == null) { + if (NetUtils.isSameIpRange(guestVmCidr, network.getCidr()) && !guestVmCidr.equals(network.getCidr())) { + throw new InvalidParameterValueException("The Start IP and End IP of guestvmcidr: " + guestVmCidr + " and CIDR: " + network.getCidr() + " are same, " + + "even though both the cidrs appear to be different. As a precaution no IP Reservation will be applied."); } - List servicesNotInNewOffering = null; - if (networkOfferingId != null) { - servicesNotInNewOffering = _networkMgr.getServicesNotSupportedInNewOffering(network, networkOfferingId); - } - if (!forced && servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) { - NetworkOfferingVO newOffering = _networkOfferingDao.findById(networkOfferingId); - throw new CloudRuntimeException("The new offering:" + newOffering.getUniqueName() + " will remove the following services " + servicesNotInNewOffering - + "along with all the related configuration currently in use. will not proceed with the network update." + "set forced parameter to true for forcing an update."); - } - try { - if (servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) { - _networkMgr.cleanupConfigForServicesInNetwork(servicesNotInNewOffering, network); - } - } catch (Throwable e) { - s_logger.debug("failed to cleanup config related to unused services error:" + e.getMessage()); + } else { + if (NetUtils.isSameIpRange(guestVmCidr, network.getNetworkCidr()) && !guestVmCidr.equals(network.getNetworkCidr())) { + throw new InvalidParameterValueException("The Start IP and End IP of guestvmcidr: " + guestVmCidr + " and Network CIDR: " + network.getNetworkCidr() + " are same, " + + "even though both the cidrs appear to be different. As a precaution IP Reservation will not be affected. If you want to reset IP Reservation, " + + "specify guestVmCidr to be: " + network.getNetworkCidr()); } + } - boolean validStateToShutdown = (network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup || network.getState() == Network.State.Allocated); - try { + // When reservation is applied for the first time, network_cidr will be null + // Populate it with the actual network cidr + if (network.getNetworkCidr() == null) { + network.setNetworkCidr(network.getCidr()); + } - do { - if (restartNetwork) { - if (validStateToShutdown) { - if (!changeCidr) { - s_logger.debug("Shutting down elements and resources for network id=" + networkId + " as a part of network update"); + // Condition for IP Reservation reset : guestVmCidr and network CIDR are same + if (network.getNetworkCidr().equals(guestVmCidr)) { + s_logger.warn("Guest VM CIDR and Network CIDR both are same, reservation will reset."); + network.setNetworkCidr(null); + } + // Finally update "cidr" with the guestVmCidr + // which becomes the effective address space for CloudStack guest VMs + network.setCidr(guestVmCidr); + _networksDao.update(networkId, network); + s_logger.info("IP Reservation has been applied. The new CIDR for Guests Vms is " + guestVmCidr); + } - if (!_networkMgr.shutdownNetworkElementsAndResources(context, true, network)) { - s_logger.warn("Failed to shutdown the network elements and resources as a part of network restart: " + network); - CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network elements and resources as a part of update to network of specified id"); - ex.addProxyObject(network.getUuid(), "networkId"); - throw ex; - } - } else { - // We need to shutdown the network, since we want to re-implement the network. - s_logger.debug("Shutting down network id=" + networkId + " as a part of network update"); - - //check if network has reservation - if (NetUtils.isNetworkAWithinNetworkB(network.getCidr(), network.getNetworkCidr())) { - s_logger.warn( - "Existing IP reservation will become ineffective for the network with id = " + networkId + " You need to reapply reservation after network reimplementation."); - //set cidr to the newtork cidr - network.setCidr(network.getNetworkCidr()); - //set networkCidr to null to bring network back to no IP reservation state - network.setNetworkCidr(null); - } + ReservationContext context = new ReservationContextImpl(null, null, callerUser, callerAccount); + // 1) Shutdown all the elements and cleanup all the rules. Don't allow to shutdown network in intermediate + // states - Shutdown and Implementing + int resourceCount = 1; + if (updateInSequence && restartNetwork && _networkOfferingDao.findById(network.getNetworkOfferingId()).isRedundantRouter() + && (networkOfferingId == null || _networkOfferingDao.findById(networkOfferingId).isRedundantRouter()) && network.getVpcId() == null) { + _networkMgr.canUpdateInSequence(network, forced); + NetworkDetailVO networkDetail = new NetworkDetailVO(network.getId(), Network.updatingInSequence, "true", true); + _networkDetailsDao.persist(networkDetail); + _networkMgr.configureUpdateInSequence(network); + resourceCount = _networkMgr.getResourceCount(network); + } + List servicesNotInNewOffering = null; + if (networkOfferingId != null) { + servicesNotInNewOffering = _networkMgr.getServicesNotSupportedInNewOffering(network, networkOfferingId); + } + if (!forced && servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) { + NetworkOfferingVO newOffering = _networkOfferingDao.findById(networkOfferingId); + throw new CloudRuntimeException("The new offering:" + newOffering.getUniqueName() + " will remove the following services " + servicesNotInNewOffering + + "along with all the related configuration currently in use. will not proceed with the network update." + "set forced parameter to true for forcing an update."); + } + try { + if (servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) { + _networkMgr.cleanupConfigForServicesInNetwork(servicesNotInNewOffering, network); + } + } catch (Throwable e) { + s_logger.debug("failed to cleanup config related to unused services error:" + e.getMessage()); + } - if (!_networkMgr.shutdownNetwork(network.getId(), context, true)) { - s_logger.warn("Failed to shutdown the network as a part of update to network with specified id"); - CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network as a part of update of specified network id"); - ex.addProxyObject(network.getUuid(), "networkId"); - throw ex; - } - } - } else { - CloudRuntimeException ex = new CloudRuntimeException( - "Failed to shutdown the network elements and resources as a part of update to network with specified id; network is in wrong state: " + network.getState()); + boolean validStateToShutdown = (network.getState() == Network.State.Implemented || network.getState() == Network.State.Setup || network.getState() == Network.State.Allocated); + try { + + do { + if (restartNetwork) { + if (validStateToShutdown) { + if (!changeCidr) { + s_logger.debug("Shutting down elements and resources for network id=" + networkId + " as a part of network update"); + + if (!_networkMgr.shutdownNetworkElementsAndResources(context, true, network)) { + s_logger.warn("Failed to shutdown the network elements and resources as a part of network restart: " + network); + CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network elements and resources as a part of update to network of specified id"); ex.addProxyObject(network.getUuid(), "networkId"); throw ex; } - } - - // 2) Only after all the elements and rules are shutdown properly, update the network VO - // get updated network - Network.State networkState = _networksDao.findById(networkId).getState(); - boolean validStateToImplement = (networkState == Network.State.Implemented || networkState == Network.State.Setup || networkState == Network.State.Allocated); - if (restartNetwork && !validStateToImplement) { - CloudRuntimeException ex = new CloudRuntimeException( - "Failed to implement the network elements and resources as a part of update to network with specified id; network is in wrong state: " + networkState); - ex.addProxyObject(network.getUuid(), "networkId"); - throw ex; - } + } else { + // We need to shutdown the network, since we want to re-implement the network. + s_logger.debug("Shutting down network id=" + networkId + " as a part of network update"); + + //check if network has reservation + if (NetUtils.isNetworkAWithinNetworkB(network.getCidr(), network.getNetworkCidr())) { + s_logger.warn( + "Existing IP reservation will become ineffective for the network with id = " + networkId + " You need to reapply reservation after network reimplementation."); + //set cidr to the newtork cidr + network.setCidr(network.getNetworkCidr()); + //set networkCidr to null to bring network back to no IP reservation state + network.setNetworkCidr(null); + } - if (networkOfferingId != null) { - if (networkOfferingChanged) { - Transaction.execute(new TransactionCallbackNoReturn() { - @Override - public void doInTransactionWithoutResult(TransactionStatus status) { - network.setNetworkOfferingId(networkOfferingId); - _networksDao.update(networkId, network, newSvcProviders); - // get all nics using this network - // log remove usage events for old offering - // log assign usage events for new offering - List nics = _nicDao.listByNetworkId(networkId); - for (NicVO nic : nics) { - if (nic.getReservationStrategy() == Nic.ReservationStrategy.PlaceHolder) { - continue; - } - long vmId = nic.getInstanceId(); - VMInstanceVO vm = _vmDao.findById(vmId); - if (vm == null) { - s_logger.error("Vm for nic " + nic.getId() + " not found with Vm Id:" + vmId); - continue; - } - long isDefault = (nic.isDefaultNic()) ? 1 : 0; - String nicIdString = Long.toString(nic.getId()); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), nicIdString, oldNetworkOfferingId, - null, isDefault, VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplay()); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), nicIdString, networkOfferingId, - null, isDefault, VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplay()); - } - } - }); - } else { - network.setNetworkOfferingId(networkOfferingId); - _networksDao.update(networkId, network, - _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), network.getPhysicalNetworkId())); + if (!_networkMgr.shutdownNetwork(network.getId(), context, true)) { + s_logger.warn("Failed to shutdown the network as a part of update to network with specified id"); + CloudRuntimeException ex = new CloudRuntimeException("Failed to shutdown the network as a part of update of specified network id"); + ex.addProxyObject(network.getUuid(), "networkId"); + throw ex; } - } else { - _networksDao.update(networkId, network); } + } else { + CloudRuntimeException ex = new CloudRuntimeException( + "Failed to shutdown the network elements and resources as a part of update to network with specified id; network is in wrong state: " + network.getState()); + ex.addProxyObject(network.getUuid(), "networkId"); + throw ex; + } + } - // 3) Implement the elements and rules again - if (restartNetwork) { - if (network.getState() != Network.State.Allocated) { - DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null); - s_logger.debug("Implementing the network " + network + " elements and resources as a part of network update"); - try { - if (!changeCidr) { - _networkMgr.implementNetworkElementsAndResources(dest, context, network, _networkOfferingDao.findById(network.getNetworkOfferingId())); - } else { - _networkMgr.implementNetwork(network.getId(), dest, context); + // 2) Only after all the elements and rules are shutdown properly, update the network VO + // get updated network + Network.State networkState = _networksDao.findById(networkId).getState(); + boolean validStateToImplement = (networkState == Network.State.Implemented || networkState == Network.State.Setup || networkState == Network.State.Allocated); + if (restartNetwork && !validStateToImplement) { + CloudRuntimeException ex = new CloudRuntimeException( + "Failed to implement the network elements and resources as a part of update to network with specified id; network is in wrong state: " + networkState); + ex.addProxyObject(network.getUuid(), "networkId"); + throw ex; + } + + if (networkOfferingId != null) { + if (networkOfferingChanged) { + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + network.setNetworkOfferingId(networkOfferingId); + _networksDao.update(networkId, network, newSvcProviders); + // get all nics using this network + // log remove usage events for old offering + // log assign usage events for new offering + List nics = _nicDao.listByNetworkId(networkId); + for (NicVO nic : nics) { + if (nic.getReservationStrategy() == Nic.ReservationStrategy.PlaceHolder) { + continue; + } + long vmId = nic.getInstanceId(); + VMInstanceVO vm = _vmDao.findById(vmId); + if (vm == null) { + s_logger.error("Vm for nic " + nic.getId() + " not found with Vm Id:" + vmId); + continue; } - } catch (Exception ex) { - s_logger.warn("Failed to implement network " + network + " elements and resources as a part of network update due to ", ex); - CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id) elements and resources as a part of network update"); - e.addProxyObject(network.getUuid(), "networkId"); - throw e; + long isDefault = (nic.isDefaultNic()) ? 1 : 0; + String nicIdString = Long.toString(nic.getId()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), nicIdString, oldNetworkOfferingId, + null, isDefault, VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplay()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), nicIdString, networkOfferingId, + null, isDefault, VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplay()); } } - if (networkOfferingChanged) { - replugNicsForUpdatedNetwork(network); - } - } + }); + } else { + network.setNetworkOfferingId(networkOfferingId); + _networksDao.update(networkId, network, + _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), network.getPhysicalNetworkId())); + } + } else { + _networksDao.update(networkId, network); + } - // 4) if network has been upgraded from a non persistent ntwk offering to a persistent ntwk offering, - // implement the network if its not already - if (networkOfferingChanged && !oldNtwkOff.isPersistent() && networkOffering.isPersistent()) { - if (network.getState() == Network.State.Allocated) { - try { - DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null); - _networkMgr.implementNetwork(network.getId(), dest, context); - } catch (Exception ex) { - s_logger.warn("Failed to implement network " + network + " elements and resources as a part o" + "f network update due to ", ex); - CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified" + " id) elements and resources as a part of network update"); - e.addProxyObject(network.getUuid(), "networkId"); - throw e; - } + // 3) Implement the elements and rules again + if (restartNetwork) { + if (network.getState() != Network.State.Allocated) { + DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null); + s_logger.debug("Implementing the network " + network + " elements and resources as a part of network update"); + try { + if (!changeCidr) { + _networkMgr.implementNetworkElementsAndResources(dest, context, network, _networkOfferingDao.findById(network.getNetworkOfferingId())); + } else { + _networkMgr.implementNetwork(network.getId(), dest, context); } + } catch (Exception ex) { + s_logger.warn("Failed to implement network " + network + " elements and resources as a part of network update due to ", ex); + CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id) elements and resources as a part of network update"); + e.addProxyObject(network.getUuid(), "networkId"); + throw e; } - resourceCount--; - } while (updateInSequence && resourceCount > 0); - } catch (Exception exception) { - if (updateInSequence) { - _networkMgr.finalizeUpdateInSequence(network, false); } - throw new CloudRuntimeException("failed to update network " + network.getUuid() + " due to " + exception.getMessage()); - } finally { - if (updateInSequence) { - if (_networkDetailsDao.findDetail(networkId, Network.updatingInSequence) != null) { - _networkDetailsDao.removeDetail(networkId, Network.updatingInSequence); + if (networkOfferingChanged) { + replugNicsForUpdatedNetwork(network); + } + } + + // 4) if network has been upgraded from a non persistent ntwk offering to a persistent ntwk offering, + // implement the network if its not already + if (networkOfferingChanged && !oldNtwkOff.isPersistent() && networkOffering.isPersistent()) { + if (network.getState() == Network.State.Allocated) { + try { + DeployDestination dest = new DeployDestination(_dcDao.findById(network.getDataCenterId()), null, null, null); + _networkMgr.implementNetwork(network.getId(), dest, context); + } catch (Exception ex) { + s_logger.warn("Failed to implement network " + network + " elements and resources as a part o" + "f network update due to ", ex); + CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified" + " id) elements and resources as a part of network update"); + e.addProxyObject(network.getUuid(), "networkId"); + throw e; } } } - return getNetwork(network.getId()); + resourceCount--; + } while (updateInSequence && resourceCount > 0); + } catch (Exception exception) { + if (updateInSequence) { + _networkMgr.finalizeUpdateInSequence(network, false); + } + throw new CloudRuntimeException("failed to update network " + network.getUuid() + " due to " + exception.getMessage()); + } finally { + if (updateInSequence) { + if (_networkDetailsDao.findDetail(networkId, Network.updatingInSequence) != null) { + _networkDetailsDao.removeDetail(networkId, Network.updatingInSequence); + } + } + } + return getNetwork(network.getId()); } @Override From 38740271c54c86e5f66e08d03f481f0682dd5f2e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 Oct 2021 08:40:42 +0200 Subject: [PATCH 005/109] IPv6: update network to offering which support IPv6 --- .../com/cloud/network/NetworkServiceImpl.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index 406b4406021d..1a566e342a02 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -1474,6 +1474,31 @@ public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapac return network; } + private Pair getIp6GatewayCidr(Long networkOfferingId, Long zoneId, Long accountId) { + String ip6Gateway = null; + String ip6Cidr = null; + if (!areServicesSupportedByNetworkOffering(networkOfferingId, Service.SourceNat)) { + throw new InvalidParameterValueException("Can only take IPv6 address with isolated networks if SourceNat is supported"); + } + String routerIpv6Gateway = Ipv6Service.routerIpv6Gateway.valueIn(accountId); + if (org.apache.commons.lang3.StringUtils.isEmpty(routerIpv6Gateway)) { + Ipv6Address ipv6Address = _ipv6Service.takeIpv6Range(zoneId, false); + if (ipv6Address == null) { + throw new InvalidParameterValueException("cannot take an IPv6 range without router ipv6 address for this network"); + } + ip6Gateway = ipv6Address.getIp6Gateway(); + ip6Cidr = ipv6Address.getIp6Cidr(); + } else { + Ipv6Address ipv6Address = _ipv6Service.takeIpv6Range(zoneId, true); + if (ipv6Address == null) { + throw new InvalidParameterValueException("cannot take an IPv6 range with router ipv6 address for this network"); + } + ip6Gateway = ipv6Address.getIp6Gateway(); + ip6Cidr = ipv6Address.getIp6Cidr(); + } + return new Pair(ip6Gateway, ip6Cidr); + } + /** * Retrieve information (if set) for private VLAN when creating the network */ @@ -2550,6 +2575,7 @@ public Network updateGuestNetwork(final UpdateNetworkCmd cmd) { Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { + updateNetworkIpv6(network, networkOfferingId); network.setNetworkOfferingId(networkOfferingId); _networksDao.update(networkId, network, newSvcProviders); // get all nics using this network @@ -2639,6 +2665,23 @@ public void doInTransactionWithoutResult(TransactionStatus status) { return getNetwork(network.getId()); } + private void updateNetworkIpv6(NetworkVO network, Long networkOfferingId) { + boolean isIpv6Supported = _ipv6Service.isIpv6Supported(network.getNetworkOfferingId()); + boolean isIpv6SupportedNew = _ipv6Service.isIpv6Supported(networkOfferingId); + if (isIpv6Supported && ! isIpv6SupportedNew) { + _ipv6AddressDao.unmark(network.getId(), network.getDomainId(), network.getAccountId()); + network.setIp6Gateway(null); + network.setIp6Cidr(null); + } else if (!isIpv6Supported && isIpv6SupportedNew) { + Pair ip6GatewayCidr = getIp6GatewayCidr(networkOfferingId, network.getDataCenterId(), network.getAccountId()); + String ip6Gateway = ip6GatewayCidr.first(); + String ip6Cidr = ip6GatewayCidr.second(); + _ipv6AddressDao.mark(network.getDataCenterId(), ip6Gateway, ip6Cidr, network.getId(), network.getDomainId(), network.getAccountId()); + network.setIp6Gateway(ip6Gateway); + network.setIp6Cidr(ip6Cidr); + } + } + @Override @ActionEvent(eventType = EventTypes.EVENT_NETWORK_MIGRATE, eventDescription = "migrating network", async = true) public Network migrateGuestNetwork(long networkId, long networkOfferingId, Account callerAccount, User callerUser, boolean resume) { From cbce2be422af76be6fcf2d8cd860301e9e438003 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 Oct 2021 08:43:55 +0200 Subject: [PATCH 006/109] IPv6: update vm nic ipv6 address when update network to new offering --- .../com/cloud/network/NetworkServiceImpl.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index 1a566e342a02..8e1c8a92c3b5 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -2672,6 +2672,13 @@ private void updateNetworkIpv6(NetworkVO network, Long networkOfferingId) { _ipv6AddressDao.unmark(network.getId(), network.getDomainId(), network.getAccountId()); network.setIp6Gateway(null); network.setIp6Cidr(null); + List nics = _nicDao.listByNetworkId(network.getId()); + for (NicVO nic : nics) { + nic.setIPv6Address(null); + nic.setIPv6Cidr(null); + nic.setIPv6Gateway(null); + _nicDao.update(nic.getId(), nic); + } } else if (!isIpv6Supported && isIpv6SupportedNew) { Pair ip6GatewayCidr = getIp6GatewayCidr(networkOfferingId, network.getDataCenterId(), network.getAccountId()); String ip6Gateway = ip6GatewayCidr.first(); @@ -2679,6 +2686,15 @@ private void updateNetworkIpv6(NetworkVO network, Long networkOfferingId) { _ipv6AddressDao.mark(network.getDataCenterId(), ip6Gateway, ip6Cidr, network.getId(), network.getDomainId(), network.getAccountId()); network.setIp6Gateway(ip6Gateway); network.setIp6Cidr(ip6Cidr); + final String ip6Prefix = ip6Gateway.split("::")[0]; + List nics = _nicDao.listByNetworkId(network.getId()); + for (NicVO nic : nics) { + IPv6Address ipv6addr = NetUtils.EUI64Address(ip6Prefix + Ipv6Service.IPV6_CIDR_SUFFIX, nic.getMacAddress()); + nic.setIPv6Address(ipv6addr.toString()); + nic.setIPv6Cidr(ip6Cidr); + nic.setIPv6Gateway(ip6Gateway); + _nicDao.update(nic.getId(), nic); + } } } From bcf1d39f8892cb542fd70a2545aca2a1c5cdc74f Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 Oct 2021 08:41:54 +0200 Subject: [PATCH 007/109] IPv6: configure VPC VR to support multiple tiers with IPv6 --- .../com/cloud/agent/api/to/NetworkTO.java | 9 ++ .../agent/api/SetupGuestNetworkCommand.java | 27 +++++ .../facade/SetGuestNetworkConfigItem.java | 7 ++ .../virtualnetwork/model/GuestNetwork.java | 54 ++++++++++ .../cloud/hypervisor/HypervisorGuruBase.java | 1 + .../network/router/CommandSetupHelper.java | 37 +++++++ .../network/router/NetworkHelperImpl.java | 3 + .../com/cloud/network/vpc/VpcManagerImpl.java | 2 +- systemvm/debian/opt/cloud/bin/configure.py | 3 +- .../opt/cloud/bin/cs/CsVpcGuestNetwork.py | 102 ++++++++++++++++++ 10 files changed, 243 insertions(+), 2 deletions(-) create mode 100755 systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py diff --git a/api/src/main/java/com/cloud/agent/api/to/NetworkTO.java b/api/src/main/java/com/cloud/agent/api/to/NetworkTO.java index 9c888059d93c..b106418f068b 100644 --- a/api/src/main/java/com/cloud/agent/api/to/NetworkTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/NetworkTO.java @@ -39,6 +39,7 @@ public class NetworkTO { protected boolean isSecurityGroupEnabled; protected String name; protected String ip6address; + protected String ip6gateway; protected String ip6cidr; public NetworkTO() { @@ -68,6 +69,10 @@ public void setIp6Address(String addr) { this.ip6address = addr; } + public void setIp6Gateway(String gateway) { + this.ip6gateway = gateway; + } + public void setIp6Cidr(String cidr) { this.ip6cidr = cidr; } @@ -161,6 +166,10 @@ public String getIp6Address() { return ip6address; } + public String getIp6Gateway() { + return ip6gateway; + } + public String getIp6Cidr() { return ip6cidr; } diff --git a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java index 0f53daa7e984..9ea05e8ababf 100644 --- a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java +++ b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java @@ -30,6 +30,9 @@ public class SetupGuestNetworkCommand extends NetworkElementCommand { boolean isRedundant = false; boolean add = true; NicTO nic; + String routerIpv6 = null; + String routerIpv6Gateway = null; + String routerIpv6Cidr = null; public NicTO getNic() { return nic; @@ -69,4 +72,28 @@ public SetupGuestNetworkCommand(final String dhcpRange, final String networkDoma this.add = add; this.nic = nic; } + + public String getRouterIpv6() { + return routerIpv6; + } + + public void setRouterIpv6(String routerIpv6) { + this.routerIpv6 = routerIpv6; + } + + public String getRouterIpv6Gateway() { + return routerIpv6Gateway; + } + + public void setRouterIpv6Gateway(String routerIpv6Gateway) { + this.routerIpv6Gateway = routerIpv6Gateway; + } + + public String getRouterIpv6Cidr() { + return routerIpv6Cidr; + } + + public void setRouterIpv6Cidr(String routerIpv6Cidr) { + this.routerIpv6Cidr = routerIpv6Cidr; + } } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java index f96e6d47d2e4..3cb85fe9238e 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java @@ -55,6 +55,13 @@ public List generateConfig(final NetworkElementCommand cmd) { final GuestNetwork guestNetwork = new GuestNetwork(command.isAdd(), nic.getMac(), "eth" + nic.getDeviceId(), routerGIP, netmask, gateway, cidr, dns, domainName); + guestNetwork.setRouterGuestIp6(nic.getIp6Address()); + guestNetwork.setRouterGuestIp6Gateway(nic.getIp6Gateway()); + guestNetwork.setRouterGuestIp6Cidr(nic.getIp6Cidr()); + + guestNetwork.setRouterIp6(command.getRouterIpv6()); + guestNetwork.setRouterIp6Gateway(command.getRouterIpv6Gateway()); + guestNetwork.setRouterIp6Cidr(command.getRouterIpv6Cidr()); return generateConfigItems(guestNetwork); } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java index 076073e79494..1506ee46f30a 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java @@ -29,6 +29,12 @@ public class GuestNetwork extends ConfigBase { private String cidr; private String dns; private String domainName; + private String routerGuestIp6; + private String routerGuestIp6Gateway; + private String routerGuestIp6Cidr; + private String routerIp6; + private String routerIp6Gateway; + private String routerIp6Cidr; public GuestNetwork() { super(ConfigBase.GUEST_NETWORK); @@ -119,4 +125,52 @@ public String getDomainName() { public void setDomainName(final String domainName) { this.domainName = domainName; } + + public String getRouterGuestIp6() { + return routerGuestIp6; + } + + public void setRouterGuestIp6(String routerGuestIp6) { + this.routerGuestIp6 = routerGuestIp6; + } + + public String getRouterGuestIp6Gateway() { + return routerGuestIp6Gateway; + } + + public void setRouterGuestIp6Gateway(String routerGuestIp6Gateway) { + this.routerGuestIp6Gateway = routerGuestIp6Gateway; + } + + public String getRouterGuestIp6Cidr() { + return routerGuestIp6Cidr; + } + + public void setRouterGuestIp6Cidr(String routerGuestIp6Cidr) { + this.routerGuestIp6Cidr = routerGuestIp6Cidr; + } + + public String getRouterIp6() { + return routerIp6; + } + + public void setRouterIp6(String routerIp6) { + this.routerIp6 = routerIp6; + } + + public String getRouterIp6Gateway() { + return routerIp6Gateway; + } + + public void setRouterIp6Gateway(String routerIp6Gateway) { + this.routerIp6Gateway = routerIp6Gateway; + } + + public String getRouterIp6Cidr() { + return routerIp6Cidr; + } + + public void setRouterIp6Cidr(String routerIp6Cidr) { + this.routerIp6Cidr = routerIp6Cidr; + } } \ No newline at end of file diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java index e99b2fd6757a..fe37e670306f 100644 --- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java @@ -137,6 +137,7 @@ public NicTO toNicTO(NicProfile profile) { to.setName(profile.getName()); to.setSecurityGroupEnabled(profile.isSecurityGroupEnabled()); to.setIp6Address(profile.getIPv6Address()); + to.setIp6Gateway(profile.getIPv6Gateway()); to.setIp6Cidr(profile.getIPv6Cidr()); NetworkVO network = _networkDao.findById(profile.getNetworkId()); diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 4bff1a5187d4..698ad52ea60f 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -26,6 +26,10 @@ import javax.inject.Inject; +import com.cloud.dc.dao.DataCenterIpv6AddressDao; +import com.cloud.network.Ipv6Service; +import com.cloud.utils.exception.CloudRuntimeException; +import com.googlecode.ipv6.IPv6Address; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -179,6 +183,10 @@ public class CommandSetupHelper { private RouterControlHelper _routerControlHelper; @Inject private HostDao _hostDao; + @Inject + Ipv6Service _ipv6Service; + @Inject + DataCenterIpv6AddressDao _ipv6AddressDao; @Autowired @Qualifier("networkHelper") @@ -1025,6 +1033,11 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute final SetupGuestNetworkCommand setupCmd = new SetupGuestNetworkCommand(dhcpRange, networkDomain, router.getIsRedundantRouter(), defaultDns1, defaultDns2, add, _itMgr.toNicTO(nicProfile, router.getHypervisorType())); + NicVO publicNic = _nicDao.findDefaultNicForVM(router.getId()); + if (publicNic != null) { + updateSetupGuestNetworkCommandIpv6(setupCmd, network, publicNic.getMacAddress()); + } + final String brd = NetUtils.long2Ip(NetUtils.ip2Long(guestNic.getIPv4Address()) | ~NetUtils.ip2Long(guestNic.getIPv4Netmask())); setupCmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId())); setupCmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(network.getId(), router.getId())); @@ -1041,6 +1054,30 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute return setupCmd; } + private void updateSetupGuestNetworkCommandIpv6(SetupGuestNetworkCommand setupCmd, Network network, String macAddress) { + boolean isIpv6Supported = _ipv6Service.isIpv6Supported(network.getNetworkOfferingId()); + if (isIpv6Supported) { + final String routerIpv6 = _ipv6AddressDao.getRouterIpv6ByNetwork(network.getId()); + if (routerIpv6 == null) { + final String routerIpv6Gateway = Ipv6Service.routerIpv6Gateway.valueIn(network.getAccountId()); + if (routerIpv6Gateway == null) { + throw new CloudRuntimeException(String.format("Invalid routerIpv6Prefix for account %s", network.getAccountId())); + } + final String routerIpv6Prefix = routerIpv6Gateway.split("::")[0]; + IPv6Address ipv6addr = NetUtils.EUI64Address(routerIpv6Prefix + Ipv6Service.IPV6_CIDR_SUFFIX, macAddress); + s_logger.info("Calculated IPv6 address " + ipv6addr + " using EUI-64 for mac address " + macAddress); + setupCmd.setRouterIpv6(ipv6addr.toString()); + setupCmd.setRouterIpv6Cidr(routerIpv6Prefix + Ipv6Service.IPV6_CIDR_SUFFIX); + setupCmd.setRouterIpv6Gateway(routerIpv6Gateway); + } else { + setupCmd.setRouterIpv6(routerIpv6); + setupCmd.setRouterIpv6Cidr(routerIpv6 + Ipv6Service.IPV6_CIDR_SUFFIX); + final String routerIpv6Gateway = _ipv6AddressDao.getRouterIpv6GatewayByNetwork((network.getId())); + setupCmd.setRouterIpv6Gateway(routerIpv6Gateway); + } + } + } + private VmDataCommand generateVmDataCommand(final VirtualRouter router, final String vmPrivateIpAddress, final String userData, final String serviceOffering, final String zoneName, final String publicIpAddress, final String vmName, final String vmInstanceName, final long vmId, final String vmUuid, final String publicKey, final long guestNetworkId, String hostname) { diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index cc947bd05031..16e39eca63e6 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -681,6 +681,9 @@ protected LinkedHashMap> configurePublicNic( s_logger.info("Use same MAC as previous RvR, the MAC is " + peerNic.getMacAddress()); defaultNic.setMacAddress(peerNic.getMacAddress()); } + if (routerDeploymentDefinition.getGuestNetwork() != null) { + _ipv6Service.updateNicIpv6(defaultNic, routerDeploymentDefinition.getDest().getDataCenter(), routerDeploymentDefinition.getGuestNetwork()); + } publicConfig.put(publicNetworks.get(0), new ArrayList(Arrays.asList(defaultNic))); } diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index 5752da2bf917..586d612ce72f 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -2602,7 +2602,7 @@ public Network createVpcGuestNetwork(final long ntwkOffId, final String name, fi // 2) Create network final Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId, false, networkDomain, owner, domainId, pNtwk, zoneId, aclType, - subdomainAccess, vpcId, null, null, isDisplayNetworkEnabled, null, null, externalId, null, null); + subdomainAccess, vpcId, ip6Gateway, ip6Cidr, isDisplayNetworkEnabled, null, null, externalId, null, null); if (guestNetwork != null) { guestNetwork.setNetworkACLId(aclId); diff --git a/systemvm/debian/opt/cloud/bin/configure.py b/systemvm/debian/opt/cloud/bin/configure.py index 53e9452d0b92..253065185c14 100755 --- a/systemvm/debian/opt/cloud/bin/configure.py +++ b/systemvm/debian/opt/cloud/bin/configure.py @@ -38,6 +38,7 @@ from cs.CsConfig import CsConfig from cs.CsProcess import CsProcess from cs.CsStaticRoutes import CsStaticRoutes +from cs.CsVpcGuestNetwork import CsVpcGuestNetwork class CsPassword(CsDataBag): @@ -1069,7 +1070,7 @@ def main(argv): config.address().compare() config.address().process() - databag_map = OrderedDict([("guest_network", {"process_iptables": True, "executor": []}), + databag_map = OrderedDict([("guest_network", {"process_iptables": True, "executor": [CsVpcGuestNetwork("guestnetwork", config)]}), ("ip_aliases", {"process_iptables": True, "executor": []}), ("vm_password", {"process_iptables": False, "executor": [CsPassword("vmpassword", config)]}), ("vm_metadata", {"process_iptables": False, "executor": [CsVmMetadata('vmdata', config)]}), diff --git a/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py b/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py new file mode 100755 index 000000000000..f2ae38882836 --- /dev/null +++ b/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py @@ -0,0 +1,102 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import logging +import os.path +from cs.CsDatabag import CsDataBag +from CsFile import CsFile +import CsHelper + +VPC_PUBLIC_INTERFACE = "eth1" + +RADVD_CONF = "/etc/radvd.conf" +RADVD_CONF_NEW = "/etc/radvd.conf.new" + +class CsVpcGuestNetwork(CsDataBag): + """ Manage Vpc Guest Networks """ + + def process(self): + logging.debug("Processing CsVpcGuestNetwork") + self.conf = CsFile(RADVD_CONF_NEW) + self.conf.empty() + for item in self.dbag: + if item == "id": + continue + for address in self.dbag[item]: + if address['add']: + self.add_address_route(address) + self.add_radvd_conf(address) + else: + self.remove_address_route(address) + self.conf.commit() + file = CsFile(RADVD_CONF) + if not file.compare(self.conf): + CsHelper.copy(RADVD_CONF_NEW, RADVD_CONF) + logging.debug("CsVpcGuestNetwork:: will restart radvd !") + CsHelper.service("radvd", "restart") + + def add_address_route(self, entry): + if 'router_guest_ip6' in entry.keys() and entry['router_guest_ip6']: + self.enable_ipv6() + cidr_size = entry['router_guest_ip6_cidr'].split("/")[-1] + full_addr = entry['router_guest_ip6_gateway'] + "/" + cidr_size + if not CsHelper.execute("ip -6 addr show dev %s | grep -w %s" % (entry['device'], full_addr)): + CsHelper.execute("ip -6 addr add %s dev %s" % (full_addr, entry['device'])) + if 'router_ip6' in entry.keys() and entry['router_ip6']: + if not CsHelper.execute("ip -6 addr show dev %s | grep -w %s" % (VPC_PUBLIC_INTERFACE, entry['router_ip6_cidr'])): + CsHelper.execute("ip -6 addr add %s dev %s" % (entry['router_ip6_cidr'], VPC_PUBLIC_INTERFACE)) + if not CsHelper.execute("ip -6 route list default via %s" % entry['router_ip6_gateway']): + CsHelper.execute("ip -6 route add default via %s" % entry['router_ip6_gateway']) + else: + return + + def remove_address_route(self, entry): + if 'router_guest_ip6' in entry.keys() and entry['router_guest_ip6']: + cidr_size = entry['router_guest_ip6_cidr'].split("/")[-1] + full_addr = entry['router_guest_ip6_gateway'] + "/" + cidr_size + CsHelper.execute("ip -6 addr del %s dev %s" % (full_addr, entry['device'])) + if 'router_ip6' in entry.keys() and entry['router_ip6']: + CsHelper.execute("ip -6 addr del %s dev %s" % (entry['router_ip6_cidr'], VPC_PUBLIC_INTERFACE)) + else: + return + + def enable_ipv6(self): + logging.debug("Enabling IPv6 in this router") + CsHelper.execute("sysctl net.ipv6.conf.all.disable_ipv6=0") + CsHelper.execute("sysctl net.ipv6.conf.all.forwarding=1") + CsHelper.execute("sysctl net.ipv6.conf.all.accept_ra=1") + + # to solve the 'tentative dadfailed' when perform rolling upgrade + CsHelper.execute("sysctl net.ipv6.conf.all.accept_dad=0") + CsHelper.execute("sysctl net.ipv6.conf.default.accept_dad=0") + CsHelper.execute("sysctl net.ipv6.conf.all.use_tempaddr=0") + CsHelper.execute("sysctl net.ipv6.conf.default.use_tempaddr=0") + + def add_radvd_conf(self, entry): + if 'router_guest_ip6' in entry.keys() and entry['router_guest_ip6']: + cidr_size = entry['router_guest_ip6_cidr'].split("/")[-1] + full_addr = entry['router_guest_ip6_gateway'] + "/" + cidr_size + self.conf.append("interface %s" % entry['device']) + self.conf.append("{") + self.conf.append(" AdvSendAdvert on;") + self.conf.append(" MinRtrAdvInterval 5;") + self.conf.append(" MaxRtrAdvInterval 15;") + self.conf.append(" prefix %s" % full_addr) + self.conf.append(" {") + self.conf.append(" AdvOnLink on;") + self.conf.append(" AdvAutonomous on;") + self.conf.append(" };") + self.conf.append("};") From 84f8efb695e74b2c64adbc82b47f4562dbf276f3 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 Oct 2021 08:47:07 +0200 Subject: [PATCH 008/109] IPv6: add RDNSS in radvd.conf --- .../agent/api/SetupGuestNetworkCommand.java | 26 +++++++++++++++++++ .../facade/SetGuestNetworkConfigItem.java | 14 +++++++++- .../virtualnetwork/model/GuestNetwork.java | 12 ++++++++- .../network/router/CommandSetupHelper.java | 10 +++++-- .../VirtualNetworkApplianceManagerImpl.java | 4 +-- systemvm/debian/etc/radvd.conf.tmpl | 1 + .../opt/cloud/bin/cs/CsVpcGuestNetwork.py | 6 +++++ systemvm/debian/opt/cloud/bin/setup/common.sh | 9 ++++++- 8 files changed, 75 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java index 9ea05e8ababf..a5a7028e8e9b 100644 --- a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java +++ b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java @@ -27,6 +27,8 @@ public class SetupGuestNetworkCommand extends NetworkElementCommand { String networkDomain; String defaultDns1 = null; String defaultDns2 = null; + String defaultIp6Dns1 = null; + String defaultIp6Dns2 = null; boolean isRedundant = false; boolean add = true; NicTO nic; @@ -46,6 +48,14 @@ public String getDefaultDns2() { return defaultDns2; } + public String getDefaultIp6Dns1() { + return defaultIp6Dns1; + } + + public String getDefaultIp6Dns2() { + return defaultIp6Dns2; + } + public String getNetworkDomain() { return networkDomain; } @@ -96,4 +106,20 @@ public String getRouterIpv6Cidr() { public void setRouterIpv6Cidr(String routerIpv6Cidr) { this.routerIpv6Cidr = routerIpv6Cidr; } + + public Boolean getRouterIpv6Firewall() { + return routerIpv6Firewall; + } + + public void setRouterIpv6Firewall(Boolean routerIpv6Firewall) { + this.routerIpv6Firewall = routerIpv6Firewall; + } + + public void setDefaultIp6Dns1(String defaultIp6Dns1) { + this.defaultIp6Dns1 = defaultIp6Dns1; + } + + public void setDefaultIp6Dns2(String defaultIp6Dns2) { + this.defaultIp6Dns2 = defaultIp6Dns2; + } } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java index 3cb85fe9238e..7d4c42caf24c 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java @@ -30,6 +30,8 @@ import com.cloud.agent.resource.virtualnetwork.model.GuestNetwork; import com.cloud.utils.net.NetUtils; +import org.apache.commons.lang3.StringUtils; + public class SetGuestNetworkConfigItem extends AbstractConfigItemFacade { @Override @@ -53,8 +55,18 @@ public List generateConfig(final NetworkElementCommand cmd) { } } + String dns6 = command.getDefaultIp6Dns1(); + if (StringUtils.isEmpty(dns6)) { + dns6 = command.getDefaultIp6Dns2(); + } else { + final String dns2 = command.getDefaultIp6Dns2(); + if (StringUtils.isNotEmpty(dns2)) { + dns6 += "," + dns2; + } + } + final GuestNetwork guestNetwork = new GuestNetwork(command.isAdd(), nic.getMac(), "eth" + nic.getDeviceId(), routerGIP, netmask, gateway, - cidr, dns, domainName); + cidr, dns, dns6, domainName); guestNetwork.setRouterGuestIp6(nic.getIp6Address()); guestNetwork.setRouterGuestIp6Gateway(nic.getIp6Gateway()); guestNetwork.setRouterGuestIp6Cidr(nic.getIp6Cidr()); diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java index 1506ee46f30a..200ab8eb96b3 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java @@ -28,6 +28,7 @@ public class GuestNetwork extends ConfigBase { private String routerGuestGateway; private String cidr; private String dns; + private String dns6; private String domainName; private String routerGuestIp6; private String routerGuestIp6Gateway; @@ -41,7 +42,7 @@ public GuestNetwork() { } public GuestNetwork(final boolean add, final String macAddress, final String device, final String routerGuestIp, final String routerGuestNetmask, final String routerGuestGateway, - final String cidr, final String dns, final String domainName) { + final String cidr, final String dns, final String dns6, final String domainName) { super(ConfigBase.GUEST_NETWORK); this.add = add; this.macAddress = macAddress; @@ -51,6 +52,7 @@ public GuestNetwork(final boolean add, final String macAddress, final String dev this.routerGuestGateway = routerGuestGateway; this.cidr = cidr; this.dns = dns; + this.dns6 = dns6; this.domainName = domainName; } @@ -118,6 +120,14 @@ public void setDns(final String dns) { this.dns = dns; } + public String getDns6() { + return dns6; + } + + public void setDns6(String dns6) { + this.dns6 = dns6; + } + public String getDomainName() { return domainName; } diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 698ad52ea60f..0ea8e527d22d 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -1004,6 +1004,8 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute String defaultDns1 = null; String defaultDns2 = null; + String defaultIp6Dns1 = null; + String defaultIp6Dns2 = null; final boolean dnsProvided = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dns, Provider.VPCVirtualRouter); final boolean dhcpProvided = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, Provider.VPCVirtualRouter); @@ -1022,6 +1024,8 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute } else { defaultDns2 = dcVo.getDns2(); } + defaultIp6Dns1 = dcVo.getIp6Dns1(); + defaultIp6Dns2 = dcVo.getIp6Dns2(); } final Nic nic = _nicDao.findByNtwkIdAndInstanceId(network.getId(), router.getId()); @@ -1035,7 +1039,7 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute NicVO publicNic = _nicDao.findDefaultNicForVM(router.getId()); if (publicNic != null) { - updateSetupGuestNetworkCommandIpv6(setupCmd, network, publicNic.getMacAddress()); + updateSetupGuestNetworkCommandIpv6(setupCmd, network, publicNic.getMacAddress(), defaultIp6Dns1, defaultIp6Dns2); } final String brd = NetUtils.long2Ip(NetUtils.ip2Long(guestNic.getIPv4Address()) | ~NetUtils.ip2Long(guestNic.getIPv4Netmask())); @@ -1054,9 +1058,11 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute return setupCmd; } - private void updateSetupGuestNetworkCommandIpv6(SetupGuestNetworkCommand setupCmd, Network network, String macAddress) { + private void updateSetupGuestNetworkCommandIpv6(SetupGuestNetworkCommand setupCmd, Network network, String macAddress, String defaultIp6Dns1, String defaultIp6Dns2) { boolean isIpv6Supported = _ipv6Service.isIpv6Supported(network.getNetworkOfferingId()); if (isIpv6Supported) { + setupCmd.setDefaultIp6Dns1(defaultIp6Dns1); + setupCmd.setDefaultIp6Dns2(defaultIp6Dns2); final String routerIpv6 = _ipv6AddressDao.getRouterIpv6ByNetwork(network.getId()); if (routerIpv6 == null) { final String routerIpv6Gateway = Ipv6Service.routerIpv6Gateway.valueIn(network.getAccountId()); diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 39d4c5f55df6..914d118c6f00 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1972,12 +1972,12 @@ public boolean finalizeVirtualMachineProfile(final VirtualMachineProfile profile buf.append(" gateway=").append(nic.getIPv4Gateway()); } if (ipv6) { + defaultIp6Dns1 = nic.getIPv6Dns1() != null? nic.getIPv6Dns1() : dc.getIp6Dns1(); + defaultIp6Dns2 = nic.getIPv6Dns2() != null? nic.getIPv6Dns2() : dc.getIp6Dns2(); buf.append(" ip6gateway=").append(nic.getIPv6Gateway()); } defaultDns1 = nic.getIPv4Dns1(); defaultDns2 = nic.getIPv4Dns2(); - defaultIp6Dns1 = nic.getIPv6Dns1(); - defaultIp6Dns2 = nic.getIPv6Dns2(); } if (nic.getTrafficType() == TrafficType.Management) { diff --git a/systemvm/debian/etc/radvd.conf.tmpl b/systemvm/debian/etc/radvd.conf.tmpl index 247a877644ab..0001c9df401b 100644 --- a/systemvm/debian/etc/radvd.conf.tmpl +++ b/systemvm/debian/etc/radvd.conf.tmpl @@ -8,4 +8,5 @@ interface {{ GUEST_INTERFACE }} AdvOnLink on; AdvAutonomous on; }; +{{ RDNSS_CONFIG }} }; diff --git a/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py b/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py index f2ae38882836..3b9aebdba8b7 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py @@ -99,4 +99,10 @@ def add_radvd_conf(self, entry): self.conf.append(" AdvOnLink on;") self.conf.append(" AdvAutonomous on;") self.conf.append(" };") + if 'dns6' in entry.keys() and entry['dns6']: + for dns in entry['dns6'].split(","): + self.conf.append(" RDNSS %s" % dns) + self.conf.append(" {") + self.conf.append(" AdvRDNSSLifetime 30;") + self.conf.append(" };") self.conf.append("};") diff --git a/systemvm/debian/opt/cloud/bin/setup/common.sh b/systemvm/debian/opt/cloud/bin/setup/common.sh index 1b4de011c658..96f6f4a87329 100755 --- a/systemvm/debian/opt/cloud/bin/setup/common.sh +++ b/systemvm/debian/opt/cloud/bin/setup/common.sh @@ -371,8 +371,15 @@ setup_radvd() { cp /etc/radvd.conf.tmpl /etc/radvd.conf.$intf sed -i "s,{{ GUEST_INTERFACE }},$intf,g" /etc/radvd.conf.$intf sed -i "s,{{ IPV6_CIDR }},$ip6cidr,g" /etc/radvd.conf.$intf + RDNSS_CFG= + if [ -n "$IP6_NS1" ];then + RDNSS_CFG=$RDNSS_CFG" RDNSS $IP6_NS1\n {\n AdvRDNSSLifetime 30;\n };\n" + fi + if [ -n "$IP6_NS2" ];then + RDNSS_CFG=$RDNSS_CFG" RDNSS $IP6_NS2\n {\n AdvRDNSSLifetime 30;\n };\n" + fi + sed -i "s,{{ RDNSS_CONFIG }},$RDNSS_CFG,g" /etc/radvd.conf.$intf cat /etc/radvd.conf.$intf >> /etc/radvd.conf - systemctl enable radvd echo "radvd" >> /var/cache/cloud/enabled_svcs } From 5000bcfc646db4f4c409de31552e6315a3c1964a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 Oct 2021 08:48:15 +0200 Subject: [PATCH 009/109] IPv6/UI: support ipv6 protocols in Network ACL --- ui/public/locales/en.json | 4 ++++ ui/src/views/network/AclListRulesTab.vue | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index e7f08baaa7a4..4a74d337c754 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -434,6 +434,7 @@ "label.alerts": "Alerts", "label.algorithm": "Algorithm", "label.all": "All", +"label.all.ipv6": "All IPv6", "label.all.zone": "All Zones", "label.allocated": "Allocated", "label.allocatediops": "IOPS Allocated", @@ -1078,6 +1079,7 @@ "label.hypervnetworklabel": "HyperV Traffic Label", "label.i.accept.all.license.agreements": "I accept all license agreement", "label.icmp": "ICMP", +"label.icmp6": "ICMPv6", "label.icmpcode": "ICMP Code", "label.icmpcode.end.port": "ICMP Code / End Port", "label.icmptype": "ICMP Type", @@ -2180,6 +2182,7 @@ "label.tariffvalue": "Tariff Value", "label.task.completed": "Task completed", "label.tcp": "TCP", +"label.tcp6": "TCPv6", "label.tcp.proxy": "TCP Proxy", "label.template": "Select a template", "label.template.select.existing": "Select an existing template", @@ -2252,6 +2255,7 @@ "label.type.id": "Type ID", "label.ucs": "UCS", "label.udp": "UDP", +"label.udp6": "UDPv6", "label.uk.keyboard": "UK keyboard", "label.unauthorized": "Unauthorized", "label.unavailable": "Unavailable", diff --git a/ui/src/views/network/AclListRulesTab.vue b/ui/src/views/network/AclListRulesTab.vue index 673d33862a71..04a1d91dc116 100644 --- a/ui/src/views/network/AclListRulesTab.vue +++ b/ui/src/views/network/AclListRulesTab.vue @@ -181,6 +181,10 @@ {{ $t('label.icmp') | capitalise }} {{ $t('label.all') }} {{ $t('label.protocol.number') }} + {{ $t('label.tcp6') | capitalise }} + {{ $t('label.udp6') | capitalise }} + {{ $t('label.icmp6') | capitalise }} + {{ $t('label.all.ipv6') }} From d7543dea5b7465b3df9700410cfd5584acdcc951 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 15 Dec 2021 11:19:04 +0530 Subject: [PATCH 010/109] wip Signed-off-by: Abhishek Kumar --- .../configuration/ConfigurationService.java | 19 +- ...ix.java => DataCenterGuestIpv6Prefix.java} | 6 +- ...a => Ipv6GuestPrefixSubnetNetworkMap.java} | 3 +- .../PublicIpv6AddressNetworkMap.java} | 24 +- .../com/cloud/offering/NetworkOffering.java | 2 +- .../cloudstack/api/ResponseGenerator.java | 21 +- ...a => CreateGuestNetworkIpv6PrefixCmd.java} | 39 ++- .../DeleteGuestNetworkIpv6RangeCmd.java | 90 +++++ .../ListGuestNetworkIpv6PrefixesCmd.java | 82 +++++ .../DataCenterGuestIpv6PrefixResponse.java | 71 ++++ .../cloudstack/api/response/PodResponse.java | 20 -- .../api/response/VlanIpRangeResponse.java | 21 +- .../agent/api/SetupGuestNetworkCommand.java | 1 + .../com/cloud/network/vpc/VpcManager.java | 2 +- .../orchestration/NetworkOrchestrator.java | 6 + ....java => DataCenterGuestIpv6PrefixVO.java} | 11 +- .../com/cloud/dc/PodManagementIp6RangeVO.java | 160 --------- ...java => DataCenterGuestIpv6PrefixDao.java} | 8 +- ... => DataCenterGuestIpv6PrefixDaoImpl.java} | 19 +- .../dc/dao/PodManagementIp6RangeDaoImpl.java | 50 --- .../java/com/cloud/dc/dao/VlanDaoImpl.java | 2 +- ...=> Ipv6GuestPrefixSubnetNetworkMapVO.java} | 32 +- .../PublicIpv6AddressNetworkMapVO.java | 112 +++++++ ...Ip6GuestPrefixSubnetNetworkMapDaoImpl.java | 67 ---- .../Ipv6GuestPrefixSubnetNetworkMapDao.java} | 17 +- ...pv6GuestPrefixSubnetNetworkMapDaoImpl.java | 107 ++++++ ...va => PublicIpv6AddressNetworkMapDao.java} | 9 +- .../PublicIpv6AddressNetworkMapDaoImpl.java | 78 +++++ .../offerings/dao/NetworkOfferingDao.java | 2 + .../offerings/dao/NetworkOfferingDaoImpl.java | 6 + ...spring-engine-schema-core-daos-context.xml | 6 +- .../META-INF/db/schema-41610to41700.sql | 15 +- .../java/com/cloud/api/ApiResponseHelper.java | 68 ++-- .../ConfigurationManagerImpl.java | 102 ++++-- .../java/com/cloud/network/Ipv6Service.java | 57 ++++ .../com/cloud/network/Ipv6ServiceImpl.java | 314 ++++++++++++++++++ .../com/cloud/network/NetworkServiceImpl.java | 114 ++----- .../guru/ExternalGuestNetworkGuru.java | 29 +- .../cloud/network/guru/GuestNetworkGuru.java | 56 +++- .../cloud/network/guru/PublicNetworkGuru.java | 5 + .../network/router/CommandSetupHelper.java | 47 ++- .../network/router/NetworkHelperImpl.java | 5 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 2 +- .../cloud/server/ManagementServerImpl.java | 8 +- .../spring-server-core-managers-context.xml | 2 + .../vpc/MockConfigurationManagerImpl.java | 29 +- .../test/resources/createNetworkOffering.xml | 1 + ui/src/role/index.js | 2 +- .../views/infra/network/IpRangesTabGuest.vue | 77 ++--- .../views/infra/network/IpRangesTabPublic.vue | 15 +- 50 files changed, 1393 insertions(+), 648 deletions(-) rename api/src/main/java/com/cloud/dc/{PodGuestIp6Prefix.java => DataCenterGuestIpv6Prefix.java} (87%) rename api/src/main/java/com/cloud/network/{Ip6GuestPrefixSubnetNetworkMap.java => Ipv6GuestPrefixSubnetNetworkMap.java} (88%) rename api/src/main/java/com/cloud/{dc/PodManagementIp6Range.java => network/PublicIpv6AddressNetworkMap.java} (71%) rename api/src/main/java/org/apache/cloudstack/api/command/admin/network/{CreateGuestNetworkIp6PrefixCmd.java => CreateGuestNetworkIpv6PrefixCmd.java} (72%) create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6RangeCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/admin/network/ListGuestNetworkIpv6PrefixesCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java rename engine/schema/src/main/java/com/cloud/dc/{PodGuestIp6PrefixVO.java => DataCenterGuestIpv6PrefixVO.java} (89%) delete mode 100644 engine/schema/src/main/java/com/cloud/dc/PodManagementIp6RangeVO.java rename engine/schema/src/main/java/com/cloud/dc/dao/{PodManagementIp6RangeDao.java => DataCenterGuestIpv6PrefixDao.java} (75%) rename engine/schema/src/main/java/com/cloud/dc/dao/{PodGuestIp6PrefixDaoImpl.java => DataCenterGuestIpv6PrefixDaoImpl.java} (63%) delete mode 100644 engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDaoImpl.java rename engine/schema/src/main/java/com/cloud/network/{Ip6GuestPrefixSubnetNetworkMapVO.java => Ipv6GuestPrefixSubnetNetworkMapVO.java} (73%) create mode 100644 engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java delete mode 100644 engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDaoImpl.java rename engine/schema/src/main/java/com/cloud/{dc/dao/PodGuestIp6PrefixDao.java => network/dao/Ipv6GuestPrefixSubnetNetworkMapDao.java} (55%) create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java rename engine/schema/src/main/java/com/cloud/network/dao/{Ip6GuestPrefixSubnetNetworkMapDao.java => PublicIpv6AddressNetworkMapDao.java} (71%) create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java create mode 100644 server/src/main/java/com/cloud/network/Ipv6Service.java create mode 100644 server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index d0207d5bad80..5e02f4ce2e81 100644 --- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java +++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java @@ -19,11 +19,13 @@ import java.util.List; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; -import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIp6PrefixCmd; +import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd; import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd; @@ -51,6 +53,7 @@ import org.apache.cloudstack.region.PortableIpRange; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterGuestIpv6Prefix; import com.cloud.dc.Pod; import com.cloud.dc.Vlan; import com.cloud.domain.Domain; @@ -215,9 +218,19 @@ public interface ConfigurationService { void updatePodIpRange(UpdatePodManagementNetworkIpRangeCmd cmd) throws ConcurrentOperationException; /** - * ToDo + * Creates a new IPv6 prefix for a zone. Needs to be >= /64. */ - Pod createPodGuestIp6Prefix(CreateGuestNetworkIp6PrefixCmd cmd); + DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(CreateGuestNetworkIpv6PrefixCmd cmd); + + /** + * Lists IPv6 prefixes for a zone. + */ + List listDataCenterGuestIpv6Prefixes(ListGuestNetworkIpv6PrefixesCmd cmd); + + /** + * Deletes an existing IPv6 prefix. + */ + boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6RangeCmd cmd); /** * Edits a pod in the database. Will not allow you to edit pods that are being used anywhere in the system. diff --git a/api/src/main/java/com/cloud/dc/PodGuestIp6Prefix.java b/api/src/main/java/com/cloud/dc/DataCenterGuestIpv6Prefix.java similarity index 87% rename from api/src/main/java/com/cloud/dc/PodGuestIp6Prefix.java rename to api/src/main/java/com/cloud/dc/DataCenterGuestIpv6Prefix.java index 38dfddd32d6d..0a1d451a6621 100644 --- a/api/src/main/java/com/cloud/dc/PodGuestIp6Prefix.java +++ b/api/src/main/java/com/cloud/dc/DataCenterGuestIpv6Prefix.java @@ -17,14 +17,18 @@ package com.cloud.dc; +import java.util.Date; + import org.apache.cloudstack.acl.InfrastructureEntity; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; -public interface PodGuestIp6Prefix extends InfrastructureEntity, InternalIdentity, Identity { +public interface DataCenterGuestIpv6Prefix extends InfrastructureEntity, InternalIdentity, Identity { Long getDataCenterId(); Long getPodId(); String getPrefix(); + + Date getCreated(); } diff --git a/api/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMap.java b/api/src/main/java/com/cloud/network/Ipv6GuestPrefixSubnetNetworkMap.java similarity index 88% rename from api/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMap.java rename to api/src/main/java/com/cloud/network/Ipv6GuestPrefixSubnetNetworkMap.java index 3b764b1b8269..48f42a0ec92b 100644 --- a/api/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMap.java +++ b/api/src/main/java/com/cloud/network/Ipv6GuestPrefixSubnetNetworkMap.java @@ -20,8 +20,9 @@ import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; -public interface Ip6GuestPrefixSubnetNetworkMap extends Identity, InternalIdentity { +public interface Ipv6GuestPrefixSubnetNetworkMap extends Identity, InternalIdentity { enum State { + Allocating, // The subnet will be assigned to a network Allocated, // The subnet is in use. Free // The subnet is ready to be allocated. } diff --git a/api/src/main/java/com/cloud/dc/PodManagementIp6Range.java b/api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java similarity index 71% rename from api/src/main/java/com/cloud/dc/PodManagementIp6Range.java rename to api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java index ef3416adb3e3..0df9115478ea 100644 --- a/api/src/main/java/com/cloud/dc/PodManagementIp6Range.java +++ b/api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java @@ -15,24 +15,22 @@ // specific language governing permissions and limitations // under the License. -package com.cloud.dc; +package com.cloud.network; -import org.apache.cloudstack.acl.InfrastructureEntity; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; -public interface PodManagementIp6Range extends InfrastructureEntity, InternalIdentity, Identity { - Long getDataCenterId(); +public interface PublicIpv6AddressNetworkMap extends Identity, InternalIdentity { + enum State { + Allocated, // The subnet is in use. + Free // The subnet is ready to be allocated. + } - Long getPodId(); + long getRangeId(); - String getGateway(); + String getIp6Address(); - String getCidr(); + Long getNetworkId(); - Integer getVlan(); - - String getStartIp(); - - String getEndIp(); -} \ No newline at end of file + PublicIpv6AddressNetworkMap.State getState(); +} diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java index 738f0a55ed10..f85c5487f18b 100644 --- a/api/src/main/java/com/cloud/offering/NetworkOffering.java +++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java @@ -42,7 +42,7 @@ public enum State { } public enum Detail { - InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RelatedNetworkOffering, domainid, zoneid, pvlanType, internetProtocol + InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RelatedNetworkOffering, domainid, zoneid, pvlanType, internetProtocol, ipv6Firewall } public enum InternetProtocol { diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java index 03f0a3c8369f..90566a4c0c94 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java @@ -22,12 +22,6 @@ import java.util.Map; import java.util.Set; -import com.cloud.server.ResourceIcon; -import org.apache.cloudstack.api.response.ResourceIconResponse; -import org.apache.cloudstack.api.response.RouterHealthCheckResultResponse; -import com.cloud.resource.RollingMaintenanceManager; -import org.apache.cloudstack.api.response.RollingMaintenanceResponse; -import org.apache.cloudstack.management.ManagementServerHost; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ApiConstants.HostDetails; @@ -41,6 +35,7 @@ import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse; import org.apache.cloudstack.api.response.BackupOfferingResponse; +import org.apache.cloudstack.api.response.BackupResponse; import org.apache.cloudstack.api.response.BackupScheduleResponse; import org.apache.cloudstack.api.response.CapacityResponse; import org.apache.cloudstack.api.response.ClusterResponse; @@ -48,6 +43,7 @@ import org.apache.cloudstack.api.response.ConfigurationResponse; import org.apache.cloudstack.api.response.CounterResponse; import org.apache.cloudstack.api.response.CreateCmdResponse; +import org.apache.cloudstack.api.response.DataCenterGuestIpv6PrefixResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.DomainRouterResponse; @@ -92,8 +88,11 @@ import org.apache.cloudstack.api.response.RegionResponse; import org.apache.cloudstack.api.response.RemoteAccessVpnResponse; import org.apache.cloudstack.api.response.ResourceCountResponse; +import org.apache.cloudstack.api.response.ResourceIconResponse; import org.apache.cloudstack.api.response.ResourceLimitResponse; import org.apache.cloudstack.api.response.ResourceTagResponse; +import org.apache.cloudstack.api.response.RollingMaintenanceResponse; +import org.apache.cloudstack.api.response.RouterHealthCheckResultResponse; import org.apache.cloudstack.api.response.SSHKeyPairResponse; import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; @@ -117,7 +116,6 @@ import org.apache.cloudstack.api.response.UsageRecordResponse; import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserVmResponse; -import org.apache.cloudstack.api.response.BackupResponse; import org.apache.cloudstack.api.response.VMSnapshotResponse; import org.apache.cloudstack.api.response.VirtualRouterProviderResponse; import org.apache.cloudstack.api.response.VlanIpRangeResponse; @@ -126,10 +124,11 @@ import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; -import org.apache.cloudstack.backup.BackupOffering; import org.apache.cloudstack.backup.Backup; +import org.apache.cloudstack.backup.BackupOffering; import org.apache.cloudstack.backup.BackupSchedule; import org.apache.cloudstack.config.Configuration; +import org.apache.cloudstack.management.ManagementServerHost; import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; import org.apache.cloudstack.region.PortableIp; import org.apache.cloudstack.region.PortableIpRange; @@ -140,6 +139,7 @@ import com.cloud.configuration.ResourceCount; import com.cloud.configuration.ResourceLimit; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterGuestIpv6Prefix; import com.cloud.dc.Pod; import com.cloud.dc.StorageNetworkIpRange; import com.cloud.dc.Vlan; @@ -191,6 +191,8 @@ import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; import com.cloud.region.ha.GlobalLoadBalancerRule; +import com.cloud.resource.RollingMaintenanceManager; +import com.cloud.server.ResourceIcon; import com.cloud.server.ResourceTag; import com.cloud.storage.GuestOS; import com.cloud.storage.GuestOSHypervisor; @@ -274,6 +276,8 @@ public interface ResponseGenerator { ZoneResponse createZoneResponse(ResponseView view, DataCenter dataCenter, Boolean showCapacities, Boolean showResourceIcon); + DataCenterGuestIpv6PrefixResponse createDataCenterGuestIpv6PrefixResponse(DataCenterGuestIpv6Prefix prefix); + VolumeResponse createVolumeResponse(ResponseView view, Volume volume); InstanceGroupResponse createInstanceGroupResponse(InstanceGroup group); @@ -490,5 +494,4 @@ List createTemplateResponses(ResponseView view, VirtualMachine RollingMaintenanceResponse createRollingMaintenanceResponse(Boolean success, String details, List hostsUpdated, List hostsSkipped); ResourceIconResponse createResourceIconResponse(ResourceIcon resourceIcon); - } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIp6PrefixCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java similarity index 72% rename from api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIp6PrefixCmd.java rename to api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java index 89a781d0acdf..945f9da74c85 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIp6PrefixCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java @@ -25,10 +25,12 @@ import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DataCenterGuestIpv6PrefixResponse; import org.apache.cloudstack.api.response.PodResponse; +import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.log4j.Logger; -import com.cloud.dc.Pod; +import com.cloud.dc.DataCenterGuestIpv6Prefix; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; @@ -36,26 +38,32 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.Account; -@APICommand(name = CreateGuestNetworkIp6PrefixCmd.APINAME, - description = "Creates a Guest network IPv6 prefix.", - responseObject = PodResponse.class, +@APICommand(name = CreateGuestNetworkIpv6PrefixCmd.APINAME, + description = "Creates a guest network IPv6 prefix.", + responseObject = DataCenterGuestIpv6PrefixResponse.class, since = "4.17.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin}) -public class CreateGuestNetworkIp6PrefixCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(CreateGuestNetworkIp6PrefixCmd.class); +public class CreateGuestNetworkIpv6PrefixCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(CreateGuestNetworkIpv6PrefixCmd.class); - public static final String APINAME = "createGuestNetworkIp6Prefix"; + public static final String APINAME = "createGuestNetworkIpv6Prefix"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.UUID, + entityType = ZoneResponse.class, + required = true, + description = "UUID of zone to which the IPv6 prefix belongs to.", + validations = {ApiArgValidator.PositiveNumber}) + private Long zoneId; @Parameter(name = ApiConstants.POD_ID, type = CommandType.UUID, entityType = PodResponse.class, - required = true, - description = "UUID of POD, where the IP range belongs to.", + description = "UUID of POD to which the IPv6 prefix belongs to.", validations = {ApiArgValidator.PositiveNumber}) private Long podId; @@ -69,6 +77,11 @@ public class CreateGuestNetworkIp6PrefixCmd extends BaseAsyncCmd { /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// + + public Long getZoneId() { + return zoneId; + } + public Long getPodId() { return podId; } @@ -83,19 +96,19 @@ public String getEventType() { @Override public String getEventDescription() { - return "Creating public IPv6 prefix " + getPrefix() + " for pod=" + getPodId(); + return "Creating guest IPv6 prefix " + getPrefix() + " for zone=" + getZoneId(); } @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { - Pod result = _configService.createPodGuestIp6Prefix(this); + DataCenterGuestIpv6Prefix result = _configService.createDataCenterGuestIpv6Prefix(this); if (result != null) { - PodResponse response = _responseGenerator.createPodResponse(result, false); + DataCenterGuestIpv6PrefixResponse response = _responseGenerator.createDataCenterGuestIpv6PrefixResponse(result); response.setResponseName(getCommandName()); this.setResponseObject(response); } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Pod Public IP6 prefix."); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create zone guest IPv6 prefix."); } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6RangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6RangeCmd.java new file mode 100644 index 000000000000..93b1649cf67a --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6RangeCmd.java @@ -0,0 +1,90 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.network; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.log4j.Logger; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.utils.exception.CloudRuntimeException; + +@APICommand(name = DeleteGuestNetworkIpv6RangeCmd.APINAME, + description = "Deletes an existing guest network IPv6 prefix.", + responseObject = SuccessResponse.class, + since = "4.17.0.0", + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, + authorized = {RoleType.Admin}) +public class DeleteGuestNetworkIpv6RangeCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DeleteGuestNetworkIpv6RangeCmd.class); + public static final String APINAME = "deleteNetworkDevice"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = HostResponse.class, required = true, description = "Id of the guest network IPv6 prefix") + private Long id; + + public Long getId() { + return id; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, + ResourceAllocationException { + try { + boolean result = _configService.deleteDataCenterGuestIpv6Prefix(this); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete guest network IPv6 prefix:" + getId()); + } + } catch (InvalidParameterValueException ex) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ex.getMessage()); + } catch (CloudRuntimeException ex) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); + } + + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/ListGuestNetworkIpv6PrefixesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/ListGuestNetworkIpv6PrefixesCmd.java new file mode 100644 index 000000000000..5a1fd2f065ec --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/ListGuestNetworkIpv6PrefixesCmd.java @@ -0,0 +1,82 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.network; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.DataCenterGuestIpv6PrefixResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.ZoneResponse; + +import com.cloud.dc.DataCenterGuestIpv6Prefix; + +@APICommand(name = ListGuestNetworkIpv6PrefixesCmd.APINAME, + description = "Lists guest network IPv6 prefixes", + responseObject = DataCenterGuestIpv6PrefixResponse.class, + since = "4.17.0", + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false) + +public class ListGuestNetworkIpv6PrefixesCmd extends BaseListCmd { + + public static final String APINAME = "listGuestNetworkIpv6Prefixes"; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.UUID, + entityType = ZoneResponse.class, + required = true, + description = "UUID of zone to which the IPv6 prefix belongs to.", + validations = {ApiArgValidator.PositiveNumber}) + private Long zoneId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public Long getZoneId() { + return zoneId; + } + + @Override + public void execute() { + List prefixes = _configService.listDataCenterGuestIpv6Prefixes(this); + ListResponse response = new ListResponse<>(); + List prefixResponses = new ArrayList<>(); + for (DataCenterGuestIpv6Prefix prefix : prefixes) { + DataCenterGuestIpv6PrefixResponse prefixResponse = _responseGenerator.createDataCenterGuestIpv6PrefixResponse(prefix); + prefixResponse.setObjectName("guestnetworkipv6prefix"); + prefixResponses.add(prefixResponse); + } + + response.setResponses(prefixResponses, prefixes.size()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + RESPONSE_SUFFIX; + } + +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java new file mode 100644 index 000000000000..f4c8e636aaac --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java @@ -0,0 +1,71 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.response; + +import java.util.Date; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import com.cloud.dc.DataCenterGuestIpv6Prefix; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@EntityReference(value = DataCenterGuestIpv6Prefix.class) +public class DataCenterGuestIpv6PrefixResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) + @Param(description = "id of the guest IPv6 prefix") + private String id; + + @SerializedName(ApiConstants.PREFIX) + @Param(description = "guest IPv6 prefix") + private String prefix; + + @SerializedName(ApiConstants.ZONE_ID) + @Param(description = "id of zone to which the IPv6 prefix belongs to." ) + private String zoneId; + + @SerializedName(ApiConstants.POD_ID) + @Param(description = "id of pod to which the IPv6 prefix belongs to." ) + private String pod; + + @SerializedName(ApiConstants.CREATED) + @Param(description = " date when this IPv6 prefix was created." ) + private Date created; + + public void setId(String id) { + this.id = id; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public void setPod(String pod) { + this.pod = pod; + } + + public void setCreated(Date created) { + this.created = created; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/PodResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/PodResponse.java index 4af8fc52e1b2..587fabfae8db 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/PodResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/PodResponse.java @@ -57,10 +57,6 @@ public class PodResponse extends BaseResponseWithAnnotations { @Param(description = "the IP ranges for the Pod", responseObject = IpRangeResponse.class, since = "4.16.0") private List ipRanges; - @SerializedName(ApiConstants.IP6_RANGES) - @Param(description = "the IPv6 ranges for the Pod", responseObject = IpRangeResponse.class, since = "4.17.0") - private List ip6Ranges; - @Deprecated(since = "4.16") @SerializedName(ApiConstants.START_IP) @Param(description = "the starting IP for the Pod. This parameter is deprecated, please use 'startip' from ipranges parameter.") @@ -89,10 +85,6 @@ public class PodResponse extends BaseResponseWithAnnotations { @Param(description = "the capacity of the Pod", responseObject = CapacityResponse.class) private List capacities; - @SerializedName(ApiConstants.GUEST_IP6_PREFIX) - @Param(description = "the guest IPv6 prefixes for the Pod", since = "4.17.0") - private List publicIp6Prefixes; - public String getId() { return id; } @@ -145,10 +137,6 @@ public void setIpRanges(List ipRanges) { this.ipRanges = ipRanges; } - public void setIp6Ranges(List ip6Ranges) { - this.ip6Ranges = ip6Ranges; - } - public List getStartIp() { return startIp; } @@ -196,12 +184,4 @@ public List getCapacities() { public void setCapacities(List capacities) { this.capacities = capacities; } - - public List getPublicIp6Prefixes() { - return publicIp6Prefixes; - } - - public void setPublicIp6Prefixes(List publicIp6Prefixes) { - this.publicIp6Prefixes = publicIp6Prefixes; - } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java index 5656a92955d1..a22e2eb7024d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java @@ -16,14 +16,13 @@ // under the License. package org.apache.cloudstack.api.response; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; import com.cloud.dc.Vlan; import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; @EntityReference(value = Vlan.class) @SuppressWarnings("unused") @@ -64,6 +63,10 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit @Param(description = "the Pod name for the VLAN IP range") private String podName; + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the description of the VLAN IP range") + private String description; + @SerializedName(ApiConstants.GATEWAY) @Param(description = "the gateway of the VLAN IP range") private String gateway; @@ -72,9 +75,9 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit @Param(description = "the netmask of the VLAN IP range") private String netmask; - @SerializedName(ApiConstants.DESCRIPTION) - @Param(description = "the description of the VLAN IP range") - private String description; + @SerializedName(ApiConstants.CIDR) + @Param(description = "the cidr of the VLAN IP range") + private String cidr; @SerializedName(ApiConstants.START_IP) @Param(description = "the start ip of the VLAN IP range") @@ -167,6 +170,10 @@ public void setPodName(String podName) { this.podName = podName; } + public void setDescription(String description) { + this.description = description; + } + public void setGateway(String gateway) { this.gateway = gateway; } @@ -175,8 +182,8 @@ public void setNetmask(String netmask) { this.netmask = netmask; } - public void setDescription(String description) { - this.description = description; + public void setCidr(String cidr) { + this.cidr = cidr; } public void setStartIp(String startIp) { diff --git a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java index a5a7028e8e9b..2cf5b7975162 100644 --- a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java +++ b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java @@ -35,6 +35,7 @@ public class SetupGuestNetworkCommand extends NetworkElementCommand { String routerIpv6 = null; String routerIpv6Gateway = null; String routerIpv6Cidr = null; + Boolean routerIpv6Firewall = null; public NicTO getNic() { return nic; diff --git a/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java b/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java index db4221f9e3ee..56e70ca56f1f 100644 --- a/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java +++ b/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java @@ -109,7 +109,7 @@ public interface VpcManager { Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Long aclId, Account caller, - Boolean displayNetworkEnabled, String externalId) + Boolean displayNetworkEnabled, String externalId, String ip6Gateway, String ip6Cidr) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index bcd52a0d1dad..10351c533b0d 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -115,6 +115,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddress; import com.cloud.network.IpAddressManager; +import com.cloud.network.Ipv6Service; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Event; @@ -318,6 +319,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra ResourceManager resourceManager; @Inject private AnnotationDao annotationDao; + @Inject + Ipv6Service ipv6Service; List networkGurus; @@ -3098,6 +3101,9 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { throw new CloudRuntimeException("Failed to delete network " + networkFinal + "; was unable to cleanup corresponding ip ranges"); } else { // commit transaction only when ips and vlans for the network are released successfully + + ipv6Service.releaseIpv6SubnetForNetwork(networkId); + ipv6Service.releasePublicIpv6ForNetwork(networkId); try { stateTransitTo(networkFinal, Event.DestroyNetwork); } catch (final NoTransitionException e) { diff --git a/engine/schema/src/main/java/com/cloud/dc/PodGuestIp6PrefixVO.java b/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java similarity index 89% rename from engine/schema/src/main/java/com/cloud/dc/PodGuestIp6PrefixVO.java rename to engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java index dd90cafd023b..9b19e332a283 100644 --- a/engine/schema/src/main/java/com/cloud/dc/PodGuestIp6PrefixVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java @@ -30,8 +30,8 @@ import javax.persistence.TemporalType; @Entity -@Table(name = "pod_ip6_guest_prefix") -public class PodGuestIp6PrefixVO implements PodGuestIp6Prefix { +@Table(name = "dc_ip6_guest_prefix") +public class DataCenterGuestIpv6PrefixVO implements DataCenterGuestIpv6Prefix { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") @@ -44,7 +44,7 @@ public class PodGuestIp6PrefixVO implements PodGuestIp6Prefix { private long dataCenterId; @Column(name = "pod_id") - private long podId; + private Long podId; @Column(name = "prefix") private String prefix; @@ -53,7 +53,7 @@ public class PodGuestIp6PrefixVO implements PodGuestIp6Prefix { @Temporal(value = TemporalType.TIMESTAMP) private Date created = null; - public PodGuestIp6PrefixVO(long dcId, long podId, String prefix) { + public DataCenterGuestIpv6PrefixVO(long dcId, Long podId, String prefix) { this(); this.dataCenterId = dcId; this.podId = podId; @@ -61,7 +61,7 @@ public PodGuestIp6PrefixVO(long dcId, long podId, String prefix) { this.created = new Date(); } - protected PodGuestIp6PrefixVO() { + protected DataCenterGuestIpv6PrefixVO() { this.uuid = UUID.randomUUID().toString(); } @@ -101,6 +101,7 @@ public void setPrefix(String prefix) { this.prefix = prefix; } + @Override public Date getCreated() { return created; } diff --git a/engine/schema/src/main/java/com/cloud/dc/PodManagementIp6RangeVO.java b/engine/schema/src/main/java/com/cloud/dc/PodManagementIp6RangeVO.java deleted file mode 100644 index f06f594fcc97..000000000000 --- a/engine/schema/src/main/java/com/cloud/dc/PodManagementIp6RangeVO.java +++ /dev/null @@ -1,160 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package com.cloud.dc; - -import java.util.Date; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; - -@Entity -@Table(name = "pod_ip6_range") -public class PodManagementIp6RangeVO implements PodManagementIp6Range { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - private long id; - - @Column(name = "uuid") - String uuid; - - @Column(name = "data_center_id") - private long dataCenterId; - - @Column(name = "pod_id") - private long podId; - - @Column(name = "gateway") - private String gateway; - - @Column(name = "cidr") - private String cidr; - - @Column(name = "vlan") - private Integer vlan; - - @Column(name = "start_ip") - private String startIp; - - @Column(name = "end_ip") - private String endIp; - - @Column(name = "created") - @Temporal(value = TemporalType.TIMESTAMP) - private Date created = null; - - public PodManagementIp6RangeVO(long dcId, long podId, String gateway, String cidr, Integer vlan, String startIp, String endIp) { - this(); - this.dataCenterId = dcId; - this.podId = podId; - this.gateway = gateway; - this.cidr = cidr; - this.vlan = vlan; - this.startIp = startIp; - this.endIp = endIp; - this.created = new Date(); - } - - protected PodManagementIp6RangeVO() { - this.uuid = UUID.randomUUID().toString(); - } - - @Override - public long getId() { - return id; - } - - @Override - public String getUuid() { - return uuid; - } - - @Override - public Long getDataCenterId() { - return dataCenterId; - } - - public void setDataCenterId(long dcId) { - this.dataCenterId = dcId; - } - - @Override - public Long getPodId() { - return podId; - } - - public void setPodId(long podId) { - this.podId = podId; - } - - @Override - public String getGateway() { - return this.gateway; - } - - public void setGateway(String gateway) { - this.gateway = gateway; - } - - @Override - public String getCidr() { - return cidr; - } - - public void setCidr(String cidr) { - this.cidr = cidr; - } - - @Override - public Integer getVlan() { - return vlan; - } - - public void setVlan(int vlan) { - this.vlan = vlan; - } - - @Override - public String getStartIp() { - return startIp; - } - - public void setStartIp(String start) { - this.startIp = start; - } - - @Override - public String getEndIp() { - return endIp; - } - - public void setEndIp(String end) { - this.endIp = end; - } - - public Date getCreated() { - return created; - } -} \ No newline at end of file diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDao.java similarity index 75% rename from engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDao.java rename to engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDao.java index 81bf4ae41eb8..278c0cc61864 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDao.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDao.java @@ -19,12 +19,12 @@ import java.util.List; -import com.cloud.dc.PodManagementIp6RangeVO; +import com.cloud.dc.DataCenterGuestIpv6PrefixVO; import com.cloud.utils.db.GenericDao; -public interface PodManagementIp6RangeDao extends GenericDao { +public interface DataCenterGuestIpv6PrefixDao extends GenericDao { - List listByPodId(long podId); + List listByPodId(long podId); - List listByDataCenterId(long dcId); + List listByDataCenterId(long dcId); } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDaoImpl.java similarity index 63% rename from engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDaoImpl.java rename to engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDaoImpl.java index 050720085f37..f0d140c1bcb8 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDaoImpl.java @@ -21,7 +21,7 @@ import org.springframework.stereotype.Component; -import com.cloud.dc.PodGuestIp6PrefixVO; +import com.cloud.dc.DataCenterGuestIpv6PrefixVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.QueryBuilder; @@ -29,21 +29,22 @@ @Component @DB -public class PodGuestIp6PrefixDaoImpl extends GenericDaoBase implements PodGuestIp6PrefixDao { +public class DataCenterGuestIpv6PrefixDaoImpl extends GenericDaoBase implements DataCenterGuestIpv6PrefixDao { - public PodGuestIp6PrefixDaoImpl() { + public DataCenterGuestIpv6PrefixDaoImpl() { } @Override - public List listByPodId(long podId) { - QueryBuilder sc = QueryBuilder.create(PodGuestIp6PrefixVO.class); - sc.and(sc.entity().getPodId(), SearchCriteria.Op.EQ, podId); - return sc.list(); + public List listByPodId(long podId) { + SearchCriteria sc = createSearchCriteria(); + sc.addOr("podId", SearchCriteria.Op.NULL); + sc.addOr("podId", SearchCriteria.Op.EQ, podId); + return listBy(sc); } @Override - public List listByDataCenterId(long dcId) { - QueryBuilder sc = QueryBuilder.create(PodGuestIp6PrefixVO.class); + public List listByDataCenterId(long dcId) { + QueryBuilder sc = QueryBuilder.create(DataCenterGuestIpv6PrefixVO.class); sc.and(sc.entity().getDataCenterId(), SearchCriteria.Op.EQ, dcId); return sc.list(); } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDaoImpl.java deleted file mode 100644 index 13fda5ec26fd..000000000000 --- a/engine/schema/src/main/java/com/cloud/dc/dao/PodManagementIp6RangeDaoImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package com.cloud.dc.dao; - -import java.util.List; - -import org.springframework.stereotype.Component; - -import com.cloud.dc.PodManagementIp6RangeVO; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.QueryBuilder; -import com.cloud.utils.db.SearchCriteria; - -@Component -@DB -public class PodManagementIp6RangeDaoImpl extends GenericDaoBase implements PodManagementIp6RangeDao { - - public PodManagementIp6RangeDaoImpl() { - } - - @Override - public List listByPodId(long podId) { - QueryBuilder sc = QueryBuilder.create(PodManagementIp6RangeVO.class); - sc.and(sc.entity().getPodId(), SearchCriteria.Op.EQ, podId); - return sc.list(); - } - - @Override - public List listByDataCenterId(long dcId) { - QueryBuilder sc = QueryBuilder.create(PodManagementIp6RangeVO.class); - sc.and(sc.entity().getDataCenterId(), SearchCriteria.Op.EQ, dcId); - return sc.list(); - } -} diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java index 67ee05d1f756..96df26dc86dc 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java @@ -260,7 +260,7 @@ public boolean configure(String name, Map params) throws Configu PhysicalNetworkVlanIp6Search.and("physicalNetworkId", PhysicalNetworkVlanIp6Search.entity().getPhysicalNetworkId(), SearchCriteria.Op.EQ); PhysicalNetworkVlanIp6Search.and("ip6Gateway", PhysicalNetworkVlanIp6Search.entity().getIp6Gateway(), SearchCriteria.Op.NNULL); PhysicalNetworkVlanIp6Search.and("ip6Cidr", PhysicalNetworkVlanIp6Search.entity().getIp6Cidr(), SearchCriteria.Op.NNULL); - PhysicalNetworkVlanIp6Search.and("ip6range", PhysicalNetworkVlanIp6Search.entity().getIpRange(), SearchCriteria.Op.NNULL); + PhysicalNetworkVlanIp6Search.and("ip6range", PhysicalNetworkVlanIp6Search.entity().getIp6Range(), SearchCriteria.Op.NNULL); PhysicalNetworkVlanIp6Search.done(); return result; diff --git a/engine/schema/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMapVO.java b/engine/schema/src/main/java/com/cloud/network/Ipv6GuestPrefixSubnetNetworkMapVO.java similarity index 73% rename from engine/schema/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMapVO.java rename to engine/schema/src/main/java/com/cloud/network/Ipv6GuestPrefixSubnetNetworkMapVO.java index 2317b8b436a8..769965dfdf11 100644 --- a/engine/schema/src/main/java/com/cloud/network/Ip6GuestPrefixSubnetNetworkMapVO.java +++ b/engine/schema/src/main/java/com/cloud/network/Ipv6GuestPrefixSubnetNetworkMapVO.java @@ -26,12 +26,14 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; import com.cloud.utils.db.GenericDao; @Entity @Table(name = "ip6_guest_prefix_subnet_network_map") -public class Ip6GuestPrefixSubnetNetworkMapVO implements Ip6GuestPrefixSubnetNetworkMap { +public class Ipv6GuestPrefixSubnetNetworkMapVO implements Ipv6GuestPrefixSubnetNetworkMap { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -53,17 +55,21 @@ public class Ip6GuestPrefixSubnetNetworkMapVO implements Ip6GuestPrefixSubnetNet @Column(name = "state") private State state; + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "updated") + Date updated; + @Column(name = GenericDao.CREATED_COLUMN) private Date created; @Column(name= GenericDao.REMOVED_COLUMN) private Date removed; - protected Ip6GuestPrefixSubnetNetworkMapVO() { + protected Ipv6GuestPrefixSubnetNetworkMapVO() { uuid = UUID.randomUUID().toString(); } - protected Ip6GuestPrefixSubnetNetworkMapVO(long prefixId, String subnet, Long networkId, State state) { + protected Ipv6GuestPrefixSubnetNetworkMapVO(long prefixId, String subnet, Long networkId, Ipv6GuestPrefixSubnetNetworkMap.State state) { this.prefixId = prefixId; this.subnet = subnet; this.networkId = networkId; @@ -96,8 +102,28 @@ public Long getNetworkId() { return networkId; } + public void setNetworkId(Long networkId) { + this.networkId = networkId; + } + @Override public State getState() { return state; } + + public void setState(Ipv6GuestPrefixSubnetNetworkMap.State state) { + this.state = state; + } + + public void setUpdated(Date updated) { + this.updated = updated; + } + + public Date getUpdated() { + return updated; + } + + public Date getCreated() { + return created; + } } diff --git a/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java b/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java new file mode 100644 index 000000000000..28e190a2520c --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java @@ -0,0 +1,112 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = "public_ip6_address_network_map") +public class PublicIpv6AddressNetworkMapVO implements PublicIpv6AddressNetworkMap { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "vlan_db_id") + private Long rangeId; + + @Column(name = "public_ip_address") + private String ip6Address; + + @Column(name = "network_id") + private Long networkId; + + @Column(name = "state") + private PublicIpv6AddressNetworkMap.State state; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + @Column(name= GenericDao.REMOVED_COLUMN) + private Date removed; + + protected PublicIpv6AddressNetworkMapVO() { + uuid = UUID.randomUUID().toString(); + } + + protected PublicIpv6AddressNetworkMapVO(long rangeId, String ip6Address, Long networkId, PublicIpv6AddressNetworkMap.State state) { + this.rangeId = rangeId; + this.ip6Address = ip6Address; + this.networkId = networkId; + this.state = state; + uuid = UUID.randomUUID().toString(); + } + + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public long getRangeId() { + return rangeId; + } + + @Override + public String getIp6Address() { + return ip6Address; + } + + @Override + public Long getNetworkId() { + return networkId; + } + + public void setNetworkId(Long networkId) { + this.networkId = networkId; + } + + @Override + public State getState() { + return state; + } + + public void setState(PublicIpv6AddressNetworkMap.State state) { + this.state = state; + } +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDaoImpl.java deleted file mode 100644 index 6fea25e3c1a0..000000000000 --- a/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDaoImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package com.cloud.network.dao; - -import java.util.List; - -import javax.annotation.PostConstruct; - -import org.apache.commons.collections.CollectionUtils; -import org.springframework.stereotype.Component; - -import com.cloud.network.Ip6GuestPrefixSubnetNetworkMap; -import com.cloud.network.Ip6GuestPrefixSubnetNetworkMapVO; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; - -@Component -@DB -public class Ip6GuestPrefixSubnetNetworkMapDaoImpl extends GenericDaoBase implements Ip6GuestPrefixSubnetNetworkMapDao { - - protected SearchBuilder FreeSubnetSearch; - protected SearchBuilder PrefixIdSearch; - - @PostConstruct - public void init() { - FreeSubnetSearch = createSearchBuilder(); - FreeSubnetSearch.and("prefixId", FreeSubnetSearch.entity().getPrefixId(), SearchCriteria.Op.EQ); - FreeSubnetSearch.and("state", FreeSubnetSearch.entity().getState(), SearchCriteria.Op.EQ); - FreeSubnetSearch.done(); - PrefixIdSearch = createSearchBuilder(); - PrefixIdSearch.and("prefixId", FreeSubnetSearch.entity().getPrefixId(), SearchCriteria.Op.EQ); - PrefixIdSearch.done(); - } - - @Override - public Ip6GuestPrefixSubnetNetworkMapVO findFirstAvailable(long prefixId) { - SearchCriteria sc = FreeSubnetSearch.create(); - sc.setParameters("prefixId", prefixId); - sc.setParameters("state", Ip6GuestPrefixSubnetNetworkMap.State.Free); - return findOneBy(sc); - } - - @Override - public Ip6GuestPrefixSubnetNetworkMapVO findLast(long prefixId) { - SearchCriteria sc = PrefixIdSearch.create(); - sc.setParameters("prefixId", prefixId); - List list = listBy(sc); - return CollectionUtils.isNotEmpty(list) ? list.get(list.size() - 1) : null; - } -} diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDao.java b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDao.java similarity index 55% rename from engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDao.java rename to engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDao.java index 17e0427b748a..9449a1b4e727 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/PodGuestIp6PrefixDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDao.java @@ -15,16 +15,19 @@ // specific language governing permissions and limitations // under the License. -package com.cloud.dc.dao; +package com.cloud.network.dao; import java.util.List; -import com.cloud.dc.PodGuestIp6PrefixVO; +import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMap; +import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMapVO; import com.cloud.utils.db.GenericDao; -public interface PodGuestIp6PrefixDao extends GenericDao { - - List listByPodId(long podId); - - List listByDataCenterId(long dcId); +public interface Ipv6GuestPrefixSubnetNetworkMapDao extends GenericDao { + Ipv6GuestPrefixSubnetNetworkMapVO findFirstAvailable(long prefixId); + Ipv6GuestPrefixSubnetNetworkMapVO findLast(long prefixId); + Ipv6GuestPrefixSubnetNetworkMapVO findByNetworkId(long networkId); + Ipv6GuestPrefixSubnetNetworkMapVO findBySubnet(String subnet); + List findPrefixesInStates(Ipv6GuestPrefixSubnetNetworkMap.State... states); + void deleteByPrefixId(long prefixId); } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java new file mode 100644 index 000000000000..74c8d84cd8cd --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java @@ -0,0 +1,107 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network.dao; + +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Component; + +import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMap; +import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMapVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@DB +public class Ipv6GuestPrefixSubnetNetworkMapDaoImpl extends GenericDaoBase implements Ipv6GuestPrefixSubnetNetworkMapDao { + + protected SearchBuilder FreeSubnetSearch; + protected SearchBuilder PrefixIdSearch; + protected SearchBuilder NetworkIdSearch; + protected SearchBuilder SubnetSearch; + protected SearchBuilder StatesSearch; + + @PostConstruct + public void init() { + FreeSubnetSearch = createSearchBuilder(); + FreeSubnetSearch.and("prefixId", FreeSubnetSearch.entity().getPrefixId(), SearchCriteria.Op.EQ); + FreeSubnetSearch.and("state", FreeSubnetSearch.entity().getState(), SearchCriteria.Op.EQ); + FreeSubnetSearch.done(); + PrefixIdSearch = createSearchBuilder(); + PrefixIdSearch.and("prefixId", PrefixIdSearch.entity().getPrefixId(), SearchCriteria.Op.EQ); + PrefixIdSearch.done(); + NetworkIdSearch = createSearchBuilder(); + NetworkIdSearch.and("networkId", NetworkIdSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); + NetworkIdSearch.done(); + SubnetSearch = createSearchBuilder(); + SubnetSearch.and("subnet", SubnetSearch.entity().getSubnet(), SearchCriteria.Op.EQ); + SubnetSearch.done(); + StatesSearch = createSearchBuilder(); + StatesSearch.and("state", StatesSearch.entity().getSubnet(), SearchCriteria.Op.IN); + StatesSearch.done(); + } + + @Override + public Ipv6GuestPrefixSubnetNetworkMapVO findFirstAvailable(long prefixId) { + SearchCriteria sc = FreeSubnetSearch.create(); + sc.setParameters("prefixId", prefixId); + sc.setParameters("state", Ipv6GuestPrefixSubnetNetworkMap.State.Free); + return findOneBy(sc); + } + + @Override + public Ipv6GuestPrefixSubnetNetworkMapVO findLast(long prefixId) { + SearchCriteria sc = PrefixIdSearch.create(); + sc.setParameters("prefixId", prefixId); + List list = listBy(sc); + return CollectionUtils.isNotEmpty(list) ? list.get(list.size() - 1) : null; + } + + @Override + public Ipv6GuestPrefixSubnetNetworkMapVO findByNetworkId(long networkId) { + SearchCriteria sc = NetworkIdSearch.create(); + sc.setParameters("networkId", networkId); + return findOneBy(sc); + } + + @Override + public Ipv6GuestPrefixSubnetNetworkMapVO findBySubnet(String subnet) { + SearchCriteria sc = SubnetSearch.create(); + sc.setParameters("subnet", subnet); + return findOneBy(sc); + } + + @Override + public List findPrefixesInStates(Ipv6GuestPrefixSubnetNetworkMap.State... states) { + SearchCriteria sc = StatesSearch.create(); + sc.setParameters("state", (Object[])states); + return listBy(sc); + } + + @Override + public void deleteByPrefixId(long prefixId) { + SearchCriteria sc = PrefixIdSearch.create(); + sc.setParameters("prefixId", prefixId); + remove(sc); + } +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDao.java b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java similarity index 71% rename from engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDao.java rename to engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java index 6c9b64442886..1d32026dd305 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Ip6GuestPrefixSubnetNetworkMapDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java @@ -17,10 +17,11 @@ package com.cloud.network.dao; -import com.cloud.network.Ip6GuestPrefixSubnetNetworkMapVO; +import com.cloud.network.PublicIpv6AddressNetworkMapVO; import com.cloud.utils.db.GenericDao; -public interface Ip6GuestPrefixSubnetNetworkMapDao extends GenericDao { - Ip6GuestPrefixSubnetNetworkMapVO findFirstAvailable(long prefixId); - Ip6GuestPrefixSubnetNetworkMapVO findLast(long prefixId); +public interface PublicIpv6AddressNetworkMapDao extends GenericDao { + PublicIpv6AddressNetworkMapVO findFirstAvailable(long rangeId); + PublicIpv6AddressNetworkMapVO findLast(long rangeId); + PublicIpv6AddressNetworkMapVO findByNetworkId(long networkId); } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java new file mode 100644 index 000000000000..485abc3a73b1 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java @@ -0,0 +1,78 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network.dao; + +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Component; + +import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMap; +import com.cloud.network.PublicIpv6AddressNetworkMapVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@DB +public class PublicIpv6AddressNetworkMapDaoImpl extends GenericDaoBase implements PublicIpv6AddressNetworkMapDao { + + protected SearchBuilder FreeAddressSearch; + protected SearchBuilder RangeIdSearch; + protected SearchBuilder NetworkIdSearch; + + @PostConstruct + public void init() { + FreeAddressSearch = createSearchBuilder(); + FreeAddressSearch.and("prefixId", FreeAddressSearch.entity().getRangeId(), SearchCriteria.Op.EQ); + FreeAddressSearch.and("state", FreeAddressSearch.entity().getState(), SearchCriteria.Op.EQ); + FreeAddressSearch.done(); + RangeIdSearch = createSearchBuilder(); + RangeIdSearch.and("prefixId", RangeIdSearch.entity().getRangeId(), SearchCriteria.Op.EQ); + RangeIdSearch.done(); + NetworkIdSearch = createSearchBuilder(); + NetworkIdSearch.and("networkId", NetworkIdSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); + NetworkIdSearch.done(); + } + + @Override + public PublicIpv6AddressNetworkMapVO findFirstAvailable(long prefixId) { + SearchCriteria sc = FreeAddressSearch.create(); + sc.setParameters("prefixId", prefixId); + sc.setParameters("state", Ipv6GuestPrefixSubnetNetworkMap.State.Free); + return findOneBy(sc); + } + + @Override + public PublicIpv6AddressNetworkMapVO findLast(long prefixId) { + SearchCriteria sc = RangeIdSearch.create(); + sc.setParameters("prefixId", prefixId); + List list = listBy(sc); + return CollectionUtils.isNotEmpty(list) ? list.get(list.size() - 1) : null; + } + + @Override + public PublicIpv6AddressNetworkMapVO findByNetworkId(long networkId) { + SearchCriteria sc = NetworkIdSearch.create(); + sc.setParameters("networkId", networkId); + return findOneBy(sc); + } +} \ No newline at end of file diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java index 52a547b48bdf..5a2660b92dcc 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java @@ -71,4 +71,6 @@ public interface NetworkOfferingDao extends GenericDao void persistDefaultL2NetworkOfferings(); boolean isIpv6Supported(Long offeringId); + + boolean isIpv6FirewallEnabled(Long offeringId); } diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java index 7d13b7b5d989..939157cbed75 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java @@ -280,4 +280,10 @@ public boolean isIpv6Supported(Long offeringId) { NetworkOffering.InternetProtocol internetProtocol = NetworkOffering.InternetProtocol.fromValue(internetProtocolStr); return ipv6EnabledProtocols.contains(internetProtocol); } + + @Override + public boolean isIpv6FirewallEnabled(Long offeringId) { + String ipv6FirewallStr = _detailsDao.getDetail(offeringId, NetworkOffering.Detail.ipv6Firewall); + return Boolean.parseBoolean(ipv6FirewallStr); + } } diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index c66f093d1336..7d358b4b74b4 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -108,7 +108,8 @@ - + + @@ -198,8 +199,7 @@ - - + diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql index 8a9716d6d6f0..adda9a57fbdb 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql @@ -23,7 +23,7 @@ ALTER TABLE cloud.remote_access_vpn MODIFY ipsec_psk text NOT NULL; -- For IPv6 guest prefixes. -CREATE TABLE `cloud`.`pod_ip6_guest_prefix` ( +CREATE TABLE `cloud`.`dc_ip6_guest_prefix` ( `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', `uuid` varchar(40) DEFAULT NULL, `data_center_id` bigint(20) unsigned NOT NULL COMMENT 'zone it belongs to', @@ -32,9 +32,9 @@ CREATE TABLE `cloud`.`pod_ip6_guest_prefix` ( `created` datetime default NULL, `removed` datetime default NULL, PRIMARY KEY (`id`), - CONSTRAINT `fk_pod_ip6_guest_prefix__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`), - CONSTRAINT `fk_pod_ip6_guest_prefix__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `host_pod_ref`(`id`), - CONSTRAINT `uc_pod_ip6_guest_prefix__uuid` UNIQUE (`uuid`) + CONSTRAINT `fk_dc_ip6_guest_prefix__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`), + CONSTRAINT `fk_dc_ip6_guest_prefix__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `host_pod_ref`(`id`), + CONSTRAINT `uc_dc_ip6_guest_prefix__uuid` UNIQUE (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `cloud`.`ip6_guest_prefix_subnet_network_map` ( @@ -44,11 +44,12 @@ CREATE TABLE `cloud`.`ip6_guest_prefix_subnet_network_map` ( `subnet` varchar(255) NOT NULL COMMENT 'subnet of the ipv6 network', `network_id` bigint(20) unsigned DEFAULT NULL COMMENT 'network to which subnet is associated to', `state` varchar(255) NOT NULL COMMENT 'state of the subnet network', + `updated` datetime default NULL, `created` datetime default NULL, `removed` datetime default NULL, PRIMARY KEY (`id`), - CONSTRAINT `fk_ip6_guest_prefix_subnet_network_map__prefix_id` FOREIGN KEY (`prefix_id`) REFERENCES `pod_ip6_guest_prefix`(`id`), - CONSTRAINT `fk_ip6_guest_prefix_subnet_network_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `network`(`id`), + CONSTRAINT `fk_ip6_guest_prefix_subnet_network_map__prefix_id` FOREIGN KEY (`prefix_id`) REFERENCES `dc_ip6_guest_prefix`(`id`), + CONSTRAINT `fk_ip6_guest_prefix_subnet_network_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), CONSTRAINT `uc_ip6_guest_prefix_subnet_network_map__uuid` UNIQUE (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -63,6 +64,6 @@ CREATE TABLE `cloud`.`public_ip6_address_network_map` ( `removed` datetime default NULL, PRIMARY KEY (`id`), CONSTRAINT `fk_public_ip6_address_network_map__prefix_id` FOREIGN KEY (`vlan_db_id`) REFERENCES `vlan`(`id`), - CONSTRAINT `fk_public_ip6_address_network_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `network`(`id`), + CONSTRAINT `fk_public_ip6_address_network_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), CONSTRAINT `uc_public_ip6_address_network_map__uuid` UNIQUE (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 32b443195f01..e35f6de32a97 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -26,6 +26,7 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -67,6 +68,7 @@ import org.apache.cloudstack.api.response.CounterResponse; import org.apache.cloudstack.api.response.CreateCmdResponse; import org.apache.cloudstack.api.response.CreateSSHKeyPairResponse; +import org.apache.cloudstack.api.response.DataCenterGuestIpv6PrefixResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.DomainRouterResponse; @@ -180,6 +182,7 @@ import org.apache.cloudstack.usage.UsageService; import org.apache.cloudstack.usage.UsageTypes; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import com.cloud.agent.api.VgpuTypesInfo; @@ -219,15 +222,15 @@ import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterGuestIpv6Prefix; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; -import com.cloud.dc.PodGuestIp6PrefixVO; import com.cloud.dc.StorageNetworkIpRange; import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; -import com.cloud.dc.dao.PodGuestIp6PrefixDao; +import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.event.Event; @@ -364,7 +367,8 @@ import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; -import org.apache.commons.lang3.StringUtils; +import com.googlecode.ipv6.IPv6Address; +import com.googlecode.ipv6.IPv6AddressRange; public class ApiResponseHelper implements ResponseGenerator { @@ -416,7 +420,7 @@ public class ApiResponseHelper implements ResponseGenerator { @Inject private UserStatisticsDao userStatsDao; @Inject - PodGuestIp6PrefixDao podGuestIp6PrefixDao; + DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao; @Override public UserResponse createUserResponse(User user) { @@ -777,8 +781,13 @@ public VlanIpRangeResponse createVlanIpRangeResponse(Class ips = ipv6Range.iterator(); + int idx = 0; + while (ips.hasNext() && idx < 10) { + IPv6Address ip = ips.next(); + s_logger.debug(String.format("IPv6Address::%d -- %s", idx, ip.toString())); + if (idx % 2 == 0) { + s_logger.debug(String.format("IPv6Address-added::%s -- %s", ip, ip.add(1))); + } + idx++; + } } if (vlan.getNetworkId() != null) { @@ -1126,18 +1149,6 @@ public PodResponse createPodResponse(Pod pod, Boolean showCapacities) { } } - List ip6Ranges = podManagementIp6RangeDao.listByPodId(pod.getId()); - List ip6RangesResponses = new ArrayList<>(); - for (PodManagementIp6RangeVO ip6Range : ip6Ranges) { - IpRangeResponse response = new IpRangeResponse(); - response.setGateway(ip6Range.getGateway()); - response.setCidr(ip6Range.getCidr()); - response.setVlanId(ip6Range.getVlan() != null ? BroadcastDomainType.Vlan.toUri(String.valueOf(ip6Range.getVlan())).toString() : BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED).toString()); - response.setStartIp(ip6Range.getStartIp()); - response.setEndIp(ip6Range.getEndIp()); - ip6RangesResponses.add(response); - } - PodResponse podResponse = new PodResponse(); podResponse.setId(pod.getUuid()); podResponse.setName(pod.getName()); @@ -1148,9 +1159,6 @@ public PodResponse createPodResponse(Pod pod, Boolean showCapacities) { } podResponse.setNetmask(NetUtils.getCidrNetmask(pod.getCidrSize())); podResponse.setIpRanges(ipRanges); - if (CollectionUtils.isNotEmpty(ip6Ranges)) { - podResponse.setIp6Ranges(ip6RangesResponses); - } podResponse.setStartIp(startIps); podResponse.setEndIp(endIps); podResponse.setForSystemVms(forSystemVms); @@ -1184,9 +1192,6 @@ public PodResponse createPodResponse(Pod pod, Boolean showCapacities) { podResponse.setCapacities(new ArrayList(capacityResponses)); } - List ip6Prefixes = podGuestIp6PrefixDao.listByPodId(pod.getId()); - podResponse.setPublicIp6Prefixes(ip6Prefixes.stream().map(PodGuestIp6PrefixVO::getPrefix).collect(Collectors.toList())); - podResponse.setHasAnnotation(annotationDao.hasAnnotations(pod.getUuid(), AnnotationService.EntityType.POD.name(), _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId()))); podResponse.setObjectName("pod"); @@ -1253,6 +1258,21 @@ private static List getStatsCapacityresponse(Long poolId, Long return capacityResponses; } + @Override + public DataCenterGuestIpv6PrefixResponse createDataCenterGuestIpv6PrefixResponse(DataCenterGuestIpv6Prefix prefix) { + DataCenterGuestIpv6PrefixResponse response = new DataCenterGuestIpv6PrefixResponse(); + response.setId(prefix.getUuid()); + response.setPrefix(prefix.getPrefix()); + DataCenter dc = ApiDBUtils.findZoneById(prefix.getDataCenterId()); + response.setZoneId(dc.getUuid()); + if (prefix.getPodId() != null) { + Pod pod = ApiDBUtils.findPodById(prefix.getPodId()); + response.setPod(pod.getUuid()); + } + response.setCreated(prefix.getCreated()); + return response; + } + @Override public VolumeResponse createVolumeResponse(ResponseView view, Volume volume) { List viewVrs = ApiDBUtils.newVolumeView(volume); diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 9a1e3181b19d..7cbdcb2e7c71 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -37,6 +37,7 @@ import java.util.Set; import java.util.UUID; import java.util.Vector; +import java.util.stream.Collectors; import javax.inject.Inject; import javax.naming.ConfigurationException; @@ -51,11 +52,13 @@ import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; -import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIp6PrefixCmd; +import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd; import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd; @@ -129,6 +132,8 @@ import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.DataCenterGuestIpv6Prefix; +import com.cloud.dc.DataCenterGuestIpv6PrefixVO; import com.cloud.dc.DataCenterIpAddressVO; import com.cloud.dc.DataCenterLinkLocalIpAddressVO; import com.cloud.dc.DataCenterVO; @@ -136,7 +141,6 @@ import com.cloud.dc.DomainVlanMapVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; -import com.cloud.dc.PodGuestIp6PrefixVO; import com.cloud.dc.PodVlanMapVO; import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; @@ -145,12 +149,12 @@ import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterDetailsDao; +import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao; import com.cloud.dc.dao.DataCenterIpAddressDao; import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDao; import com.cloud.dc.dao.DedicatedResourceDao; import com.cloud.dc.dao.DomainVlanMapDao; import com.cloud.dc.dao.HostPodDao; -import com.cloud.dc.dao.PodGuestIp6PrefixDao; import com.cloud.dc.dao.PodVlanMapDao; import com.cloud.dc.dao.VlanDao; import com.cloud.dc.dao.VsphereStoragePolicyDao; @@ -175,6 +179,8 @@ import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostTagsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMap; +import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMapVO; import com.cloud.network.IpAddress; import com.cloud.network.IpAddressManager; import com.cloud.network.Network; @@ -191,6 +197,7 @@ import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkDao; @@ -416,7 +423,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Inject UserIpv6AddressDao _ipv6Dao; @Inject - PodGuestIp6PrefixDao podGuestIp6PrefixDao; + DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao; + @Inject + Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao; // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? @Inject @@ -1440,16 +1449,16 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } private Pod createPodIp6Range(HostPodVO pod, String gateway, String cidr, String startIp, String endIp, String vlan) { - Integer vlanId = null; - if (vlan != null && !vlan.equalsIgnoreCase("untagged")) { - try { - vlanId = Integer.valueOf(vlan); - } catch (NumberFormatException nfe) { - throw new InvalidParameterValueException("The VLAN is invalid"); - } - } - PodManagementIp6RangeVO ip6RangeVO = new PodManagementIp6RangeVO(pod.getDataCenterId(), pod.getId(), gateway, cidr, vlanId, startIp, endIp); - podManagementIp6RangeDao.persist(ip6RangeVO); +// Integer vlanId = null; +// if (vlan != null && !vlan.equalsIgnoreCase("untagged")) { +// try { +// vlanId = Integer.valueOf(vlan); +// } catch (NumberFormatException nfe) { +// throw new InvalidParameterValueException("The VLAN is invalid"); +// } +// } +// PodManagementIp6RangeVO ip6RangeVO = new PodManagementIp6RangeVO(pod.getDataCenterId(), pod.getId(), gateway, cidr, vlanId, startIp, endIp); +// podManagementIp6RangeDao.persist(ip6RangeVO); return pod; } @@ -1740,30 +1749,63 @@ private void checkIpRangeContainsTakenAddresses(final HostPodVO pod,final String @Override @DB - public Pod createPodGuestIp6Prefix(final CreateGuestNetworkIp6PrefixCmd cmd) throws ConcurrentOperationException { - final long podId = cmd.getPodId(); - final HostPodVO pod = _podDao.findById(podId); - if (pod == null) { - throw new InvalidParameterValueException("Unable to find pod by id: " + podId); + public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(final CreateGuestNetworkIpv6PrefixCmd cmd) throws ConcurrentOperationException { + final long zoneId = cmd.getZoneId(); + final DataCenterVO zone = _zoneDao.findById(zoneId); + if (zone == null) { + throw new InvalidParameterValueException("Unable to find zone by id: " + zoneId); + } + final Long podId = cmd.getPodId(); + if (podId != null) { + final HostPodVO pod = _podDao.findById(podId); + if (pod == null) { + throw new InvalidParameterValueException("Unable to find pod by id: " + podId); + } } - final String prefix = cmd.getPrefix(); - + DataCenterGuestIpv6Prefix dataCenterGuestIpv6Prefix = null; try { - - Transaction.execute(new TransactionCallbackNoReturn() { + dataCenterGuestIpv6Prefix = Transaction.execute(new TransactionCallback() { @Override - public void doInTransactionWithoutResult(final TransactionStatus status) { - final long zoneId = pod.getDataCenterId(); - PodGuestIp6PrefixVO podGuestIp6PrefixVO = new PodGuestIp6PrefixVO(zoneId, podId, prefix); - podGuestIp6PrefixDao.persist(podGuestIp6PrefixVO); + public DataCenterGuestIpv6Prefix doInTransaction(TransactionStatus status) { + DataCenterGuestIpv6PrefixVO dataCenterGuestIpv6PrefixVO = new DataCenterGuestIpv6PrefixVO(zoneId, podId, prefix); + dataCenterGuestIpv6PrefixDao.persist(dataCenterGuestIpv6PrefixVO); + return dataCenterGuestIpv6PrefixVO; } }); } catch (final Exception e) { - s_logger.error("Unable to update Pod " + podId + " IP range due to " + e.getMessage(), e); - throw new CloudRuntimeException("Failed to update Pod " + podId + " IP range. Please contact Cloud Support."); + s_logger.error(String.format("Unable to add IPv6 prefix for zone: %s due to %s", zone, e.getMessage()), e); + throw new CloudRuntimeException(String.format("Unable to add IPv6 prefix for zone ID: %s. Please contact Cloud Support.", zone.getUuid())); } - return pod; + return dataCenterGuestIpv6Prefix; + } + + @Override + public List listDataCenterGuestIpv6Prefixes(final ListGuestNetworkIpv6PrefixesCmd cmd) throws ConcurrentOperationException { + final long zoneId = cmd.getZoneId(); + final DataCenterVO zone = _zoneDao.findById(zoneId); + if (zone == null) { + throw new InvalidParameterValueException("Unable to find zone by id: " + zoneId); + } + return dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); + } + + @Override + public boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6RangeCmd cmd) { + final long prefixId = cmd.getId(); + final DataCenterGuestIpv6PrefixVO prefix = dataCenterGuestIpv6PrefixDao.findById(prefixId); + if (prefix == null) { + throw new InvalidParameterValueException("Unable to find guest network IPv6 prefix by id: " + prefixId); + } + List prefixSubnets = ipv6GuestPrefixSubnetNetworkMapDao.findPrefixesInStates(Ipv6GuestPrefixSubnetNetworkMap.State.Allocated, Ipv6GuestPrefixSubnetNetworkMap.State.Allocating); + if (CollectionUtils.isNotEmpty(prefixSubnets)) { + List usedSubnets = prefixSubnets.stream().map(Ipv6GuestPrefixSubnetNetworkMapVO::getSubnet).collect(Collectors.toList()); + s_logger.error(String.format("Subnets for guest IPv6 prefix {ID: %s, %s} are in use: %s", prefix.getUuid(), prefix.getPrefix(), String.join(", ", usedSubnets))); + throw new CloudRuntimeException("Unable to delete guest network IPv6 prefix ID: %s. Prefix subnets are in use."); + } + ipv6GuestPrefixSubnetNetworkMapDao.deleteByPrefixId(prefixId); + dataCenterGuestIpv6PrefixDao.remove(prefixId); + return true; } @Override diff --git a/server/src/main/java/com/cloud/network/Ipv6Service.java b/server/src/main/java/com/cloud/network/Ipv6Service.java new file mode 100644 index 000000000000..dea63afd0e73 --- /dev/null +++ b/server/src/main/java/com/cloud/network/Ipv6Service.java @@ -0,0 +1,57 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network; + +import org.apache.cloudstack.framework.config.Configurable; + +import com.cloud.dc.DataCenter; +import com.cloud.dc.VlanVO; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.utils.Pair; +import com.cloud.vm.NicProfile; + +public interface Ipv6Service extends Configurable { + + public static final String IPV6_CIDR_SUFFIX = "/64"; + + public static final String RouterSlaacIpv6Prefix = "SLAAC-"; + + Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws ResourceAllocationException; + + void assignIpv6SubnetToNetwork(String subnet, long networkId); + + void releaseIpv6SubnetForNetwork(long networkId); + + Pair assignPublicIpv6ToNetwork(Network network); + + void updateNicIpv6(NicProfile nic, DataCenter dc, Network network); + + void releasePublicIpv6ForNetwork(long networkId); + +// FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd); +// +// Pair,Integer> listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd); +// +// boolean revokeIpv6FirewallRule(Long id); +// +// FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd createIpv6FirewallRuleCmd); +// +// FirewallRule getIpv6FirewallRule(Long entityId); +// +// boolean applyIpv6FirewallRule(long id); +} \ No newline at end of file diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java new file mode 100644 index 000000000000..388912617a10 --- /dev/null +++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java @@ -0,0 +1,314 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network; + +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.commons.collections.CollectionUtils; +import org.apache.log4j.Logger; + +import com.cloud.configuration.Resource; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterGuestIpv6PrefixVO; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; +import com.cloud.network.dao.PublicIpv6AddressNetworkMapDao; +import com.cloud.network.firewall.FirewallService; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ComponentLifecycleBase; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.googlecode.ipv6.IPv6Address; +import com.googlecode.ipv6.IPv6AddressRange; +import com.googlecode.ipv6.IPv6Network; +import com.googlecode.ipv6.IPv6NetworkMask; + +public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Service { + + public static final Logger s_logger = Logger.getLogger(Ipv6ServiceImpl.class.getName()); + + ScheduledExecutorService _ipv6GuestPrefixSubnetNetworkMapStateScanner; + + @Inject + NetworkOfferingDao networkOfferingDao; + @Inject + VlanDao vlanDao; + @Inject + DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao; + @Inject + Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao; + @Inject + PublicIpv6AddressNetworkMapDao publicIpv6AddressNetworkMapDao; + @Inject + FirewallRulesDao firewallRulesDao; + @Inject + FirewallService firewallservice; + + + @Override + public boolean start() { + _ipv6GuestPrefixSubnetNetworkMapStateScanner.scheduleWithFixedDelay(new Ipv6GuestPrefixSubnetNetworkMapStateScanner(), 300, 30*60, TimeUnit.SECONDS); + return true; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _name = name; + _configParams = params; + _ipv6GuestPrefixSubnetNetworkMapStateScanner = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Kubernetes-Cluster-State-Scanner")); + + return true; + } + + private IPv6AddressRange getIpv6AddressRangeFromIpv6Vlan(VlanVO vlanVO) { + String[] rangeArr = vlanVO.getIp6Range().split("-"); + String firstStr = rangeArr[0].trim(); + String lastStr = rangeArr[1].trim(); + IPv6AddressRange range = null; + try { + IPv6Address first = IPv6Address.fromString(firstStr); + IPv6Address last = IPv6Address.fromString(lastStr); + range = IPv6AddressRange.fromFirstAndLast(first, last); + } catch (IllegalArgumentException ex) { + s_logger.warn(String.format("Unable to retrieve IPv6 address range for vlan ID: %d, range: %s", vlanVO.getId(), vlanVO.getIp6Range()), ex); + } + return range; + } + + protected void releaseIpv6Subnet(long subnetId) { + Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO = ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(subnetId); + ipv6GuestPrefixSubnetNetworkMapVO.setState(Ipv6GuestPrefixSubnetNetworkMap.State.Free); + ipv6GuestPrefixSubnetNetworkMapVO.setNetworkId(null); + ipv6GuestPrefixSubnetNetworkMapVO.setUpdated(new Date()); + ipv6GuestPrefixSubnetNetworkMapDao.update(ipv6GuestPrefixSubnetNetworkMapVO.getId(), ipv6GuestPrefixSubnetNetworkMapVO); + } + + @Override + public String getConfigComponentName() { + return Ipv6Service.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] {}; + } + + public Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws ResourceAllocationException { + List prefixes = dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); + if (CollectionUtils.isEmpty(prefixes)) { + s_logger.error(String.format("IPv6 prefixes not found for the zone ID: %d", zoneId)); + throw new ResourceAllocationException("Unable to allocate IPv6 network", Resource.ResourceType.network); + } + Ipv6GuestPrefixSubnetNetworkMapVO ip6Subnet = null; + for (DataCenterGuestIpv6PrefixVO prefix : prefixes) { + ip6Subnet = ipv6GuestPrefixSubnetNetworkMapDao.findFirstAvailable(prefix.getId()); + if (ip6Subnet == null) { + Ipv6GuestPrefixSubnetNetworkMapVO last = ipv6GuestPrefixSubnetNetworkMapDao.findLast(prefix.getId()); + String lastUsedSubnet = last != null ? last.getSubnet() : null; + final IPv6Network ip6Prefix = IPv6Network.fromString(prefix.getPrefix()); + Iterator splits = ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(64)); + if (splits.hasNext()) { + splits.next(); + } + while (splits.hasNext()) { + IPv6Network i = splits.next(); + if (lastUsedSubnet == null) { + ip6Subnet = new Ipv6GuestPrefixSubnetNetworkMapVO(prefix.getId(), i.toString(), null, Ipv6GuestPrefixSubnetNetworkMap.State.Allocating); + break; + } + if (i.toString().equals(lastUsedSubnet)) { + lastUsedSubnet = null; + } + } + } + if (ip6Subnet != null) { + break; + } + } + if (ip6Subnet == null) { + throw new ResourceAllocationException("Unable to allocate IPv6 guest subnet for the network", Resource.ResourceType.network); + } + ip6Subnet.setUpdated(new Date()); + if (Ipv6GuestPrefixSubnetNetworkMap.State.Free.equals(ip6Subnet.getState())) { + ip6Subnet.setState(Ipv6GuestPrefixSubnetNetworkMap.State.Allocating); + ipv6GuestPrefixSubnetNetworkMapDao.update(ip6Subnet.getId(), ip6Subnet); + } else { + ipv6GuestPrefixSubnetNetworkMapDao.persist(ip6Subnet); + } + IPv6Network network = IPv6Network.fromString(ip6Subnet.getSubnet()); + return new Pair<>(network.getFirst().toString(), network.toString()); + } + + @Override + public void assignIpv6SubnetToNetwork(String subnet, long networkId) { + Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO = ipv6GuestPrefixSubnetNetworkMapDao.findBySubnet(subnet); + if (ipv6GuestPrefixSubnetNetworkMapVO != null) { + ipv6GuestPrefixSubnetNetworkMapVO = ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(ipv6GuestPrefixSubnetNetworkMapVO.getId()); + ipv6GuestPrefixSubnetNetworkMapVO.setState(Ipv6GuestPrefixSubnetNetworkMap.State.Allocated); + ipv6GuestPrefixSubnetNetworkMapVO.setNetworkId(networkId); + ipv6GuestPrefixSubnetNetworkMapVO.setUpdated(new Date()); + ipv6GuestPrefixSubnetNetworkMapDao.update(ipv6GuestPrefixSubnetNetworkMapVO.getId(), ipv6GuestPrefixSubnetNetworkMapVO); + } + } + + @Override + public void releaseIpv6SubnetForNetwork(long networkId) { + Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO = ipv6GuestPrefixSubnetNetworkMapDao.findByNetworkId(networkId); + if (ipv6GuestPrefixSubnetNetworkMapVO != null) { + releaseIpv6Subnet(ipv6GuestPrefixSubnetNetworkMapVO.getId()); + } + } + + @Override + public Pair assignPublicIpv6ToNetwork(Network network) { + PublicIpv6AddressNetworkMapVO ip6NetworkMap = null; + VlanVO selectedVlan = null; + final List ranges = vlanDao.listVlansWithIpV6RangeByPhysicalNetworkId(network.getPhysicalNetworkId()); + if (ranges == null) { + s_logger.error(String.format("Unable to find IPv6 range for the zone ID: %d", network.getDataCenterId())); + throw new CloudRuntimeException(String.format("Cannot find IPv6 range for network %s", network.getName())); + } + for (VlanVO range : ranges) { + ip6NetworkMap = publicIpv6AddressNetworkMapDao.findFirstAvailable(range.getId()); + if (ip6NetworkMap == null) { + PublicIpv6AddressNetworkMapVO last = publicIpv6AddressNetworkMapDao.findLast(range.getId()); + String lastUsedIp6Address = last != null ? last.getIp6Address() : null; + final IPv6AddressRange ip6Range = getIpv6AddressRangeFromIpv6Vlan(range); + IPv6Address ip = null; + if (ip6Range != null) { + if (lastUsedIp6Address == null) { + ip = ip6Range.getFirst(); + } else { + IPv6Address lastAddress = IPv6Address.fromString(lastUsedIp6Address); + lastAddress = lastAddress.add(1); + if (ip6Range.contains(lastAddress)) { + ip = lastAddress; + } + } + if (ip != null) { + selectedVlan = range; + ip6NetworkMap = new PublicIpv6AddressNetworkMapVO(range.getId(), ip.toString(), network.getId(), PublicIpv6AddressNetworkMap.State.Allocated); + break; + } + } + } + } + if (ip6NetworkMap == null) { + s_logger.error(String.format("Unable to find an IPv6 address available for allocation for network %s in zone ID: %d", network.getName(), network.getDataCenterId())); + throw new CloudRuntimeException(String.format("Cannot find available IPv6 address for network %s", network.getName())); + } + if (PublicIpv6AddressNetworkMap.State.Free.equals(ip6NetworkMap.getState())) { + ip6NetworkMap.setState(PublicIpv6AddressNetworkMap.State.Allocated); + publicIpv6AddressNetworkMapDao.update(ip6NetworkMap.getId(), ip6NetworkMap); + } else { + publicIpv6AddressNetworkMapDao.persist(ip6NetworkMap); + } + return new Pair<>(ip6NetworkMap, selectedVlan); + } + + @Override + public void updateNicIpv6(NicProfile nic, DataCenter dc, Network network) { + boolean isIpv6Supported = networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()); + if (nic.getIPv6Address() == null && isIpv6Supported) { + Pair publicIpv6AddressNetworkMapVlanPair = assignPublicIpv6ToNetwork(network); + final PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMapVO = publicIpv6AddressNetworkMapVlanPair.first(); + final VlanVO vlan = publicIpv6AddressNetworkMapVlanPair.second(); + final String routerIpv6 = publicIpv6AddressNetworkMapVO.getIp6Address(); + final String routerIpv6Gateway = vlan.getIp6Gateway(); + final String routerIpv6Cidr = vlan.getIp6Cidr(); + nic.setIPv6Address(routerIpv6); + nic.setIPv6Gateway(routerIpv6Gateway); + nic.setIPv6Cidr(routerIpv6Cidr); + if (nic.getIPv4Address() != null) { + nic.setFormat(Networks.AddressFormat.DualStack); + } else { + nic.setFormat(Networks.AddressFormat.Ip6); + } + nic.setIPv6Dns1(dc.getIp6Dns1()); + nic.setIPv6Dns2(dc.getIp6Dns2()); + } + } + + @Override + public void releasePublicIpv6ForNetwork(long networkId) { + PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMapVO = publicIpv6AddressNetworkMapDao.findByNetworkId(networkId); + if (publicIpv6AddressNetworkMapVO != null) { + publicIpv6AddressNetworkMapVO = publicIpv6AddressNetworkMapDao.createForUpdate(publicIpv6AddressNetworkMapVO.getId()); + publicIpv6AddressNetworkMapVO.setState(PublicIpv6AddressNetworkMap.State.Free); + publicIpv6AddressNetworkMapVO.setNetworkId(null); + publicIpv6AddressNetworkMapDao.update(publicIpv6AddressNetworkMapVO.getId(), publicIpv6AddressNetworkMapVO); + } + } + + public class Ipv6GuestPrefixSubnetNetworkMapStateScanner extends ManagedContextRunnable { + @Override + protected void runInContext() { + GlobalLock gcLock = GlobalLock.getInternLock("Ipv6GuestPrefixSubnetNetworkMap.State.Scanner.Lock"); + try { + if (gcLock.lock(3)) { + try { + reallyRun(); + } finally { + gcLock.unlock(); + } + } + } finally { + gcLock.releaseRef(); + } + } + + public void reallyRun() { + try { + List subnets = ipv6GuestPrefixSubnetNetworkMapDao.findPrefixesInStates(Ipv6GuestPrefixSubnetNetworkMap.State.Allocating); + for (Ipv6GuestPrefixSubnetNetworkMapVO subnet : subnets) { + if (s_logger.isInfoEnabled()) { + s_logger.info(String.format("Running state scanned on Ipv6GuestPrefixSubnetNetworkMap : %s", subnet.getSubnet())); + } + try { + if ((new Date()).getTime() - subnet.getUpdated().getTime() < 30*60*1000) { + continue; + } + releaseIpv6Subnet(subnet.getId()); + } catch (CloudRuntimeException e) { + s_logger.warn(String.format("Failed to release IPv6 guest prefix subnet : %s during state scan", subnet.getSubnet()), e); + } + } + } catch (Exception e) { + s_logger.warn("Caught exception while running Ipv6GuestPrefixSubnetNetworkMap state scanner: ", e); + } + } + } +} diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index 8e1c8a92c3b5..4741873af98f 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -30,7 +30,6 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -62,7 +61,6 @@ import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; @@ -74,12 +72,10 @@ import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenterVnetVO; -import com.cloud.dc.PodGuestIp6PrefixVO; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterVnetDao; -import com.cloud.dc.dao.PodGuestIp6PrefixDao; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DeployDestination; import com.cloud.domain.Domain; @@ -116,7 +112,7 @@ import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; -import com.cloud.network.dao.Ip6GuestPrefixSubnetNetworkMapDao; +import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.NetworkAccountDao; import com.cloud.network.dao.NetworkDao; @@ -211,8 +207,7 @@ import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; -import com.googlecode.ipv6.IPv6Network; -import com.googlecode.ipv6.IPv6NetworkMask; +import com.googlecode.ipv6.IPv6Address; /** * NetworkServiceImpl implements NetworkService. @@ -340,9 +335,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C @Inject VirtualMachineManager vmManager; @Inject - PodGuestIp6PrefixDao podGuestIp6PrefixDao; + Ipv6Service ipv6Service; @Inject - Ip6GuestPrefixSubnetNetworkMapDao ip6GuestPrefixSubnetNetworkMapDao; + Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao; int _cidrLimit; boolean _allowSubdomainNetworkAccess; @@ -1349,11 +1344,11 @@ public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapac } validateRouterIps(routerIp, routerIpv6, startIP, endIP, gateway, netmask, startIPv6, endIPv6, ip6Cidr); - + Pair ip6GatewayCidr = null; if (zone.getNetworkType() == NetworkType.Advanced && ntwkOff.getGuestType() == GuestType.Isolated) { ipv6 = _networkOfferingDao.isIpv6Supported(ntwkOff.getId()); if (ipv6) { - Pair ip6GatewayCidr = getIp6GatewayCidr(ntwkOff.getId(), zoneId, owner.getId()); + ip6GatewayCidr = ipv6Service.preAllocateIpv6SubnetForNetwork(zone.getId()); ip6Gateway = ip6GatewayCidr.first(); ip6Cidr = ip6GatewayCidr.second(); } @@ -1433,7 +1428,7 @@ public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapac if (!createVlan) { // Only support advance shared network in IPv6, which means createVlan is a must - if (ipv6) { + if (ipv6 && ntwkOff.getGuestType() != GuestType.Isolated) { createVlan = true; } } @@ -1451,6 +1446,10 @@ public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapac _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.hideIpAddressUsage, String.valueOf(hideIpAddressUsage), false)); } + if (ip6GatewayCidr != null) { + ipv6Service.assignIpv6SubnetToNetwork(ip6Cidr, network.getId()); + } + // if the network offering has persistent set to true, implement the network if (ntwkOff.isPersistent()) { try { @@ -1474,31 +1473,6 @@ public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapac return network; } - private Pair getIp6GatewayCidr(Long networkOfferingId, Long zoneId, Long accountId) { - String ip6Gateway = null; - String ip6Cidr = null; - if (!areServicesSupportedByNetworkOffering(networkOfferingId, Service.SourceNat)) { - throw new InvalidParameterValueException("Can only take IPv6 address with isolated networks if SourceNat is supported"); - } - String routerIpv6Gateway = Ipv6Service.routerIpv6Gateway.valueIn(accountId); - if (org.apache.commons.lang3.StringUtils.isEmpty(routerIpv6Gateway)) { - Ipv6Address ipv6Address = _ipv6Service.takeIpv6Range(zoneId, false); - if (ipv6Address == null) { - throw new InvalidParameterValueException("cannot take an IPv6 range without router ipv6 address for this network"); - } - ip6Gateway = ipv6Address.getIp6Gateway(); - ip6Cidr = ipv6Address.getIp6Cidr(); - } else { - Ipv6Address ipv6Address = _ipv6Service.takeIpv6Range(zoneId, true); - if (ipv6Address == null) { - throw new InvalidParameterValueException("cannot take an IPv6 range with router ipv6 address for this network"); - } - ip6Gateway = ipv6Address.getIp6Gateway(); - ip6Cidr = ipv6Address.getIp6Cidr(); - } - return new Pair(ip6Gateway, ip6Cidr); - } - /** * Retrieve information (if set) for private VLAN when creating the network */ @@ -1591,7 +1565,7 @@ public Network doInTransaction(TransactionStatus status) throws InsufficientCapa } } network = _vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, - subdomainAccess, vpcId, aclId, caller, displayNetwork, externalId); + subdomainAccess, vpcId, aclId, caller, displayNetwork, externalId, ip6Gateway, ip6Cidr); } else { if (_configMgr.isOfferingForVpc(ntwkOff)) { throw new InvalidParameterValueException("Network offering can be used for VPC networks only"); @@ -2666,10 +2640,10 @@ public void doInTransactionWithoutResult(TransactionStatus status) { } private void updateNetworkIpv6(NetworkVO network, Long networkOfferingId) { - boolean isIpv6Supported = _ipv6Service.isIpv6Supported(network.getNetworkOfferingId()); - boolean isIpv6SupportedNew = _ipv6Service.isIpv6Supported(networkOfferingId); + boolean isIpv6Supported = _networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()); + boolean isIpv6SupportedNew = _networkOfferingDao.isIpv6Supported(networkOfferingId); if (isIpv6Supported && ! isIpv6SupportedNew) { - _ipv6AddressDao.unmark(network.getId(), network.getDomainId(), network.getAccountId()); +// _ipv6AddressDao.unmark(network.getId(), network.getDomainId(), network.getAccountId()); network.setIp6Gateway(null); network.setIp6Cidr(null); List nics = _nicDao.listByNetworkId(network.getId()); @@ -2680,17 +2654,22 @@ private void updateNetworkIpv6(NetworkVO network, Long networkOfferingId) { _nicDao.update(nic.getId(), nic); } } else if (!isIpv6Supported && isIpv6SupportedNew) { - Pair ip6GatewayCidr = getIp6GatewayCidr(networkOfferingId, network.getDataCenterId(), network.getAccountId()); + Pair ip6GatewayCidr; + try { + ip6GatewayCidr = ipv6Service.preAllocateIpv6SubnetForNetwork(network.getDataCenterId()); + ipv6Service.assignIpv6SubnetToNetwork(ip6GatewayCidr.second(), network.getId()); + } catch (ResourceAllocationException ex) { + throw new CloudRuntimeException(String.format("Failed to update network: %s", network.getName()), ex); + } String ip6Gateway = ip6GatewayCidr.first(); String ip6Cidr = ip6GatewayCidr.second(); - _ipv6AddressDao.mark(network.getDataCenterId(), ip6Gateway, ip6Cidr, network.getId(), network.getDomainId(), network.getAccountId()); network.setIp6Gateway(ip6Gateway); network.setIp6Cidr(ip6Cidr); - final String ip6Prefix = ip6Gateway.split("::")[0]; + Ipv6GuestPrefixSubnetNetworkMapVO map = ipv6GuestPrefixSubnetNetworkMapDao.findByNetworkId(network.getId()); List nics = _nicDao.listByNetworkId(network.getId()); for (NicVO nic : nics) { - IPv6Address ipv6addr = NetUtils.EUI64Address(ip6Prefix + Ipv6Service.IPV6_CIDR_SUFFIX, nic.getMacAddress()); - nic.setIPv6Address(ipv6addr.toString()); + IPv6Address iPv6Address = NetUtils.EUI64Address(map.getSubnet(), nic.getMacAddress()); + nic.setIPv6Address(iPv6Address.toString()); nic.setIPv6Cidr(ip6Cidr); nic.setIPv6Gateway(ip6Gateway); _nicDao.update(nic.getId(), nic); @@ -4820,47 +4799,4 @@ public String getConfigComponentName() { public ConfigKey[] getConfigKeys() { return new ConfigKey[] {AllowDuplicateNetworkName, AllowEmptyStartEndIpAddress}; } - - - private Pair getGuestNetworkIp6GatewayAndCidr(long physicalNetworkId) throws ResourceAllocationException { - List vlans = _vlanDao.listVlansWithIpV6RangeByPhysicalNetworkId(physicalNetworkId); - if (CollectionUtils.isEmpty(vlans)) { - throw new ResourceAllocationException("Unable to allocate IPv6 vlan network", Resource.ResourceType.network); - } - for (VlanVO vlan : vlans) { - vlan. - } - List prefixes = podGuestIp6PrefixDao.listByPodId(1); - if (CollectionUtils.isEmpty(prefixes)) { - throw new ResourceAllocationException("Unable to allocate IPv6 network", Resource.ResourceType.network); - } - Ip6GuestPrefixSubnetNetworkMapVO ip6Subnet = null; - for (PodGuestIp6PrefixVO prefix : prefixes) { - ip6Subnet = ip6GuestPrefixSubnetNetworkMapDao.findFirstAvailable(prefix.getId()); - if (ip6Subnet == null) { - Ip6GuestPrefixSubnetNetworkMapVO last = ip6GuestPrefixSubnetNetworkMapDao.findLast(prefix.getId()); - String lastUsedSubnet = last != null ? last.getSubnet() : null; - final IPv6Network ip6Prefix = IPv6Network.fromString(prefix.getPrefix()); - Iterator splits = ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(64)); - while (splits.hasNext()) { - IPv6Network i = splits.next(); - if (lastUsedSubnet == null) { - ip6Subnet = new Ip6GuestPrefixSubnetNetworkMapVO(prefix.getId(), i.toString(), null, Ip6GuestPrefixSubnetNetworkMap.State.Allocated); - break; - } - if (i.toString().equals(lastUsedSubnet)) { - lastUsedSubnet = null; - } - } - } - if (ip6Subnet != null) { - break; - } - } - if (ip6Subnet == null) { - throw new ResourceAllocationException("Unable to allocate IPv6 guest subnet for the network", Resource.ResourceType.network); - } - return new Pair<>(vlanip6Subnet.getSubnet()); - } - } diff --git a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java index 5da0952b0d14..211bcbaa24ba 100644 --- a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -17,6 +17,14 @@ package com.cloud.network.guru; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.log4j.Logger; + import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.dao.DataCenterDao; @@ -27,6 +35,7 @@ import com.cloud.event.EventVO; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.IpAddressManager; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; @@ -60,12 +69,6 @@ import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; -import org.apache.log4j.Logger; - -import javax.inject.Inject; -import java.util.List; public class ExternalGuestNetworkGuru extends GuestNetworkGuru { private static final Logger s_logger = Logger.getLogger(ExternalGuestNetworkGuru.class); @@ -119,6 +122,20 @@ public Network design(NetworkOffering offering, DeploymentPlan plan, Network use /* In order to revert userSpecified network setup */ config.setState(State.Allocated); } + if (userSpecified == null) { + return config; + } + if ((userSpecified.getIp6Cidr() == null && userSpecified.getIp6Gateway() != null) || + (userSpecified.getIp6Cidr() != null && userSpecified.getIp6Gateway() == null)) { + throw new InvalidParameterValueException("ip6gateway and ip6cidr must be specified together."); + } + if (userSpecified.getIp6Cidr() != null) { + config.setIp6Cidr(userSpecified.getIp6Cidr()); + config.setIp6Gateway(userSpecified.getIp6Gateway()); + } + if (userSpecified.getRouterIpv6() != null) { + config.setRouterIpv6(userSpecified.getRouterIpv6()); + } return config; } diff --git a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java index c1ce99c0606e..1853511cb45d 100644 --- a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java @@ -22,7 +22,6 @@ import javax.inject.Inject; -import com.cloud.network.Network.GuestType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.ConfigKey; @@ -44,12 +43,15 @@ import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.IpAddressManager; +import com.cloud.network.Ipv6AddressManager; import com.cloud.network.Network; +import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Network.State; import com.cloud.network.NetworkModel; import com.cloud.network.NetworkProfile; +import com.cloud.network.Networks; import com.cloud.network.Networks.AddressFormat; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; @@ -65,6 +67,7 @@ import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.server.ConfigurationServer; import com.cloud.user.Account; import com.cloud.utils.Pair; @@ -110,6 +113,10 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur ConfigurationServer _configServer; @Inject IpAddressManager _ipAddrMgr; + @Inject + NetworkOfferingDao networkOfferingDao; + @Inject + Ipv6AddressManager ipv6AddressManager; Random _rand = new Random(System.currentTimeMillis()); static final ConfigKey UseSystemGuestVlans = @@ -348,6 +355,23 @@ public NicProfile allocate(final Network network, NicProfile nic, final VirtualM final DataCenter dc = _dcDao.findById(network.getDataCenterId()); + boolean isIpv6Supported = networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()); + boolean isGateway = false; + //if Vm is router vm and source nat is enabled in the network, set ip4 to the network gateway + if (vm.getVirtualMachine().getType() == VirtualMachine.Type.DomainRouter) { + if (network.getVpcId() != null) { + final Vpc vpc = _vpcDao.findById(network.getVpcId()); + // Redundant Networks need a guest IP that is not the same as the gateway IP. + if (_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.SourceNat, Provider.VPCVirtualRouter) && !vpc.isRedundant()) { + isGateway = true; + } + } else { + if (_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.SourceNat, Provider.VirtualRouter)) { + isGateway = true; + } + } + } + if (nic.getIPv4Address() == null) { nic.setBroadcastUri(network.getBroadcastUri()); nic.setIsolationUri(network.getBroadcastUri()); @@ -357,22 +381,6 @@ public NicProfile allocate(final Network network, NicProfile nic, final VirtualM if (network.getSpecifyIpRanges()) { _ipAddrMgr.allocateDirectIp(nic, dc, vm, network, nic.getRequestedIPv4(), null); } else { - //if Vm is router vm and source nat is enabled in the network, set ip4 to the network gateway - boolean isGateway = false; - if (vm.getVirtualMachine().getType() == VirtualMachine.Type.DomainRouter) { - if (network.getVpcId() != null) { - final Vpc vpc = _vpcDao.findById(network.getVpcId()); - // Redundant Networks need a guest IP that is not the same as the gateway IP. - if (_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.SourceNat, Provider.VPCVirtualRouter) && !vpc.isRedundant()) { - isGateway = true; - } - } else { - if (_networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.SourceNat, Provider.VirtualRouter)) { - isGateway = true; - } - } - } - if (isGateway) { guestIp = network.getGateway(); } else { @@ -415,7 +423,19 @@ public NicProfile allocate(final Network network, NicProfile nic, final VirtualM throw new InsufficientAddressCapacityException("Unable to allocate more mac addresses", Network.class, network.getId()); } } - + if (nic.getIPv6Address() == null && isIpv6Supported && network.getIp6Cidr() != null && network.getIp6Gateway() != null) { + if (isGateway) { + nic.setIPv6Address(network.getIp6Gateway()); + nic.setIPv6Cidr(network.getIp6Cidr()); + nic.setIPv6Gateway(network.getIp6Gateway()); + if (nic.getIPv4Address() != null) { + nic.setFormat(Networks.AddressFormat.DualStack); + } else { + nic.setFormat(Networks.AddressFormat.Ip6); + } + } + ipv6AddressManager.setNicIp6Address(nic, dc, network); + } return nic; } diff --git a/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java index 330a3652b2f6..c3f7ee3d9416 100644 --- a/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java @@ -31,6 +31,7 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.network.IpAddressManager; +import com.cloud.network.Ipv6Service; import com.cloud.network.Network; import com.cloud.network.Network.State; import com.cloud.network.NetworkProfile; @@ -70,6 +71,8 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { IPAddressDao _ipAddressDao; @Inject IpAddressManager _ipAddrMgr; + @Inject + Ipv6Service ipv6Service; private static final TrafficType[] TrafficTypes = {TrafficType.Public}; @@ -139,6 +142,8 @@ protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Ne nic.setIPv4Dns1(dc.getDns1()); nic.setIPv4Dns2(dc.getDns2()); + + ipv6Service.updateNicIpv6(nic, dc, network); } @Override diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 0ea8e527d22d..c472532e2ef8 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -26,10 +26,6 @@ import javax.inject.Inject; -import com.cloud.dc.dao.DataCenterIpv6AddressDao; -import com.cloud.network.Ipv6Service; -import com.cloud.utils.exception.CloudRuntimeException; -import com.googlecode.ipv6.IPv6Address; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -70,17 +66,20 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; +import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.VlanDao; import com.cloud.host.Host; import com.cloud.host.dao.HostDao; import com.cloud.network.IpAddress; +import com.cloud.network.Ipv6Service; import com.cloud.network.Network; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.NetworkModel; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.PublicIpv6AddressNetworkMapVO; import com.cloud.network.PublicIpAddress; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.Site2SiteVpnConnection; @@ -88,9 +87,10 @@ import com.cloud.network.VpnUserVO; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; -import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.PublicIpv6AddressNetworkMapDao; import com.cloud.network.dao.Site2SiteCustomerGatewayDao; import com.cloud.network.dao.Site2SiteCustomerGatewayVO; import com.cloud.network.dao.Site2SiteVpnGatewayDao; @@ -184,9 +184,9 @@ public class CommandSetupHelper { @Inject private HostDao _hostDao; @Inject - Ipv6Service _ipv6Service; + private Ipv6Service ipv6Service; @Inject - DataCenterIpv6AddressDao _ipv6AddressDao; + private PublicIpv6AddressNetworkMapDao publicIpv6AddressNetworkMapDao; @Autowired @Qualifier("networkHelper") @@ -1059,28 +1059,25 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute } private void updateSetupGuestNetworkCommandIpv6(SetupGuestNetworkCommand setupCmd, Network network, String macAddress, String defaultIp6Dns1, String defaultIp6Dns2) { - boolean isIpv6Supported = _ipv6Service.isIpv6Supported(network.getNetworkOfferingId()); + boolean isIpv6Supported = _networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()); if (isIpv6Supported) { setupCmd.setDefaultIp6Dns1(defaultIp6Dns1); setupCmd.setDefaultIp6Dns2(defaultIp6Dns2); - final String routerIpv6 = _ipv6AddressDao.getRouterIpv6ByNetwork(network.getId()); - if (routerIpv6 == null) { - final String routerIpv6Gateway = Ipv6Service.routerIpv6Gateway.valueIn(network.getAccountId()); - if (routerIpv6Gateway == null) { - throw new CloudRuntimeException(String.format("Invalid routerIpv6Prefix for account %s", network.getAccountId())); - } - final String routerIpv6Prefix = routerIpv6Gateway.split("::")[0]; - IPv6Address ipv6addr = NetUtils.EUI64Address(routerIpv6Prefix + Ipv6Service.IPV6_CIDR_SUFFIX, macAddress); - s_logger.info("Calculated IPv6 address " + ipv6addr + " using EUI-64 for mac address " + macAddress); - setupCmd.setRouterIpv6(ipv6addr.toString()); - setupCmd.setRouterIpv6Cidr(routerIpv6Prefix + Ipv6Service.IPV6_CIDR_SUFFIX); - setupCmd.setRouterIpv6Gateway(routerIpv6Gateway); - } else { - setupCmd.setRouterIpv6(routerIpv6); - setupCmd.setRouterIpv6Cidr(routerIpv6 + Ipv6Service.IPV6_CIDR_SUFFIX); - final String routerIpv6Gateway = _ipv6AddressDao.getRouterIpv6GatewayByNetwork((network.getId())); - setupCmd.setRouterIpv6Gateway(routerIpv6Gateway); + PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMapVO = publicIpv6AddressNetworkMapDao.findByNetworkId(network.getId()); + VlanVO vlanVO = null; + if (ipv6AddressNetworkMapVO == null) { + Pair publicIpv6AddressNetworkMapVlanPair = ipv6Service.assignPublicIpv6ToNetwork(network); + ipv6AddressNetworkMapVO = publicIpv6AddressNetworkMapVlanPair.first(); + vlanVO = publicIpv6AddressNetworkMapVlanPair.second(); + } + setupCmd.setRouterIpv6(ipv6AddressNetworkMapVO.getIp6Address()); + if (vlanVO == null) { + vlanVO = _vlanDao.findById(ipv6AddressNetworkMapVO.getRangeId()); } + final String routerIpv6Gateway = vlanVO.getIp6Gateway(); + final String routerIpv6Cidr = vlanVO.getIp6Cidr(); + setupCmd.setRouterIpv6Gateway(routerIpv6Gateway); + setupCmd.setRouterIpv6Cidr(routerIpv6Cidr); } } diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index 16e39eca63e6..0ac53485779e 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -65,6 +65,7 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddressManager; +import com.cloud.network.Ipv6Service; import com.cloud.network.Network; import com.cloud.network.NetworkModel; import com.cloud.network.Networks.BroadcastDomainType; @@ -164,6 +165,8 @@ public class NetworkHelperImpl implements NetworkHelper { NetworkDetailsDao networkDetailsDao; @Inject RouterHealthCheckResultDao _routerHealthCheckResultDao; + @Inject + Ipv6Service ipv6Service; protected final Map> hypervisorsMap = new HashMap<>(); @@ -682,7 +685,7 @@ protected LinkedHashMap> configurePublicNic( defaultNic.setMacAddress(peerNic.getMacAddress()); } if (routerDeploymentDefinition.getGuestNetwork() != null) { - _ipv6Service.updateNicIpv6(defaultNic, routerDeploymentDefinition.getDest().getDataCenter(), routerDeploymentDefinition.getGuestNetwork()); + ipv6Service.updateNicIpv6(defaultNic, routerDeploymentDefinition.getDest().getDataCenter(), routerDeploymentDefinition.getGuestNetwork()); } publicConfig.put(publicNetworks.get(0), new ArrayList(Arrays.asList(defaultNic))); } diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index 586d612ce72f..552cb2406e44 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -2577,7 +2577,7 @@ public boolean isIpAllocatedToVpc(final IpAddress ip) { @Override public Network createVpcGuestNetwork(final long ntwkOffId, final String name, final String displayText, final String gateway, final String cidr, final String vlanId, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk, final long zoneId, final ACLType aclType, final Boolean subdomainAccess, - final long vpcId, final Long aclId, final Account caller, final Boolean isDisplayNetworkEnabled, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, + final long vpcId, final Long aclId, final Account caller, final Boolean isDisplayNetworkEnabled, String externalId, String ip6Gateway, String ip6Cidr) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { final Vpc vpc = getActiveVpc(vpcId); diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 2243ad03cf26..a8ca537ba0c9 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -117,13 +117,14 @@ import org.apache.cloudstack.api.command.admin.management.ListMgmtsCmd; import org.apache.cloudstack.api.command.admin.network.AddNetworkDeviceCmd; import org.apache.cloudstack.api.command.admin.network.AddNetworkServiceProviderCmd; -import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIp6PrefixCmd; +import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkCmdByAdmin; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.CreatePhysicalNetworkCmd; import org.apache.cloudstack.api.command.admin.network.CreateStorageNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkDeviceCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; @@ -131,6 +132,7 @@ import org.apache.cloudstack.api.command.admin.network.DeletePhysicalNetworkCmd; import org.apache.cloudstack.api.command.admin.network.DeleteStorageNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; +import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd; import org.apache.cloudstack.api.command.admin.network.ListNetworkDeviceCmd; import org.apache.cloudstack.api.command.admin.network.ListNetworkIsolationMethodsCmd; import org.apache.cloudstack.api.command.admin.network.ListNetworkServiceProvidersCmd; @@ -3474,7 +3476,9 @@ public List> getCommands() { cmdList.add(AcquirePodIpCmdByAdmin.class); cmdList.add(ReleasePodIpCmdByAdmin.class); cmdList.add(CreateManagementNetworkIpRangeCmd.class); - cmdList.add(CreateGuestNetworkIp6PrefixCmd.class); + cmdList.add(CreateGuestNetworkIpv6PrefixCmd.class); + cmdList.add(ListGuestNetworkIpv6PrefixesCmd.class); + cmdList.add(DeleteGuestNetworkIpv6RangeCmd.class); cmdList.add(DeleteManagementNetworkIpRangeCmd.class); cmdList.add(UploadTemplateDirectDownloadCertificateCmd.class); cmdList.add(RevokeTemplateDirectDownloadCertificateCmd.class); diff --git a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index d79908ecedf7..52f070b78480 100644 --- a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -137,6 +137,8 @@ + + diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index 88024a98ad40..db45e665f05b 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -24,11 +24,13 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; -import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIp6PrefixCmd; +import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; +import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd; import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd; @@ -61,6 +63,7 @@ import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.DataCenterGuestIpv6Prefix; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; @@ -214,11 +217,33 @@ public void updatePodIpRange(final UpdatePodManagementNetworkIpRangeCmd cmd) thr return; } + /* (non-Javadoc) + * @see com.cloud.configuration.ConfigurationService#createDataCenterGuestIpv6Prefix(org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd) + */ @Override - public Pod createPodGuestIp6Prefix(CreateGuestNetworkIp6PrefixCmd cmd) { + public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(CreateGuestNetworkIpv6PrefixCmd cmd) { + // TODO Auto-generated method stub return null; } + /* (non-Javadoc) + * @see com.cloud.configuration.ConfigurationService#listDataCenterGuestIpv6Prefixes(org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd) + */ + @Override + public List listDataCenterGuestIpv6Prefixes(ListGuestNetworkIpv6PrefixesCmd cmd) { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see com.cloud.configuration.ConfigurationService#deleteDataCenterGuestIpv6Prefix(org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd) + */ + @Override + public boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6RangeCmd cmd) { + // TODO Auto-generated method stub + return true; + } + /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationService#editPod(org.apache.cloudstack.api.commands.UpdatePodCmd) */ diff --git a/server/src/test/resources/createNetworkOffering.xml b/server/src/test/resources/createNetworkOffering.xml index 897d4dac3054..a728f656c622 100644 --- a/server/src/test/resources/createNetworkOffering.xml +++ b/server/src/test/resources/createNetworkOffering.xml @@ -41,6 +41,7 @@ + diff --git a/ui/src/role/index.js b/ui/src/role/index.js index 2052e3e0577e..3385eacb806d 100644 --- a/ui/src/role/index.js +++ b/ui/src/role/index.js @@ -22,5 +22,5 @@ export function isAdmin () { } export function isAdminOrDomainAdmin () { - return ['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype) + return ['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype) } diff --git a/ui/src/views/infra/network/IpRangesTabGuest.vue b/ui/src/views/infra/network/IpRangesTabGuest.vue index b6f151ef18fd..f48e490b6576 100644 --- a/ui/src/views/infra/network/IpRangesTabGuest.vue +++ b/ui/src/views/infra/network/IpRangesTabGuest.vue @@ -20,18 +20,18 @@ IPv6 Ranges + @click="addIpv6PrefixModal = true"> {{ $t('Add IPv6 Prefix') }} @@ -94,32 +94,18 @@ + @cancel="addIpv6PrefixModal = false" + v-ctrl-enter="handleAddIpv6Prefix"> - - - {{ item.name }} - - @@ -127,8 +113,8 @@
- {{ $t('label.cancel') }} - {{ $t('label.ok') }} + {{ $t('label.cancel') }} + {{ $t('label.ok') }}
@@ -192,18 +178,14 @@ export default { dataIndex: 'ip6cidr' } ], - ip6Prefixes: [], - ip6Columns: [ - { - title: this.$t('label.podid'), - dataIndex: 'name' - }, + ipv6Prefixes: [], + ipv6Columns: [ { title: this.$t('label.prefix'), dataIndex: 'prefix' } ], - addIp6PrefixModal: false + addIpv6PrefixModal: false } }, beforeCreate () { @@ -237,30 +219,17 @@ export default { }).finally(() => { this.componentLoading = false }) - this.fetchPodData() + this.fetchGuetsNetworkIpv6PrefixData() }, - fetchPodData () { + fetchGuetsNetworkIpv6PrefixData () { // this.componentLoading = true - api('listPods', { + api('listGuestNetworkIpv6Prefixes', { zoneid: this.resource.zoneid, page: this.page, pagesize: this.pageSize }).then(response => { - this.items = [] - this.ip6Prefixes = [] - this.total = response.listpodsresponse.count || 0 - this.pods = response.listpodsresponse.pod ? response.listpodsresponse.pod : [] - for (const pod of this.pods) { - if (pod && pod.guestip6prefix && pod.guestip6prefix.length > 0) { - for (var guestip6prefix of pod.guestip6prefix) { - this.ip6Prefixes.push({ - id: pod.id, - name: pod.name, - prefix: guestip6prefix - }) - } - } - } + this.ipv6Prefixes = response.listguestnetworkipv6prefixesresponse.guestnetworkipv6prefix + this.total = response.listguestnetworkipv6prefixesresponse.count || 0 }).catch(error => { console.log(error) this.$notifyError(error) @@ -284,20 +253,20 @@ export default { this.pageSize = pageSize this.fetchData() }, - handleAddIp6Prefix (e) { + handleAddIpv6Prefix (e) { if (this.componentLoading) return this.form.validateFields((error, values) => { if (error) return this.componentLoading = true - this.addIp6PrefixModal = false + this.addIpv6PrefixModal = false var params = { - podid: values.pod, + zoneid: this.resource.zoneid, prefix: values.prefix } - api('createGuestNetworkIp6Prefix', params).then(response => { + api('createGuestNetworkIpv6Prefix', params).then(response => { this.$pollJob({ - jobId: response.createguestnetworkip6prefixresponse.jobid, + jobId: response.createguestnetworkipv6prefixresponse.jobid, title: this.$t('label.add.ip.range'), description: values.pod, successMessage: this.$t('message.success.add.iprange'), diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index 2fa415d92050..c5d2f6d6bb2f 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -37,6 +37,9 @@ + @@ -393,13 +396,13 @@ export default { title: this.$t('label.gateway'), scopedSlots: { customRender: 'gateway' } }, + // { + // title: this.$t('label.ip4netmask'), + // dataIndex: 'netmask' + // }, { - title: this.$t('label.ip4netmask'), - dataIndex: 'netmask' - }, - { - title: this.$t('label.ip6cidr'), - dataIndex: 'ip6cidr' + title: this.$t('label.cidr'), + scopedSlots: { customRender: 'cidr' } }, { title: this.$t('label.vlan'), From a44e6311369acd4c9b78aa51bbbb5b3311127579 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 17 Dec 2021 12:35:04 +0530 Subject: [PATCH 011/109] changes for diagnostics Signed-off-by: Abhishek Kumar --- systemvm/debian/opt/cloud/bin/diagnostics.py | 12 ++++++++++++ ui/src/config/section/infra/systemVms.js | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/systemvm/debian/opt/cloud/bin/diagnostics.py b/systemvm/debian/opt/cloud/bin/diagnostics.py index 477f99d9d3fb..737b12206db8 100755 --- a/systemvm/debian/opt/cloud/bin/diagnostics.py +++ b/systemvm/debian/opt/cloud/bin/diagnostics.py @@ -50,12 +50,24 @@ def get_command(): else: return cmd + " -c 4" + elif cmd_type == 'ping6': + if '-c' in arguments: + return cmd + else: + return cmd + " -c 4" + elif cmd_type == 'traceroute': if '-m' in arguments: return cmd else: return cmd + " -m 20" + elif cmd_type == 'traceroute6': + if '-m' in arguments: + return cmd + else: + return cmd + " -m 20" + elif cmd_type == 'arping': if '-c' in arguments: return cmd diff --git a/ui/src/config/section/infra/systemVms.js b/ui/src/config/section/infra/systemVms.js index 2c0bd1d6e593..ebbec969c957 100644 --- a/ui/src/config/section/infra/systemVms.js +++ b/ui/src/config/section/infra/systemVms.js @@ -116,7 +116,7 @@ export default { value: (record) => { return record.id } }, type: { - options: ['ping', 'traceroute', 'arping'] + options: ['ping', 'ping6', 'traceroute', 'traceroute6', 'arping'] } }, response: (result) => { return result && result.diagnostics ? `Output:
${result.diagnostics.stdout}
Error: ${result.diagnostics.stderr}
Exit Code: ${result.diagnostics.exitcode}` : 'Invalid response' } From 5100f59bbba7d137bef8790c3e7bbb19061df75d Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 17 Dec 2021 13:56:57 +0530 Subject: [PATCH 012/109] more import fromo #5594 Signed-off-by: Abhishek Kumar --- .../main/java/com/cloud/event/EventTypes.java | 5 + .../java/com/cloud/network/Ipv6Service.java | 41 +- .../com/cloud/network/rules/FirewallRule.java | 2 +- .../apache/cloudstack/api/ApiConstants.java | 3 +- .../cloudstack/api/ResponseGenerator.java | 2 + .../user/ipv6/CreateIpv6FirewallRuleCmd.java | 225 ++++++++ .../user/ipv6/DeleteIpv6FirewallRuleCmd.java | 98 ++++ .../user/ipv6/ListIpv6FirewallRulesCmd.java | 136 +++++ .../user/ipv6/UpdateIpv6FirewallRuleCmd.java | 176 ++++++ .../api/response/NetworkResponse.java | 24 + .../offerings/dao/NetworkOfferingDao.java | 2 + .../offerings/dao/NetworkOfferingDaoImpl.java | 9 +- .../java/com/cloud/api/ApiResponseHelper.java | 44 ++ .../com/cloud/network/Ipv6ServiceImpl.java | 93 +++- .../network/firewall/FirewallManagerImpl.java | 13 +- .../network/router/CommandSetupHelper.java | 28 +- .../network/router/NetworkHelperImpl.java | 5 +- .../VirtualNetworkApplianceManagerImpl.java | 10 +- systemvm/debian/opt/cloud/bin/setup/common.sh | 3 + ui/src/config/section/network.js | 4 + ui/src/views/network/Ipv6FirewallRulesTab.vue | 501 ++++++++++++++++++ 21 files changed, 1352 insertions(+), 72 deletions(-) rename {server => api}/src/main/java/com/cloud/network/Ipv6Service.java (58%) create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/DeleteIpv6FirewallRuleCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java create mode 100644 ui/src/views/network/Ipv6FirewallRulesTab.vue diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 1e9fef212be2..47da9de9b36c 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -481,6 +481,11 @@ public class EventTypes { public static final String EVENT_NETWORK_ACL_ITEM_UPDATE = "NETWORK.ACL.ITEM.UPDATE"; public static final String EVENT_NETWORK_ACL_ITEM_DELETE = "NETWORK.ACL.ITEM.DELETE"; + // IPv6 firewall rule + public static final String EVENT_IPV6_FIREWALL_RULE_CREATE = "IPV6.FIREWALL.RULE.CREATE"; + public static final String EVENT_IPV6_FIREWALL_RULE_UPDATE = "IPV6.FIREWALL.RULE.UPDATE"; + public static final String EVENT_IPV6_FIREWALL_RULE_DELETE = "IPV6.FIREWALL.RULE.DELETE"; + // VPC offerings public static final String EVENT_VPC_OFFERING_CREATE = "VPC.OFFERING.CREATE"; public static final String EVENT_VPC_OFFERING_UPDATE = "VPC.OFFERING.UPDATE"; diff --git a/server/src/main/java/com/cloud/network/Ipv6Service.java b/api/src/main/java/com/cloud/network/Ipv6Service.java similarity index 58% rename from server/src/main/java/com/cloud/network/Ipv6Service.java rename to api/src/main/java/com/cloud/network/Ipv6Service.java index dea63afd0e73..532d82b457b4 100644 --- a/server/src/main/java/com/cloud/network/Ipv6Service.java +++ b/api/src/main/java/com/cloud/network/Ipv6Service.java @@ -14,44 +14,47 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. - package com.cloud.network; -import org.apache.cloudstack.framework.config.Configurable; +import java.util.List; + +import org.apache.cloudstack.api.command.user.ipv6.CreateIpv6FirewallRuleCmd; +import org.apache.cloudstack.api.command.user.ipv6.ListIpv6FirewallRulesCmd; +import org.apache.cloudstack.api.command.user.ipv6.UpdateIpv6FirewallRuleCmd; import com.cloud.dc.DataCenter; -import com.cloud.dc.VlanVO; +import com.cloud.dc.Vlan; import com.cloud.exception.ResourceAllocationException; +import com.cloud.network.rules.FirewallRule; import com.cloud.utils.Pair; +import com.cloud.utils.component.PluggableService; import com.cloud.vm.NicProfile; -public interface Ipv6Service extends Configurable { +public interface Ipv6Service extends PluggableService { public static final String IPV6_CIDR_SUFFIX = "/64"; - public static final String RouterSlaacIpv6Prefix = "SLAAC-"; - Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws ResourceAllocationException; void assignIpv6SubnetToNetwork(String subnet, long networkId); void releaseIpv6SubnetForNetwork(long networkId); - Pair assignPublicIpv6ToNetwork(Network network); + Pair assignPublicIpv6ToNetwork(Network network); void updateNicIpv6(NicProfile nic, DataCenter dc, Network network); void releasePublicIpv6ForNetwork(long networkId); -// FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd); -// -// Pair,Integer> listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd); -// -// boolean revokeIpv6FirewallRule(Long id); -// -// FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd createIpv6FirewallRuleCmd); -// -// FirewallRule getIpv6FirewallRule(Long entityId); -// -// boolean applyIpv6FirewallRule(long id); -} \ No newline at end of file + FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd); + + Pair,Integer> listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd); + + boolean revokeIpv6FirewallRule(Long id); + + FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd createIpv6FirewallRuleCmd); + + FirewallRule getIpv6FirewallRule(Long entityId); + + boolean applyIpv6FirewallRule(long id); +} diff --git a/api/src/main/java/com/cloud/network/rules/FirewallRule.java b/api/src/main/java/com/cloud/network/rules/FirewallRule.java index 6a46c7da03dc..369c6aa57eb8 100644 --- a/api/src/main/java/com/cloud/network/rules/FirewallRule.java +++ b/api/src/main/java/com/cloud/network/rules/FirewallRule.java @@ -25,7 +25,7 @@ public interface FirewallRule extends ControlledEntity, Identity, InternalIdentity, Displayable { enum Purpose { - Firewall, PortForwarding, LoadBalancing, Vpn, StaticNat, NetworkACL, + Firewall, PortForwarding, LoadBalancing, Vpn, StaticNat, NetworkACL, Ipv6Firewall, } enum FirewallRuleType { diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 510adbc6aaea..4c63ad8d9cc6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -577,7 +577,8 @@ public class ApiConstants { public static final String LIST_ALL = "listall"; public static final String IP_RANGES = "ipranges"; public static final String IP6_RANGE = "ip6range"; - public static final String IP6_RANGES = "ip6ranges"; + public static final String IPV6_FIREWALL = "ip6firewall"; + public static final String IPV6_ROUTING = "ip6routing"; public static final String SPECIFY_IP_RANGES = "specifyipranges"; public static final String IS_SOURCE_NAT = "issourcenat"; public static final String IS_STATIC_NAT = "isstaticnat"; diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java index 90566a4c0c94..c546571c58c3 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java @@ -494,4 +494,6 @@ List createTemplateResponses(ResponseView view, VirtualMachine RollingMaintenanceResponse createRollingMaintenanceResponse(Boolean success, String details, List hostsUpdated, List hostsSkipped); ResourceIconResponse createResourceIconResponse(ResourceIcon resourceIcon); + + FirewallRuleResponse createIpv6FirewallRuleResponse(FirewallRule acl); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java new file mode 100644 index 000000000000..3ca50558f386 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java @@ -0,0 +1,225 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.ipv6; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.commons.lang3.StringUtils; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Ipv6Service; +import com.cloud.network.rules.FirewallRule; +import com.cloud.user.Account; +import com.cloud.utils.net.NetUtils; + +@APICommand(name = CreateIpv6FirewallRuleCmd.APINAME, description = "Creates an Ipv6 firewall rule in the given network (the network has to belong to VPC)", responseObject = FirewallRuleResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class CreateIpv6FirewallRuleCmd extends BaseAsyncCreateCmd { + public static final Logger s_logger = Logger.getLogger(CreateIpv6FirewallRuleCmd.class.getName()); + + public static final String APINAME = "createIpv6FirewallRule"; + + @Inject + Ipv6Service ipv6Service; + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, required = true, description = "the protocol for the Ipv6 firewall rule. Valid values are TCP/UDP/ICMP/ALL or valid protocol number") + private String protocol; + + @Parameter(name = ApiConstants.START_PORT, type = CommandType.INTEGER, description = "the starting port of Ipv6 firewall rule") + private Integer publicStartPort; + + @Parameter(name = ApiConstants.END_PORT, type = CommandType.INTEGER, description = "the ending port of Ipv6 firewall rule") + private Integer publicEndPort; + + @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the CIDR list to allow traffic from/to. Multiple entries must be separated by a single comma character (,).") + private List cidrlist; + + @Parameter(name = ApiConstants.ICMP_TYPE, type = CommandType.INTEGER, description = "type of the ICMP message being sent") + private Integer icmpType; + + @Parameter(name = ApiConstants.ICMP_CODE, type = CommandType.INTEGER, description = "error code for this ICMP message") + private Integer icmpCode; + + @Parameter(name = ApiConstants.NETWORK_ID, type = CommandType.UUID, entityType = NetworkResponse.class, description = "The network of the VM the Ipv6 firewall rule will be created for") + private Long networkId; + + @Parameter(name = ApiConstants.TRAFFIC_TYPE, type = CommandType.STRING, description = "the traffic type for the Ipv6 firewall rule," + "can be ingress or egress, defaulted to ingress if not specified") + private String trafficType; + + @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the rule to the end user or not", authorized = {RoleType.Admin}) + private Boolean display; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + @Override + public boolean isDisplay() { + if (display != null) { + return display; + } else { + return true; + } + } + + public String getProtocol() { + String p = protocol.trim(); + // Deal with ICMP(protocol number 1) specially because it need to be paired with icmp type and code + if (StringUtils.isNumeric(p)) { + int protoNumber = Integer.parseInt(p); + if (protoNumber == 1) { + p = "icmp"; + } + } + return p; + } + + public List getSourceCidrList() { + if (cidrlist != null) { + return cidrlist; + } else { + List oneCidrList = new ArrayList(); + oneCidrList.add(NetUtils.ALL_IP4_CIDRS); + return oneCidrList; + } + } + + public FirewallRule.TrafficType getTrafficType() { + if (trafficType == null) { + return FirewallRule.TrafficType.Ingress; + } + for (FirewallRule.TrafficType type : FirewallRule.TrafficType.values()) { + if (type.toString().equalsIgnoreCase(trafficType)) { + return type; + } + } + throw new InvalidParameterValueException("Invalid traffic type " + trafficType); + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + RESPONSE_SUFFIX; + } + + public Integer getSourcePortStart() { + return publicStartPort; + } + + public Integer getSourcePortEnd() { + if (publicEndPort == null) { + if (publicStartPort != null) { + return publicStartPort; + } + } else { + return publicEndPort; + } + + return null; + } + + public Long getNetworkId() { + return networkId; + } + + @Override + public long getEntityOwnerId() { + Account caller = CallContext.current().getCallingAccount(); + return caller.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_IPV6_FIREWALL_RULE_CREATE; + } + + @Override + public String getEventDescription() { + return "Creating ipv6 firewall rule"; + } + + public Integer getIcmpCode() { + if (icmpCode != null) { + return icmpCode; + } else if (getProtocol().equalsIgnoreCase(NetUtils.ICMP_PROTO)) { + return -1; + } + return null; + } + + public Integer getIcmpType() { + if (icmpType != null) { + return icmpType; + } else if (getProtocol().equalsIgnoreCase(NetUtils.ICMP_PROTO)) { + return -1; + + } + return null; + } + + @Override + public void create() { + FirewallRule result = ipv6Service.createIpv6FirewallRule(this); + setEntityId(result.getId()); + setEntityUuid(result.getUuid()); + } + + @Override + public void execute() throws ResourceUnavailableException { + boolean success = false; + FirewallRule rule = ipv6Service.getIpv6FirewallRule(getEntityId()); + try { + CallContext.current().setEventDetails("Rule ID: " + getEntityId()); + success = ipv6Service.applyIpv6FirewallRule(rule.getId()); + + // State is different after the rule is applied, so get new object here + rule = ipv6Service.getIpv6FirewallRule(getEntityId()); + FirewallRuleResponse ruleResponse = new FirewallRuleResponse(); + if (rule != null) { + ruleResponse = _responseGenerator.createIpv6FirewallRuleResponse(rule); + setResponseObject(ruleResponse); + } + ruleResponse.setResponseName(getCommandName()); + } finally { + if (!success || rule == null) { + ipv6Service.revokeIpv6FirewallRule(getEntityId()); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create ipv6 firewall rule"); + } + } + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/DeleteIpv6FirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/DeleteIpv6FirewallRuleCmd.java new file mode 100644 index 000000000000..222819d97894 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/DeleteIpv6FirewallRuleCmd.java @@ -0,0 +1,98 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.ipv6; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Ipv6Service; +import com.cloud.user.Account; + +@APICommand(name = DeleteIpv6FirewallRuleCmd.APINAME, description = "Deletes a IPv6 firewall rule", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class DeleteIpv6FirewallRuleCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(DeleteIpv6FirewallRuleCmd.class.getName()); + public static final String APINAME = "deleteIpv6FirewallRule"; + + @Inject + Ipv6Service ipv6Service; + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, required = true, description = "the ID of the IPv6 firewall rule") + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + @Override + public String getCommandName() { + return APINAME.toLowerCase() + RESPONSE_SUFFIX; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_IPV6_FIREWALL_RULE_DELETE; + } + + @Override + public String getEventDescription() { + return ("Deleting IPv6 firewall rule ID=" + id); + } + + @Override + public long getEntityOwnerId() { + Account caller = CallContext.current().getCallingAccount(); + return caller.getAccountId(); + } + + @Override + public void execute() throws ResourceUnavailableException { + CallContext.current().setEventDetails("IPv6 firewall rule ID: " + id); + boolean result = ipv6Service.revokeIpv6FirewallRule(id); + + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete IPv6 firewall rule"); + } + } + +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java new file mode 100644 index 000000000000..2f902a9aea26 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java @@ -0,0 +1,136 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.ipv6; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.command.user.firewall.IListFirewallRulesCmd; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.log4j.Logger; + +import com.cloud.network.Ipv6Service; +import com.cloud.network.rules.FirewallRule; +import com.cloud.utils.Pair; + +@APICommand(name = ListIpv6FirewallRulesCmd.APINAME, description = "Lists all IPv6 firewall rules", responseObject = FirewallRuleResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class ListIpv6FirewallRulesCmd extends BaseListTaggedResourcesCmd implements IListFirewallRulesCmd { + public static final Logger s_logger = Logger.getLogger(ListIpv6FirewallRulesCmd.class.getName()); + + public static final String APINAME = "listIpv6FirewallRules"; + + @Inject + Ipv6Service ipv6Service; + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, + description = "Lists ipv6 firewall rule with the specified ID") + private Long id; + + @Parameter(name = ApiConstants.NETWORK_ID, type = CommandType.UUID, entityType = NetworkResponse.class, description = "list ipv6 firewall rules by network ID") + private Long networkId; + + @Parameter(name = ApiConstants.TRAFFIC_TYPE, type = CommandType.STRING, description = "list ipv6 firewall rules by traffic type - ingress or egress") + private String trafficType; + + @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, description = "list ipv6 firewall rules by protocol") + private String protocol; + + @Parameter(name = ApiConstants.ACTION, type = CommandType.STRING, description = "list ipv6 firewall rules by action: allow or deny") + private String action; + + @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "list resources by display flag; only ROOT admin is eligible to pass this parameter", authorized = {RoleType.Admin}) + private Boolean display; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + @Override + public Long getNetworkId() { + return networkId; + } + + @Override + public Long getId() { + return id; + } + + @Override + public FirewallRule.TrafficType getTrafficType() { + if (trafficType != null) { + return FirewallRule.TrafficType.valueOf(trafficType); + } + return null; + } + + @Override + public Long getIpAddressId() { + return null; + } + + public String getProtocol() { + return protocol; + } + + public String getAction() { + return action; + } + + @Override + public Boolean getDisplay() { + if (display != null) { + return display; + } + return super.getDisplay(); + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + RESPONSE_SUFFIX; + } + + @Override + public void execute() { + Pair, Integer> result = ipv6Service.listIpv6FirewallRules(this); + ListResponse response = new ListResponse(); + List ruleResponses = new ArrayList(); + + for (FirewallRule rule : result.first()) { + FirewallRuleResponse ruleData = _responseGenerator.createIpv6FirewallRuleResponse(rule); + ruleResponses.add(ruleData); + } + response.setResponses(ruleResponses, result.second()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java new file mode 100644 index 000000000000..ac9b24f10e3d --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java @@ -0,0 +1,176 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.ipv6; + +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseAsyncCustomIdCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Ipv6Service; +import com.cloud.network.rules.FirewallRule; +import com.cloud.user.Account; + +@APICommand(name = UpdateIpv6FirewallRuleCmd.APINAME, description = "Updates Ipv6 firewall rule with specified ID", responseObject = FirewallRuleResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class UpdateIpv6FirewallRuleCmd extends BaseAsyncCustomIdCmd { + public static final Logger s_logger = Logger.getLogger(UpdateIpv6FirewallRuleCmd.class.getName()); + + public static final String APINAME = "updateIpv6FirewallRule"; + + @Inject + Ipv6Service ipv6Service; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, required = true, description = "the ID of the ipv6 firewall rule") + private Long id; + + @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, description = "the protocol for the Ipv6 firewall rule. Valid values are TCP/UDP/ICMP/ALL or valid protocol number") + private String protocol; + + @Parameter(name = ApiConstants.START_PORT, type = CommandType.INTEGER, description = "the starting port of Ipv6 firewall rule") + private Integer publicStartPort; + + @Parameter(name = ApiConstants.END_PORT, type = CommandType.INTEGER, description = "the ending port of Ipv6 firewall rule") + private Integer publicEndPort; + + @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to allow traffic from/to. Multiple entries must be separated by a single comma character (,).") + private List cidrlist; + + @Parameter(name = ApiConstants.ICMP_TYPE, type = CommandType.INTEGER, description = "type of the ICMP message being sent") + private Integer icmpType; + + @Parameter(name = ApiConstants.ICMP_CODE, type = CommandType.INTEGER, description = "error code for this ICMP message") + private Integer icmpCode; + + @Parameter(name = ApiConstants.TRAFFIC_TYPE, type = CommandType.STRING, description = "the traffic type for the Ipv6 firewall rule, can be Ingress or Egress, defaulted to Ingress if not specified") + private String trafficType; + + @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the Ipv6 firewall rule to the end user or not", since = "4.4", authorized = { + RoleType.Admin}) + private Boolean display; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + @Override + public boolean isDisplay() { + if (display != null) { + return display; + } else { + return true; + } + } + + public Long getId() { + return id; + } + + public String getProtocol() { + if (protocol != null) { + return protocol.trim(); + } else { + return null; + } + } + + public List getSourceCidrList() { + return cidrlist; + } + + public FirewallRule.TrafficType getTrafficType() { + if (trafficType != null) { + for (FirewallRule.TrafficType type : FirewallRule.TrafficType.values()) { + if (type.toString().equalsIgnoreCase(trafficType)) { + return type; + } + } + } + return null; + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + RESPONSE_SUFFIX; + } + + public Integer getSourcePortStart() { + return publicStartPort; + } + + public Integer getSourcePortEnd() { + return publicEndPort; + } + + @Override + public long getEntityOwnerId() { + Account caller = CallContext.current().getCallingAccount(); + return caller.getAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_IPV6_FIREWALL_RULE_UPDATE; + } + + @Override + public String getEventDescription() { + return "Updating ipv6 firewall rule"; + } + + public Integer getIcmpCode() { + return icmpCode; + } + + public Integer getIcmpType() { + return icmpType; + } + + @Override + public void execute() throws ResourceUnavailableException { + CallContext.current().setEventDetails("Rule Id: " + getId()); + FirewallRule rules = ipv6Service.updateIpv6FirewallRule(this); + FirewallRuleResponse ruleResponse = _responseGenerator.createIpv6FirewallRuleResponse(rules); + setResponseObject(ruleResponse); + ruleResponse.setResponseName(getCommandName()); + } + + @Override + public void checkUuid() { + if (this.getCustomId() != null) { + _uuidMgr.checkUuid(this.getCustomId(), FirewallRule.class); + } + } + +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java index 4b41610ab02a..73b063982d0b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java @@ -263,6 +263,18 @@ public class NetworkResponse extends BaseResponseWithAnnotations implements Cont @Param(description = "the total number of network traffic bytes sent") private Long bytesSent; + @SerializedName(ApiConstants.INTERNET_PROTOCOL) + @Param(description = "The internet protocol of network offering") + private String internetProtocol; + + @SerializedName(ApiConstants.IPV6_ROUTING) + @Param(description = "The routing mode of network offering") + private String ipv6Routing; + + @SerializedName(ApiConstants.IPV6_FIREWALL) + @Param(description = "Whether enable firewall for IPv6 in isolated networks or VPCs") + private Boolean ipv6Firewall; + public Boolean getDisplayNetwork() { return displayNetwork; } @@ -528,4 +540,16 @@ public void setBytesReceived(Long bytesReceived) { public void setBytesSent(final Long bytesSent) { this.bytesSent = bytesSent; } + + public void setInternetProtocol(String internetProtocol) { + this.internetProtocol = internetProtocol; + } + + public void setIpv6Routing(String ipv6Routing) { + this.ipv6Routing = ipv6Routing; + } + + public void setIpv6Firewall(Boolean ipv6Firewall) { + this.ipv6Firewall = ipv6Firewall; + } } diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java index 5a2660b92dcc..b59f2d78ca6b 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java @@ -70,6 +70,8 @@ public interface NetworkOfferingDao extends GenericDao */ void persistDefaultL2NetworkOfferings(); + NetworkOffering.InternetProtocol getNetworkOfferingInternetProtocol(Long offeringId); + boolean isIpv6Supported(Long offeringId); boolean isIpv6FirewallEnabled(Long offeringId); diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java index 939157cbed75..a3735e2c1326 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java @@ -275,9 +275,14 @@ public void persistDefaultL2NetworkOfferings() { } @Override - public boolean isIpv6Supported(Long offeringId) { + public NetworkOffering.InternetProtocol getNetworkOfferingInternetProtocol(Long offeringId) { String internetProtocolStr = _detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol); - NetworkOffering.InternetProtocol internetProtocol = NetworkOffering.InternetProtocol.fromValue(internetProtocolStr); + return NetworkOffering.InternetProtocol.fromValue(internetProtocolStr); + } + + @Override + public boolean isIpv6Supported(Long offeringId) { + NetworkOffering.InternetProtocol internetProtocol = getNetworkOfferingInternetProtocol( offeringId); return ipv6EnabledProtocols.contains(internetProtocol); } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index e35f6de32a97..08ccaf61a761 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -302,6 +302,7 @@ import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.org.Cluster; import com.cloud.projects.Project; import com.cloud.projects.ProjectAccount; @@ -420,6 +421,8 @@ public class ApiResponseHelper implements ResponseGenerator { @Inject private UserStatisticsDao userStatsDao; @Inject + NetworkOfferingDao networkOfferingDao; + @Inject DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao; @Override @@ -2517,6 +2520,12 @@ public NetworkResponse createNetworkResponse(ResponseView view, Network network) response.setBytesReceived(bytesReceived); response.setBytesSent(bytesSent); + if (networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId())) { + response.setInternetProtocol(networkOfferingDao.getNetworkOfferingInternetProtocol(network.getNetworkOfferingId()).toString()); + response.setIpv6Routing("Static"); + response.setIpv6Firewall(networkOfferingDao.isIpv6FirewallEnabled(network.getNetworkOfferingId())); + } + response.setObjectName("network"); return response; } @@ -4585,4 +4594,39 @@ public RollingMaintenanceResponse createRollingMaintenanceResponse(Boolean succe public ResourceIconResponse createResourceIconResponse(ResourceIcon resourceIcon) { return ApiDBUtils.newResourceIconResponse(resourceIcon); } + + @Override + public FirewallRuleResponse createIpv6FirewallRuleResponse(FirewallRule fwRule) { + FirewallRuleResponse response = new FirewallRuleResponse(); + + response.setId(fwRule.getUuid()); + response.setProtocol(fwRule.getProtocol()); + + List cidrs = ApiDBUtils.findFirewallSourceCidrs(fwRule.getId()); + response.setCidrList(StringUtils.join(cidrs, ",")); + + Network network = ApiDBUtils.findNetworkById(fwRule.getNetworkId()); + response.setNetworkId(network.getUuid()); + + FirewallRule.State state = fwRule.getState(); + String stateToSet = state.toString(); + if (state.equals(FirewallRule.State.Revoke)) { + stateToSet = "Deleting"; + } + + response.setForDisplay(fwRule.isDisplay()); + + // set tag information + List tags = ApiDBUtils.listByResourceTypeAndId(ResourceObjectType.FirewallRule, fwRule.getId()); + List tagResponses = new ArrayList(); + for (ResourceTag tag : tags) { + ResourceTagResponse tagResponse = createResourceTagResponse(tag, true); + CollectionUtils.addIgnoreNull(tagResponses, tagResponse); + } + response.setTags(tagResponses); + + response.setState(stateToSet); + response.setObjectName("firewallrule"); + return response; + } } diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java index 388912617a10..e32264918337 100644 --- a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java @@ -17,6 +17,7 @@ package com.cloud.network; +import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -28,7 +29,10 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.api.command.user.ipv6.CreateIpv6FirewallRuleCmd; +import org.apache.cloudstack.api.command.user.ipv6.DeleteIpv6FirewallRuleCmd; +import org.apache.cloudstack.api.command.user.ipv6.ListIpv6FirewallRulesCmd; +import org.apache.cloudstack.api.command.user.ipv6.UpdateIpv6FirewallRuleCmd; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; @@ -36,6 +40,7 @@ import com.cloud.configuration.Resource; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterGuestIpv6PrefixVO; +import com.cloud.dc.Vlan; import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao; import com.cloud.dc.dao.VlanDao; @@ -44,7 +49,9 @@ import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; import com.cloud.network.dao.PublicIpv6AddressNetworkMapDao; import com.cloud.network.firewall.FirewallService; +import com.cloud.network.rules.FirewallRule; import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentLifecycleBase; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -73,25 +80,11 @@ public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Servi @Inject PublicIpv6AddressNetworkMapDao publicIpv6AddressNetworkMapDao; @Inject - FirewallRulesDao firewallRulesDao; + NetworkOfferingDetailsDao _networkOfferingDetailsDao; @Inject - FirewallService firewallservice; - - - @Override - public boolean start() { - _ipv6GuestPrefixSubnetNetworkMapStateScanner.scheduleWithFixedDelay(new Ipv6GuestPrefixSubnetNetworkMapStateScanner(), 300, 30*60, TimeUnit.SECONDS); - return true; - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _name = name; - _configParams = params; - _ipv6GuestPrefixSubnetNetworkMapStateScanner = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Kubernetes-Cluster-State-Scanner")); - - return true; - } + FirewallRulesDao _firewallDao; + @Inject + public FirewallService _firewallService; private IPv6AddressRange getIpv6AddressRangeFromIpv6Vlan(VlanVO vlanVO) { String[] rangeArr = vlanVO.getIp6Range().split("-"); @@ -117,13 +110,28 @@ protected void releaseIpv6Subnet(long subnetId) { } @Override - public String getConfigComponentName() { - return Ipv6Service.class.getSimpleName(); + public boolean start() { + _ipv6GuestPrefixSubnetNetworkMapStateScanner.scheduleWithFixedDelay(new Ipv6GuestPrefixSubnetNetworkMapStateScanner(), 300, 30*60, TimeUnit.SECONDS); + return true; } @Override - public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {}; + public boolean configure(String name, Map params) throws ConfigurationException { + _name = name; + _configParams = params; + _ipv6GuestPrefixSubnetNetworkMapStateScanner = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Kubernetes-Cluster-State-Scanner")); + + return true; + } + + @Override + public List> getCommands() { + final List> cmdList = new ArrayList>(); + cmdList.add(CreateIpv6FirewallRuleCmd.class); + cmdList.add(ListIpv6FirewallRulesCmd.class); + cmdList.add(UpdateIpv6FirewallRuleCmd.class); + cmdList.add(DeleteIpv6FirewallRuleCmd.class); + return cmdList; } public Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws ResourceAllocationException { @@ -193,7 +201,7 @@ public void releaseIpv6SubnetForNetwork(long networkId) { } @Override - public Pair assignPublicIpv6ToNetwork(Network network) { + public Pair assignPublicIpv6ToNetwork(Network network) { PublicIpv6AddressNetworkMapVO ip6NetworkMap = null; VlanVO selectedVlan = null; final List ranges = vlanDao.listVlansWithIpV6RangeByPhysicalNetworkId(network.getPhysicalNetworkId()); @@ -243,9 +251,9 @@ public Pair assignPublicIpv6ToNetwork(Net public void updateNicIpv6(NicProfile nic, DataCenter dc, Network network) { boolean isIpv6Supported = networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()); if (nic.getIPv6Address() == null && isIpv6Supported) { - Pair publicIpv6AddressNetworkMapVlanPair = assignPublicIpv6ToNetwork(network); - final PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMapVO = publicIpv6AddressNetworkMapVlanPair.first(); - final VlanVO vlan = publicIpv6AddressNetworkMapVlanPair.second(); + Pair publicIpv6AddressNetworkMapVlanPair = assignPublicIpv6ToNetwork(network); + final PublicIpv6AddressNetworkMap publicIpv6AddressNetworkMapVO = publicIpv6AddressNetworkMapVlanPair.first(); + final Vlan vlan = publicIpv6AddressNetworkMapVlanPair.second(); final String routerIpv6 = publicIpv6AddressNetworkMapVO.getIp6Address(); final String routerIpv6Gateway = vlan.getIp6Gateway(); final String routerIpv6Cidr = vlan.getIp6Cidr(); @@ -311,4 +319,35 @@ public void reallyRun() { } } } + + public FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd) { + // TODO + return _firewallDao.findById(updateIpv6FirewallRuleCmd.getId()); + } + + @Override + public Pair, Integer> listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd) { + return _firewallService.listFirewallRules(listIpv6FirewallRulesCmd); + } + + @Override + public boolean revokeIpv6FirewallRule(Long id) { + // TODO + return true; + } + + @Override + public FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd createIpv6FirewallRuleCmd) { + return null; + } + + @Override + public FirewallRule getIpv6FirewallRule(Long entityId) { + return _firewallDao.findById(entityId); + } + + @Override + public boolean applyIpv6FirewallRule(long id) { + return false; + } } diff --git a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java index 56814daeef25..d6a3c63df318 100644 --- a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java @@ -28,6 +28,7 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.user.firewall.IListFirewallRulesCmd; +import org.apache.cloudstack.api.command.user.ipv6.ListIpv6FirewallRulesCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -336,11 +337,15 @@ public Pair, Integer> listFirewallRules(IListFirewa sc.setParameters("ip", ipId); } - if (networkId != null) { - sc.setParameters("networkId", networkId); - } + if (networkId != null) { + sc.setParameters("networkId", networkId); + } - sc.setParameters("purpose", Purpose.Firewall); + if (cmd instanceof ListIpv6FirewallRulesCmd) { + sc.setParameters("purpose", Purpose.Ipv6Firewall); + } else { + sc.setParameters("purpose", Purpose.Firewall); + } sc.setParameters("trafficType", trafficType); Pair, Integer> result = _firewallDao.searchAndCount(sc, filter); diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index c472532e2ef8..0e9caf6ffa46 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -66,7 +66,7 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; -import com.cloud.dc.VlanVO; +import com.cloud.dc.Vlan; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.VlanDao; import com.cloud.host.Host; @@ -79,8 +79,8 @@ import com.cloud.network.NetworkModel; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; -import com.cloud.network.PublicIpv6AddressNetworkMapVO; import com.cloud.network.PublicIpAddress; +import com.cloud.network.PublicIpv6AddressNetworkMap; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.Site2SiteVpnConnection; import com.cloud.network.VpnUser; @@ -1063,21 +1063,23 @@ private void updateSetupGuestNetworkCommandIpv6(SetupGuestNetworkCommand setupCm if (isIpv6Supported) { setupCmd.setDefaultIp6Dns1(defaultIp6Dns1); setupCmd.setDefaultIp6Dns2(defaultIp6Dns2); - PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMapVO = publicIpv6AddressNetworkMapDao.findByNetworkId(network.getId()); - VlanVO vlanVO = null; - if (ipv6AddressNetworkMapVO == null) { - Pair publicIpv6AddressNetworkMapVlanPair = ipv6Service.assignPublicIpv6ToNetwork(network); - ipv6AddressNetworkMapVO = publicIpv6AddressNetworkMapVlanPair.first(); - vlanVO = publicIpv6AddressNetworkMapVlanPair.second(); + PublicIpv6AddressNetworkMap ipv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.findByNetworkId(network.getId()); + Vlan vlan = null; + if (ipv6AddressNetworkMap == null) { + Pair publicIpv6AddressNetworkMapVlanPair = ipv6Service.assignPublicIpv6ToNetwork(network); + ipv6AddressNetworkMap = publicIpv6AddressNetworkMapVlanPair.first(); + vlan = publicIpv6AddressNetworkMapVlanPair.second(); } - setupCmd.setRouterIpv6(ipv6AddressNetworkMapVO.getIp6Address()); - if (vlanVO == null) { - vlanVO = _vlanDao.findById(ipv6AddressNetworkMapVO.getRangeId()); + setupCmd.setRouterIpv6(ipv6AddressNetworkMap.getIp6Address()); + if (vlan == null) { + vlan = _vlanDao.findById(ipv6AddressNetworkMap.getRangeId()); } - final String routerIpv6Gateway = vlanVO.getIp6Gateway(); - final String routerIpv6Cidr = vlanVO.getIp6Cidr(); + final String routerIpv6Gateway = vlan.getIp6Gateway(); + final String routerIpv6Cidr = vlan.getIp6Cidr(); setupCmd.setRouterIpv6Gateway(routerIpv6Gateway); setupCmd.setRouterIpv6Cidr(routerIpv6Cidr); + boolean isIpv6FirewallEnabled = _networkOfferingDao.isIpv6FirewallEnabled(network.getNetworkOfferingId()); + setupCmd.setRouterIpv6Firewall(isIpv6FirewallEnabled); } } diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index 0ac53485779e..3d95435e36a7 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -28,14 +28,13 @@ import javax.inject.Inject; import org.apache.cloudstack.api.ApiConstants; -import org.apache.log4j.Logger; -import org.cloud.network.router.deployment.RouterDeploymentDefinition; - import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.utils.CloudStackVersion; +import org.apache.log4j.Logger; +import org.cloud.network.router.deployment.RouterDeploymentDefinition; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 914d118c6f00..51a3928ecee8 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -17,6 +17,8 @@ package com.cloud.network.router; +import static com.cloud.utils.NumbersUtil.toHumanReadableSize; + import java.lang.reflect.Type; import java.math.BigInteger; import java.nio.charset.Charset; @@ -271,8 +273,6 @@ import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; -import static com.cloud.utils.NumbersUtil.toHumanReadableSize; - /** * VirtualNetworkApplianceManagerImpl manages the different types of virtual * network appliances available in the Cloud Stack. @@ -2129,6 +2129,12 @@ protected StringBuilder createGuestBootLoadArgs(final NicProfile guestNic, final final StringBuilder buf = new StringBuilder(); + boolean isIpv6Supported = _networkOfferingDao.isIpv6Supported(guestNetwork.getNetworkOfferingId()); + boolean isIpv6FirewallEnabled = _networkOfferingDao.isIpv6FirewallEnabled(guestNetwork.getNetworkOfferingId()); + if (isIpv6Supported && isIpv6FirewallEnabled) { + buf.append(" ip6firewall=true"); + } + final boolean isRedundant = router.getIsRedundantRouter(); if (isRedundant) { buf.append(createRedundantRouterArgs(guestNic, router)); diff --git a/systemvm/debian/opt/cloud/bin/setup/common.sh b/systemvm/debian/opt/cloud/bin/setup/common.sh index 96f6f4a87329..2cb51c1c7814 100755 --- a/systemvm/debian/opt/cloud/bin/setup/common.sh +++ b/systemvm/debian/opt/cloud/bin/setup/common.sh @@ -710,6 +710,9 @@ parse_cmd_line() { ip6dns2) export IP6_NS2=$VALUE ;; + ip6firewall) + export IP6_FIREWALL=$VALUE + ;; domain) export DOMAIN=$VALUE ;; diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index 95c24159bb07..b29aa2e2710d 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -58,6 +58,10 @@ export default { name: 'egress.rules', component: () => import('@/views/network/EgressRulesTab.vue'), show: (record) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listEgressFirewallRules' in store.getters.apis } + }, { + name: 'ipv6.firewall', + component: () => import('@/views/network/Ipv6FirewallRulesTab.vue'), + show: (record) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listIpv6FirewallRules' in store.getters.apis } }, { name: 'public.ip.addresses', component: () => import('@/views/network/IpAddressesTab.vue'), diff --git a/ui/src/views/network/Ipv6FirewallRulesTab.vue b/ui/src/views/network/Ipv6FirewallRulesTab.vue new file mode 100644 index 000000000000..1a3f74459dd8 --- /dev/null +++ b/ui/src/views/network/Ipv6FirewallRulesTab.vue @@ -0,0 +1,501 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + + + + + + From 6b175ee0aeb4431f9336361374bfc65659e99b05 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 22 Oct 2021 16:55:06 +0200 Subject: [PATCH 013/109] IPv6: fix wrong public ipv6 in VPC VR --- systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py b/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py index 3b9aebdba8b7..a905f9a7984b 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py @@ -56,8 +56,9 @@ def add_address_route(self, entry): if not CsHelper.execute("ip -6 addr show dev %s | grep -w %s" % (entry['device'], full_addr)): CsHelper.execute("ip -6 addr add %s dev %s" % (full_addr, entry['device'])) if 'router_ip6' in entry.keys() and entry['router_ip6']: - if not CsHelper.execute("ip -6 addr show dev %s | grep -w %s" % (VPC_PUBLIC_INTERFACE, entry['router_ip6_cidr'])): - CsHelper.execute("ip -6 addr add %s dev %s" % (entry['router_ip6_cidr'], VPC_PUBLIC_INTERFACE)) + full_public_addr = entry['router_ip6'] + "/" + cidr_size + if not CsHelper.execute("ip -6 addr show dev %s | grep -w %s" % (VPC_PUBLIC_INTERFACE, full_public_addr)): + CsHelper.execute("ip -6 addr add %s dev %s" % (full_public_addr, VPC_PUBLIC_INTERFACE)) if not CsHelper.execute("ip -6 route list default via %s" % entry['router_ip6_gateway']): CsHelper.execute("ip -6 route add default via %s" % entry['router_ip6_gateway']) else: @@ -69,7 +70,8 @@ def remove_address_route(self, entry): full_addr = entry['router_guest_ip6_gateway'] + "/" + cidr_size CsHelper.execute("ip -6 addr del %s dev %s" % (full_addr, entry['device'])) if 'router_ip6' in entry.keys() and entry['router_ip6']: - CsHelper.execute("ip -6 addr del %s dev %s" % (entry['router_ip6_cidr'], VPC_PUBLIC_INTERFACE)) + full_public_addr = entry['router_ip6'] + "/" + cidr_size + CsHelper.execute("ip -6 addr del %s dev %s" % (full_public_addr, VPC_PUBLIC_INTERFACE)) else: return From 1aca1fe79cffb1c1cd916755975cec03778b333f Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 17 Dec 2021 16:07:44 +0530 Subject: [PATCH 014/109] changes Signed-off-by: Abhishek Kumar --- .../configuration/ConfigurationService.java | 4 +- .../apache/cloudstack/api/ApiConstants.java | 1 + ...a => DeleteGuestNetworkIpv6PrefixCmd.java} | 12 +++--- .../api/response/NetworkResponse.java | 12 +++++- .../cloud/dc/DataCenterGuestIpv6PrefixVO.java | 14 ++++--- ...pv6GuestPrefixSubnetNetworkMapDaoImpl.java | 2 +- .../java/com/cloud/api/ApiResponseHelper.java | 4 ++ .../ConfigurationManagerImpl.java | 16 ++++++- .../cloud/server/ManagementServerImpl.java | 4 +- .../vpc/MockConfigurationManagerImpl.java | 4 +- ui/public/locales/en.json | 3 ++ .../views/infra/network/IpRangesTabGuest.vue | 42 ++++++++++++++++--- .../java/com/cloud/utils/net/NetUtils.java | 18 ++++++++ 13 files changed, 108 insertions(+), 28 deletions(-) rename api/src/main/java/org/apache/cloudstack/api/command/admin/network/{DeleteGuestNetworkIpv6RangeCmd.java => DeleteGuestNetworkIpv6PrefixCmd.java} (88%) diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index 5e02f4ce2e81..0634b38313bf 100644 --- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java +++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java @@ -22,7 +22,7 @@ import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; -import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd; @@ -230,7 +230,7 @@ public interface ConfigurationService { /** * Deletes an existing IPv6 prefix. */ - boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6RangeCmd cmd); + boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6PrefixCmd cmd); /** * Edits a pod in the database. Will not allow you to edit pods that are being used anywhere in the system. diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 4c63ad8d9cc6..e1c559844c0a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -579,6 +579,7 @@ public class ApiConstants { public static final String IP6_RANGE = "ip6range"; public static final String IPV6_FIREWALL = "ip6firewall"; public static final String IPV6_ROUTING = "ip6routing"; + public static final String IPV6_ROUTING_MESSAGE = "ip6routingmessage"; public static final String SPECIFY_IP_RANGES = "specifyipranges"; public static final String IS_SOURCE_NAT = "issourcenat"; public static final String IS_STATIC_NAT = "isstaticnat"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6RangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6PrefixCmd.java similarity index 88% rename from api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6RangeCmd.java rename to api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6PrefixCmd.java index 93b1649cf67a..ac5534514d6e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6RangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6PrefixCmd.java @@ -24,7 +24,7 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.DataCenterGuestIpv6PrefixResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.log4j.Logger; @@ -36,22 +36,22 @@ import com.cloud.user.Account; import com.cloud.utils.exception.CloudRuntimeException; -@APICommand(name = DeleteGuestNetworkIpv6RangeCmd.APINAME, +@APICommand(name = DeleteGuestNetworkIpv6PrefixCmd.APINAME, description = "Deletes an existing guest network IPv6 prefix.", responseObject = SuccessResponse.class, since = "4.17.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin}) -public class DeleteGuestNetworkIpv6RangeCmd extends BaseCmd { - public static final Logger s_logger = Logger.getLogger(DeleteGuestNetworkIpv6RangeCmd.class); - public static final String APINAME = "deleteNetworkDevice"; +public class DeleteGuestNetworkIpv6PrefixCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DeleteGuestNetworkIpv6PrefixCmd.class); + public static final String APINAME = "deleteGuestNetworkIpv6Prefix"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = HostResponse.class, required = true, description = "Id of the guest network IPv6 prefix") + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DataCenterGuestIpv6PrefixResponse.class, required = true, description = "Id of the guest network IPv6 prefix") private Long id; public Long getId() { diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java index 73b063982d0b..a3263b0f47af 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java @@ -271,6 +271,10 @@ public class NetworkResponse extends BaseResponseWithAnnotations implements Cont @Param(description = "The routing mode of network offering") private String ipv6Routing; + @SerializedName(ApiConstants.IPV6_ROUTING) + @Param(description = "The routing message for the network to ease adding route in upstream router") + private String ipv6RoutingMessage; + @SerializedName(ApiConstants.IPV6_FIREWALL) @Param(description = "Whether enable firewall for IPv6 in isolated networks or VPCs") private Boolean ipv6Firewall; @@ -545,11 +549,15 @@ public void setInternetProtocol(String internetProtocol) { this.internetProtocol = internetProtocol; } + public void setIpv6Firewall(Boolean ipv6Firewall) { + this.ipv6Firewall = ipv6Firewall; + } + public void setIpv6Routing(String ipv6Routing) { this.ipv6Routing = ipv6Routing; } - public void setIpv6Firewall(Boolean ipv6Firewall) { - this.ipv6Firewall = ipv6Firewall; + public void setIpv6RoutingMessage(String ipv6RoutingMessage) { + this.ipv6RoutingMessage = ipv6RoutingMessage; } } diff --git a/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java b/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java index 9b19e332a283..f213cff83c24 100644 --- a/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java @@ -26,8 +26,8 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; + +import com.cloud.utils.db.GenericDao; @Entity @Table(name = "dc_ip6_guest_prefix") @@ -49,9 +49,11 @@ public class DataCenterGuestIpv6PrefixVO implements DataCenterGuestIpv6Prefix { @Column(name = "prefix") private String prefix; - @Column(name = "created") - @Temporal(value = TemporalType.TIMESTAMP) - private Date created = null; + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + @Column(name= GenericDao.REMOVED_COLUMN) + private Date removed; public DataCenterGuestIpv6PrefixVO(long dcId, Long podId, String prefix) { this(); @@ -105,4 +107,6 @@ public void setPrefix(String prefix) { public Date getCreated() { return created; } + + } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java index 74c8d84cd8cd..515368b32473 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java @@ -57,7 +57,7 @@ public void init() { SubnetSearch.and("subnet", SubnetSearch.entity().getSubnet(), SearchCriteria.Op.EQ); SubnetSearch.done(); StatesSearch = createSearchBuilder(); - StatesSearch.and("state", StatesSearch.entity().getSubnet(), SearchCriteria.Op.IN); + StatesSearch.and("state", StatesSearch.entity().getState(), SearchCriteria.Op.IN); StatesSearch.done(); } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 08ccaf61a761..519eb4aec51e 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -2524,6 +2524,10 @@ public NetworkResponse createNetworkResponse(ResponseView view, Network network) response.setInternetProtocol(networkOfferingDao.getNetworkOfferingInternetProtocol(network.getNetworkOfferingId()).toString()); response.setIpv6Routing("Static"); response.setIpv6Firewall(networkOfferingDao.isIpv6FirewallEnabled(network.getNetworkOfferingId())); + if (Network.GuestType.Isolated.equals(networkOffering.getGuestType())) { + + response.setIpv6RoutingMessage(String.format("Add route in upstream router")); + } } response.setObjectName("network"); diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 7cbdcb2e7c71..3b9ad4f2c1d6 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -55,7 +55,7 @@ import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; -import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd; @@ -276,6 +276,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import com.googlecode.ipv6.IPv6Address; +import com.googlecode.ipv6.IPv6Network; public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable { public static final Logger s_logger = Logger.getLogger(ConfigurationManagerImpl.class); @@ -1763,6 +1764,17 @@ public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(final CreateGue } } final String prefix = cmd.getPrefix(); + IPv6Network prefixNet = IPv6Network.fromString(prefix); + if (prefixNet.getNetmask().asPrefixLength() < 64) { + throw new InvalidParameterValueException("IPv6 prefix must be /64 or higher"); + } + List existingPrefixes = dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); + for (DataCenterGuestIpv6PrefixVO existingPrefix : existingPrefixes) { + IPv6Network existingPrefixNet = IPv6Network.fromString(existingPrefix.getPrefix()); + if (NetUtils.ipv6NetworksOverlap(existingPrefixNet, prefixNet)) { + throw new InvalidParameterValueException(String.format("IPv6 prefix %s overlaps with the existing IPv6 prefix %s", prefixNet, existingPrefixNet)); + } + } DataCenterGuestIpv6Prefix dataCenterGuestIpv6Prefix = null; try { dataCenterGuestIpv6Prefix = Transaction.execute(new TransactionCallback() { @@ -1791,7 +1803,7 @@ public List listDataCenterGuestIpv6Prefixes } @Override - public boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6RangeCmd cmd) { + public boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6PrefixCmd cmd) { final long prefixId = cmd.getId(); final DataCenterGuestIpv6PrefixVO prefix = dataCenterGuestIpv6PrefixDao.findById(prefixId); if (prefix == null) { diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index a8ca537ba0c9..1ccf68c65b13 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -124,7 +124,7 @@ import org.apache.cloudstack.api.command.admin.network.CreatePhysicalNetworkCmd; import org.apache.cloudstack.api.command.admin.network.CreateStorageNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; -import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkDeviceCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; @@ -3478,7 +3478,7 @@ public List> getCommands() { cmdList.add(CreateManagementNetworkIpRangeCmd.class); cmdList.add(CreateGuestNetworkIpv6PrefixCmd.class); cmdList.add(ListGuestNetworkIpv6PrefixesCmd.class); - cmdList.add(DeleteGuestNetworkIpv6RangeCmd.class); + cmdList.add(DeleteGuestNetworkIpv6PrefixCmd.class); cmdList.add(DeleteManagementNetworkIpRangeCmd.class); cmdList.add(UploadTemplateDirectDownloadCertificateCmd.class); cmdList.add(RevokeTemplateDirectDownloadCertificateCmd.class); diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index db45e665f05b..44f75c3d24d8 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -27,7 +27,7 @@ import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; -import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd; +import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd; @@ -239,7 +239,7 @@ public List listDataCenterGuestIpv6Prefixes * @see com.cloud.configuration.ConfigurationService#deleteDataCenterGuestIpv6Prefix(org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd) */ @Override - public boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6RangeCmd cmd) { + public boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6PrefixCmd cmd) { // TODO Auto-generated method stub return true; } diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 4a74d337c754..f63c78083bbe 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -324,6 +324,7 @@ "label.add.intermediate.certificate": "Add intermediate certificate", "label.add.internal.lb": "Add Internal LB", "label.add.ip.range": "Add IP Range", +"label.add.ip.v6.prefix": "Add IPv6 Prefix", "label.add.isolated.guest.network": "Add Isolated Guest Network", "label.add.isolated.guest.network.with.sourcenat": "Add Isolated Guest Network with SourceNat", "label.add.isolated.network": "Add Isolated Network", @@ -1838,6 +1839,7 @@ "label.remove.from.load.balancer": "Removing instance from load balancer", "label.remove.ingress.rule": "Remove ingress rule", "label.remove.ip.range": "Remove IP range", +"label.remove.ip.v6.prefix": "Remove IPv6 prefix", "label.remove.ldap": "Remove LDAP", "label.remove.management.ip.range": "Remove Management IP Range", "label.remove.network.offering": "Remove network offering", @@ -3063,6 +3065,7 @@ "message.interloadbalance.not.return.elementid": "error: listInternalLoadBalancerElements API doesn't return Internal LB Element Id", "message.ip.address.changed": "Your IP addresses may have changed; would you like to refresh the listing? Note that in this case the details pane will close.", "message.ip.address.changes.effect.after.vm.restart": "IP address changes takes effect only after VM restart.", +"message.ip.v6.prefix.removed": "Ipv6 prefix removed", "message.iso.desc": "Disc image containing data or bootable media for OS", "message.join.project": "You have now joined a project. Please switch to Project view to see the project.", "message.kubeconfig.cluster.not.available": "Kubernetes cluster kubeconfig not available currently", diff --git a/ui/src/views/infra/network/IpRangesTabGuest.vue b/ui/src/views/infra/network/IpRangesTabGuest.vue index f48e490b6576..53cbed511045 100644 --- a/ui/src/views/infra/network/IpRangesTabGuest.vue +++ b/ui/src/views/infra/network/IpRangesTabGuest.vue @@ -25,7 +25,7 @@ icon="plus" style="margin-bottom: 20px; width: 100%" @click="addIpv6PrefixModal = true"> - {{ $t('Add IPv6 Prefix') }} + {{ $t('label.add.ip.v6.prefix') }} - + > + +

@@ -126,12 +137,14 @@ import { api } from '@/api' import CreateNetwork from '@/views/network/CreateNetwork' import ResourceIcon from '@/components/view/ResourceIcon' +import TooltipButton from '@/components/widgets/TooltipButton' export default { name: 'IpRangesTabGuest', components: { CreateNetwork, - ResourceIcon + ResourceIcon, + TooltipButton }, props: { resource: { @@ -183,6 +196,10 @@ export default { { title: this.$t('label.prefix'), dataIndex: 'prefix' + }, + { + title: this.$t('label.action'), + scopedSlots: { customRender: 'actions' } } ], addIpv6PrefixModal: false @@ -219,9 +236,9 @@ export default { }).finally(() => { this.componentLoading = false }) - this.fetchGuetsNetworkIpv6PrefixData() + this.fetchIpv6PrefixData() }, - fetchGuetsNetworkIpv6PrefixData () { + fetchIpv6PrefixData () { // this.componentLoading = true api('listGuestNetworkIpv6Prefixes', { zoneid: this.resource.zoneid, @@ -293,6 +310,19 @@ export default { this.fetchData() }) }) + }, + handleDeleteIpv6Prefix (prefix) { + this.componentLoading = true + api('deleteGuestNetworkIpv6Prefix', { id: prefix.id }).then(() => { + this.$notification.success({ + message: this.$t('message.ip.v6.prefix.removed') + ' ' + prefix.prefix + }) + }).catch(error => { + this.$notifyError(error) + }).finally(() => { + this.componentLoading = false + this.fetchIpv6PrefixData() + }) } } } diff --git a/utils/src/main/java/com/cloud/utils/net/NetUtils.java b/utils/src/main/java/com/cloud/utils/net/NetUtils.java index feaac8f7f8bc..ffea5ef693fb 100644 --- a/utils/src/main/java/com/cloud/utils/net/NetUtils.java +++ b/utils/src/main/java/com/cloud/utils/net/NetUtils.java @@ -33,6 +33,7 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Formatter; +import java.util.Iterator; import java.util.List; import java.util.Collections; import java.util.Random; @@ -1677,4 +1678,21 @@ public static boolean isIpv4(String ipAddr) { return isIpv4; } + public static boolean ipv6NetworksOverlap(IPv6Network n1, IPv6Network n2) { + IPv6Network higher = n1; + IPv6Network lower = n2; + if (lower.getNetmask().asPrefixLength() > higher.getNetmask().asPrefixLength()) { + lower = n1; + higher = n2; + } + Iterator splits = higher.split(lower.getNetmask()); + while (splits.hasNext()) { + IPv6Network i = splits.next(); + if (i.equals(lower)) { + return true; + } + } + return false; + } + } From 71f29b4fa9e2f7f57424e910e13af9ec92be8c34 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 17 Dec 2021 16:18:27 +0530 Subject: [PATCH 015/109] fix Signed-off-by: Abhishek Kumar --- .../com/cloud/configuration/ConfigurationManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 3b9ad4f2c1d6..4cf106e8af53 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1765,8 +1765,8 @@ public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(final CreateGue } final String prefix = cmd.getPrefix(); IPv6Network prefixNet = IPv6Network.fromString(prefix); - if (prefixNet.getNetmask().asPrefixLength() < 64) { - throw new InvalidParameterValueException("IPv6 prefix must be /64 or higher"); + if (prefixNet.getNetmask().asPrefixLength() > 64) { + throw new InvalidParameterValueException("IPv6 prefix must be /64 or lesser"); } List existingPrefixes = dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); for (DataCenterGuestIpv6PrefixVO existingPrefix : existingPrefixes) { From bfa9a06190c0dd4df9ae317b03f84df859ec4ee6 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 17 Dec 2021 16:24:51 +0530 Subject: [PATCH 016/109] Update server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java Co-authored-by: dahn --- .../java/com/cloud/configuration/ConfigurationManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 4cf106e8af53..f1fe620c9e38 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1766,7 +1766,7 @@ public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(final CreateGue final String prefix = cmd.getPrefix(); IPv6Network prefixNet = IPv6Network.fromString(prefix); if (prefixNet.getNetmask().asPrefixLength() > 64) { - throw new InvalidParameterValueException("IPv6 prefix must be /64 or lesser"); + throw new InvalidParameterValueException("IPv6 prefix must be /64 or less"); } List existingPrefixes = dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); for (DataCenterGuestIpv6PrefixVO existingPrefix : existingPrefixes) { From b3292219d1fee72e8e52b7af124a5616065df888 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 17 Dec 2021 16:34:29 +0530 Subject: [PATCH 017/109] ui: fix add ipv6 prefix labels, message Signed-off-by: Abhishek Kumar --- ui/public/locales/en.json | 2 ++ ui/src/views/infra/network/IpRangesTabGuest.vue | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index f63c78083bbe..fd94d295ee6f 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -2611,6 +2611,7 @@ "message.add.ip.range.direct.network": "Add an IP range to direct network in zone ", "message.add.ip.range.to.pod": "

Add an IP range to pod:

", "message.add.iprange.processing": "Adding IP Range...", +"message.add.ip.v6.prefix.processing": "Adding IPv6 Prefix...", "message.add.load.balancer": "Add a load balancer to zone", "message.add.load.balancer.under.ip": "The load balancer rule has been added under IP:", "message.add.network": "Add a new network for zone: ", @@ -3268,6 +3269,7 @@ "message.success.add.firewall.rule": "Successfully added new Firewall rule", "message.success.add.guest.network": "Successfully created guest network", "message.success.add.iprange": "Successfully added IP Range", +"message.success.add.ip.v6.prefix": "Successfully added IPv6 Prefix", "message.success.add.kuberversion": "Successfully added Kubernetes version", "message.success.add.network": "Successfully added network", "message.success.add.network.acl": "Successfully added Network ACL List", diff --git a/ui/src/views/infra/network/IpRangesTabGuest.vue b/ui/src/views/infra/network/IpRangesTabGuest.vue index 53cbed511045..f588ca24623d 100644 --- a/ui/src/views/infra/network/IpRangesTabGuest.vue +++ b/ui/src/views/infra/network/IpRangesTabGuest.vue @@ -284,9 +284,9 @@ export default { api('createGuestNetworkIpv6Prefix', params).then(response => { this.$pollJob({ jobId: response.createguestnetworkipv6prefixresponse.jobid, - title: this.$t('label.add.ip.range'), + title: this.$t('label.add.ip.v6.prefix'), description: values.pod, - successMessage: this.$t('message.success.add.iprange'), + successMessage: this.$t('message.success.add.ip.v6.prefix'), successMethod: () => { this.componentLoading = false this.fetchData() @@ -296,7 +296,7 @@ export default { this.componentLoading = false this.fetchData() }, - loadingMessage: this.$t('message.add.iprange.processing'), + loadingMessage: this.$t('message.add.ip.v6.prefix.processing'), catchMessage: this.$t('error.fetching.async.job.result'), catchMethod: () => { this.componentLoading = false From d430dd8e726846a067f0be2e14b1e2566ce63a69 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 17 Dec 2021 16:50:06 +0530 Subject: [PATCH 018/109] ui: label fix Signed-off-by: Abhishek Kumar --- ui/public/locales/en.json | 1 + ui/src/config/section/network.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index fd94d295ee6f..bbd2bd1974c3 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1156,6 +1156,7 @@ "label.ip.range.type": "IP Range Type", "label.ip.v4": "IPv4", "label.ip.v6": "IPv6", +"label.ip.v6.firewall": "IPv6 Firewall", "label.ip.allocations": "IP Allocations", "label.ip.or.fqdn": "IP or FQDN", "label.ip.range": "IP Range", diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index b29aa2e2710d..e67c18d13d0c 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -59,7 +59,7 @@ export default { component: () => import('@/views/network/EgressRulesTab.vue'), show: (record) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listEgressFirewallRules' in store.getters.apis } }, { - name: 'ipv6.firewall', + name: 'ip.v6.firewall', component: () => import('@/views/network/Ipv6FirewallRulesTab.vue'), show: (record) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listIpv6FirewallRules' in store.getters.apis } }, { From 98b27388083bec0844c6813d9b7ffe25dbcb03e4 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Mon, 20 Dec 2021 12:36:11 +0530 Subject: [PATCH 019/109] logging fix Signed-off-by: Abhishek Kumar --- .../java/com/cloud/network/Ipv6Service.java | 2 +- .../apache/cloudstack/api/ApiConstants.java | 3 +- .../api/response/NetworkResponse.java | 56 +++++++-- .../java/com/cloud/api/ApiResponseHelper.java | 9 +- .../ConfigurationManagerImpl.java | 5 +- .../com/cloud/network/Ipv6ServiceImpl.java | 107 ++++++++++++------ ui/public/locales/en.json | 3 + ui/src/components/view/DetailsTab.vue | 5 + ui/src/config/section/network.js | 2 +- 9 files changed, 142 insertions(+), 50 deletions(-) diff --git a/api/src/main/java/com/cloud/network/Ipv6Service.java b/api/src/main/java/com/cloud/network/Ipv6Service.java index 532d82b457b4..fc38cbfbd969 100644 --- a/api/src/main/java/com/cloud/network/Ipv6Service.java +++ b/api/src/main/java/com/cloud/network/Ipv6Service.java @@ -32,7 +32,7 @@ public interface Ipv6Service extends PluggableService { - public static final String IPV6_CIDR_SUFFIX = "/64"; + public static final int IPV6_GUEST_SUBNET_NETMASK = 64; Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws ResourceAllocationException; diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index e1c559844c0a..0f907f25d54b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -105,6 +105,7 @@ public class ApiConstants { public static final String HYPERVISOR_SNAPSHOT_RESERVE = "hypervisorsnapshotreserve"; public static final String DATADISK_OFFERING_LIST = "datadiskofferinglist"; public static final String DESCRIPTION = "description"; + public static final String DESTINATION = "destination"; public static final String DESTINATION_ZONE_ID = "destzoneid"; public static final String DETAILS = "details"; public static final String DEVICE_ID = "deviceid"; @@ -579,7 +580,7 @@ public class ApiConstants { public static final String IP6_RANGE = "ip6range"; public static final String IPV6_FIREWALL = "ip6firewall"; public static final String IPV6_ROUTING = "ip6routing"; - public static final String IPV6_ROUTING_MESSAGE = "ip6routingmessage"; + public static final String IPV6_ROUTES = "ip6routes"; public static final String SPECIFY_IP_RANGES = "specifyipranges"; public static final String IS_SOURCE_NAT = "issourcenat"; public static final String IS_STATIC_NAT = "isstaticnat"; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java index a3263b0f47af..271083591b17 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java @@ -17,12 +17,14 @@ package org.apache.cloudstack.api.response; import java.util.Date; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.BaseResponseWithAnnotations; import org.apache.cloudstack.api.EntityReference; @@ -267,17 +269,21 @@ public class NetworkResponse extends BaseResponseWithAnnotations implements Cont @Param(description = "The internet protocol of network offering") private String internetProtocol; + @SerializedName(ApiConstants.IPV6_FIREWALL) + @Param(description = "Whether enable firewall for IPv6 in isolated networks or VPCs", since = "4.17.0") + private Boolean ipv6Firewall; + @SerializedName(ApiConstants.IPV6_ROUTING) - @Param(description = "The routing mode of network offering") + @Param(description = "The routing mode of network offering", since = "4.17.0") private String ipv6Routing; - @SerializedName(ApiConstants.IPV6_ROUTING) - @Param(description = "The routing message for the network to ease adding route in upstream router") - private String ipv6RoutingMessage; + @SerializedName(ApiConstants.IPV6_ROUTES) + @Param(description = "The routes for the network to ease adding route in upstream router", since = "4.17.0") + private Set ipv6Routes; - @SerializedName(ApiConstants.IPV6_FIREWALL) - @Param(description = "Whether enable firewall for IPv6 in isolated networks or VPCs") - private Boolean ipv6Firewall; + public NetworkResponse() { + this.ipv6Routes = new LinkedHashSet(); + } public Boolean getDisplayNetwork() { return displayNetwork; @@ -557,7 +563,39 @@ public void setIpv6Routing(String ipv6Routing) { this.ipv6Routing = ipv6Routing; } - public void setIpv6RoutingMessage(String ipv6RoutingMessage) { - this.ipv6RoutingMessage = ipv6RoutingMessage; + public void addIpv6Route(Ipv6Route ipv6Route) { + this.ipv6Routes.add(ipv6Route); + } + + public static class Ipv6Route extends BaseResponse { + + @SerializedName(ApiConstants.SOURCE) + @Param(description = "the source IPv6 guest cidr for route") + private String source; + + @SerializedName(ApiConstants.DESTINATION) + @Param(description = "the destination outbound IPv6 address for route") + private String destination; + + public Ipv6Route(String source, String destination) { + this.source = source; + this.destination = destination; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getDestination() { + return destination; + } + + public void setDestination(String destination) { + this.destination = destination; + } } } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 519eb4aec51e..484e4230283e 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -255,6 +255,7 @@ import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PhysicalNetworkTrafficType; +import com.cloud.network.PublicIpv6AddressNetworkMapVO; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.RouterHealthCheckResult; import com.cloud.network.Site2SiteCustomerGateway; @@ -277,6 +278,7 @@ import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.dao.PublicIpv6AddressNetworkMapDao; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRuleVO; @@ -423,6 +425,8 @@ public class ApiResponseHelper implements ResponseGenerator { @Inject NetworkOfferingDao networkOfferingDao; @Inject + PublicIpv6AddressNetworkMapDao publicIpv6AddressNetworkMapDao; + @Inject DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao; @Override @@ -2525,8 +2529,9 @@ public NetworkResponse createNetworkResponse(ResponseView view, Network network) response.setIpv6Routing("Static"); response.setIpv6Firewall(networkOfferingDao.isIpv6FirewallEnabled(network.getNetworkOfferingId())); if (Network.GuestType.Isolated.equals(networkOffering.getGuestType())) { - - response.setIpv6RoutingMessage(String.format("Add route in upstream router")); + PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.findByNetworkId(network.getId()); + NetworkResponse.Ipv6Route route = new NetworkResponse.Ipv6Route(network.getIp6Cidr(), ipv6AddressNetworkMaps.getIp6Address()); + response.addIpv6Route(route); } } diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index f1fe620c9e38..b5bc1deba20c 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -183,6 +183,7 @@ import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMapVO; import com.cloud.network.IpAddress; import com.cloud.network.IpAddressManager; +import com.cloud.network.Ipv6Service; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; @@ -1765,8 +1766,8 @@ public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(final CreateGue } final String prefix = cmd.getPrefix(); IPv6Network prefixNet = IPv6Network.fromString(prefix); - if (prefixNet.getNetmask().asPrefixLength() > 64) { - throw new InvalidParameterValueException("IPv6 prefix must be /64 or less"); + if (prefixNet.getNetmask().asPrefixLength() > Ipv6Service.IPV6_GUEST_SUBNET_NETMASK) { + throw new InvalidParameterValueException(String.format("IPv6 prefix must be /%d or less", Ipv6Service.IPV6_GUEST_SUBNET_NETMASK)); } List existingPrefixes = dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); for (DataCenterGuestIpv6PrefixVO existingPrefix : existingPrefixes) { diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java index e32264918337..d6bc5422a409 100644 --- a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java @@ -47,11 +47,12 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PublicIpv6AddressNetworkMapDao; import com.cloud.network.firewall.FirewallService; import com.cloud.network.rules.FirewallRule; import com.cloud.offerings.dao.NetworkOfferingDao; -import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentLifecycleBase; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -69,6 +70,8 @@ public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Servi ScheduledExecutorService _ipv6GuestPrefixSubnetNetworkMapStateScanner; + ScheduledExecutorService _ipv6GuestNetworkRoutesLogger; + @Inject NetworkOfferingDao networkOfferingDao; @Inject @@ -80,11 +83,11 @@ public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Servi @Inject PublicIpv6AddressNetworkMapDao publicIpv6AddressNetworkMapDao; @Inject - NetworkOfferingDetailsDao _networkOfferingDetailsDao; + FirewallRulesDao firewallDao; @Inject - FirewallRulesDao _firewallDao; + FirewallService firewallService; @Inject - public FirewallService _firewallService; + NetworkDao networkDao; private IPv6AddressRange getIpv6AddressRangeFromIpv6Vlan(VlanVO vlanVO) { String[] rangeArr = vlanVO.getIp6Range().split("-"); @@ -112,6 +115,7 @@ protected void releaseIpv6Subnet(long subnetId) { @Override public boolean start() { _ipv6GuestPrefixSubnetNetworkMapStateScanner.scheduleWithFixedDelay(new Ipv6GuestPrefixSubnetNetworkMapStateScanner(), 300, 30*60, TimeUnit.SECONDS); + _ipv6GuestNetworkRoutesLogger.scheduleWithFixedDelay(new Ipv6GuestNetworkRoutesLogger(), 2*60, 60, TimeUnit.SECONDS); return true; } @@ -119,7 +123,8 @@ public boolean start() { public boolean configure(String name, Map params) throws ConfigurationException { _name = name; _configParams = params; - _ipv6GuestPrefixSubnetNetworkMapStateScanner = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Kubernetes-Cluster-State-Scanner")); + _ipv6GuestPrefixSubnetNetworkMapStateScanner = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Ipv6GuestPrefixSubnet-State-Scanner")); + _ipv6GuestNetworkRoutesLogger = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Ipv6GuestNetwork-Routes-Logger")); return true; } @@ -147,7 +152,7 @@ public Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws Ipv6GuestPrefixSubnetNetworkMapVO last = ipv6GuestPrefixSubnetNetworkMapDao.findLast(prefix.getId()); String lastUsedSubnet = last != null ? last.getSubnet() : null; final IPv6Network ip6Prefix = IPv6Network.fromString(prefix.getPrefix()); - Iterator splits = ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(64)); + Iterator splits = ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(IPV6_GUEST_SUBNET_NETMASK)); if (splits.hasNext()) { splits.next(); } @@ -281,6 +286,37 @@ public void releasePublicIpv6ForNetwork(long networkId) { } } + public FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd) { + // TODO + return firewallDao.findById(updateIpv6FirewallRuleCmd.getId()); + } + + @Override + public Pair, Integer> listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd) { + return firewallService.listFirewallRules(listIpv6FirewallRulesCmd); + } + + @Override + public boolean revokeIpv6FirewallRule(Long id) { + // TODO + return true; + } + + @Override + public FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd createIpv6FirewallRuleCmd) { + return null; + } + + @Override + public FirewallRule getIpv6FirewallRule(Long entityId) { + return firewallDao.findById(entityId); + } + + @Override + public boolean applyIpv6FirewallRule(long id) { + return false; + } + public class Ipv6GuestPrefixSubnetNetworkMapStateScanner extends ManagedContextRunnable { @Override protected void runInContext() { @@ -320,34 +356,37 @@ public void reallyRun() { } } - public FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd) { - // TODO - return _firewallDao.findById(updateIpv6FirewallRuleCmd.getId()); - } - - @Override - public Pair, Integer> listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd) { - return _firewallService.listFirewallRules(listIpv6FirewallRulesCmd); - } - - @Override - public boolean revokeIpv6FirewallRule(Long id) { - // TODO - return true; - } - - @Override - public FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd createIpv6FirewallRuleCmd) { - return null; - } - - @Override - public FirewallRule getIpv6FirewallRule(Long entityId) { - return _firewallDao.findById(entityId); - } + public class Ipv6GuestNetworkRoutesLogger extends ManagedContextRunnable { + @Override + protected void runInContext() { + GlobalLock gcLock = GlobalLock.getInternLock("Ipv6GuestPrefixSubnetNetworkMap.State.Scanner.Lock"); + try { + if (gcLock.lock(3)) { + try { + reallyRun(); + } finally { + gcLock.unlock(); + } + } + } finally { + gcLock.releaseRef(); + } + } - @Override - public boolean applyIpv6FirewallRule(long id) { - return false; + public void reallyRun() { + try { + List isolatedNetworks = networkDao.listByGuestType(Network.GuestType.Isolated); + for (NetworkVO network : isolatedNetworks) { + if (Network.State.Implemented.equals(network.getState()) && networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId())) { + PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.findByNetworkId(network.getId()); + if (ipv6AddressNetworkMap != null && s_logger.isInfoEnabled()) { + s_logger.info(String.format("Add upstream IPv6 route for %s via: %s", network.getIp6Cidr(), ipv6AddressNetworkMap.getIp6Address())); + } + } + } + } catch (Exception e) { + s_logger.warn("Caught exception while logging IPv6 guest network routes: ", e); + } + } } } diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index bbd2bd1974c3..e1e288fad0e4 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1153,6 +1153,9 @@ "label.invite.to": "Invite to", "label.invited.accounts": "Invited accounts", "label.ip": "IP Address", +"label.ip6firewall": "IPv6 Firewall", +"label.ip6routes": "IPv6 Routes", +"label.ip6routing": "IPv6 Routing", "label.ip.range.type": "IP Range Type", "label.ip.v4": "IPv4", "label.ip.v6": "IPv6", diff --git a/ui/src/components/view/DetailsTab.vue b/ui/src/components/view/DetailsTab.vue index 14508baaa5cc..634551e126b7 100644 --- a/ui/src/components/view/DetailsTab.vue +++ b/ui/src/components/view/DetailsTab.vue @@ -38,6 +38,11 @@ {{ resource.rootdisksize }} GB
+
+
+ {{ 'Add upstream IPv6 route for ' + route.source + ' via ' + route.destination }} +
+
{{ $t(resource[item].toLowerCase()) }} {{ resource[item] }} diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index e67c18d13d0c..9fa38c33ea6a 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -38,7 +38,7 @@ export default { return fields }, details: () => { - var fields = ['name', 'id', 'description', 'type', 'traffictype', 'vpcid', 'vlan', 'broadcasturi', 'cidr', 'ip6cidr', 'netmask', 'gateway', 'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 'redundantrouter', 'networkdomain', 'zonename', 'account', 'domain'] + var fields = ['name', 'id', 'description', 'type', 'traffictype', 'vpcid', 'vlan', 'broadcasturi', 'cidr', 'ip6cidr', 'netmask', 'gateway', 'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 'redundantrouter', 'networkdomain', 'zonename', 'account', 'domain', 'ip6firewall', 'ip6routing', 'ip6routes'] if (!isAdmin()) { fields = fields.filter(function (e) { return e !== 'broadcasturi' }) } From 178119c6d88d981ad469eb73259f22b04ef00cb2 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Mon, 20 Dec 2021 15:26:07 +0530 Subject: [PATCH 020/109] test fix Signed-off-by: Abhishek Kumar --- server/src/test/resources/createNetworkOffering.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/test/resources/createNetworkOffering.xml b/server/src/test/resources/createNetworkOffering.xml index a728f656c622..4a5eeb9bae45 100644 --- a/server/src/test/resources/createNetworkOffering.xml +++ b/server/src/test/resources/createNetworkOffering.xml @@ -42,6 +42,7 @@ + From 5eac72dd628aa28da5d5d1caf3228310a0cb3401 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 22 Dec 2021 12:41:29 +0530 Subject: [PATCH 021/109] changes Signed-off-by: Abhishek Kumar --- .../java/com/cloud/network/Ipv6Service.java | 6 +- .../network/PublicIpv6AddressNetworkMap.java | 2 + .../apache/cloudstack/api/ApiConstants.java | 1 + .../network/CreateNetworkOfferingCmd.java | 2 +- .../api/response/NetworkResponse.java | 34 ++-- .../orchestration/NetworkOrchestrator.java | 8 + .../src/main/java/com/cloud/dc/VlanVO.java | 2 +- .../PublicIpv6AddressNetworkMapVO.java | 15 +- ...pv6GuestPrefixSubnetNetworkMapDaoImpl.java | 10 +- .../java/com/cloud/network/dao/NetworkVO.java | 4 +- .../dao/PublicIpv6AddressNetworkMapDao.java | 5 +- .../PublicIpv6AddressNetworkMapDaoImpl.java | 25 ++- .../META-INF/db/schema-41610to41700.sql | 1 + .../java/com/cloud/api/ApiResponseHelper.java | 8 +- .../com/cloud/network/Ipv6ServiceImpl.java | 162 ++++++++++++------ .../com/cloud/network/NetworkServiceImpl.java | 5 + .../network/router/CommandSetupHelper.java | 17 +- ui/public/locales/en.json | 2 +- ui/src/components/view/DetailsTab.vue | 3 +- .../views/infra/network/IpRangesTabPublic.vue | 6 +- ui/src/views/offering/AddNetworkOffering.vue | 5 +- 21 files changed, 217 insertions(+), 106 deletions(-) diff --git a/api/src/main/java/com/cloud/network/Ipv6Service.java b/api/src/main/java/com/cloud/network/Ipv6Service.java index fc38cbfbd969..ca3402f96830 100644 --- a/api/src/main/java/com/cloud/network/Ipv6Service.java +++ b/api/src/main/java/com/cloud/network/Ipv6Service.java @@ -40,12 +40,16 @@ public interface Ipv6Service extends PluggableService { void releaseIpv6SubnetForNetwork(long networkId); - Pair assignPublicIpv6ToNetwork(Network network); + Pair checkExistingOrAssignPublicIpv6ToNetwork(Network network, String nicMacAddress); void updateNicIpv6(NicProfile nic, DataCenter dc, Network network); void releasePublicIpv6ForNetwork(long networkId); + void releasePublicIpv6ForNic(long networkId, String nicMacAddress); + + void releaseUnusedPublicIpv6ForNetwork(Network network); + FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd); Pair,Integer> listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd); diff --git a/api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java b/api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java index 0df9115478ea..83a3efb139c5 100644 --- a/api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java +++ b/api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java @@ -32,5 +32,7 @@ enum State { Long getNetworkId(); + String getNicMacAddress(); + PublicIpv6AddressNetworkMap.State getState(); } diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 0f907f25d54b..28d498a03f50 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -365,6 +365,7 @@ public class ApiConstants { public static final String STORAGE_POLICY = "storagepolicy"; public static final String STORAGE_MOTION_ENABLED = "storagemotionenabled"; public static final String STORAGE_CAPABILITIES = "storagecapabilities"; + public static final String SUBNET = "subnet"; public static final String OWNER = "owner"; public static final String SWAP_OWNER = "swapowner"; public static final String SYSTEM_VM_TYPE = "systemvmtype"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index 3d2f7b0c6fcb..77108419d0d2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -94,7 +94,7 @@ public class CreateNetworkOfferingCmd extends BaseCmd { @Parameter(name = ApiConstants.INTERNET_PROTOCOL, type = CommandType.STRING, - description = "The internet protocol of network offering. Options are ipv4, ipv6 and dualstack. Default is ipv4", + description = "The internet protocol of network offering. Options are ip4 and dualstack. Default is IPv4. dualstack will create a network offering that supports both IPv4 and IPv6", since = "4.17.0") private String internetProtocol; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java index 271083591b17..b34ff39b3597 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java @@ -569,33 +569,33 @@ public void addIpv6Route(Ipv6Route ipv6Route) { public static class Ipv6Route extends BaseResponse { - @SerializedName(ApiConstants.SOURCE) - @Param(description = "the source IPv6 guest cidr for route") - private String source; + @SerializedName(ApiConstants.SUBNET) + @Param(description = "the guest IPv6 cidr for route") + private String subnet; - @SerializedName(ApiConstants.DESTINATION) - @Param(description = "the destination outbound IPv6 address for route") - private String destination; + @SerializedName(ApiConstants.GATEWAY) + @Param(description = "the outbound IPv6 gateway") + private String gateway; - public Ipv6Route(String source, String destination) { - this.source = source; - this.destination = destination; + public Ipv6Route(String subnet, String gateway) { + this.subnet = subnet; + this.gateway = gateway; } - public String getSource() { - return source; + public String getSubnet() { + return subnet; } - public void setSource(String source) { - this.source = source; + public void setSubnet(String subnet) { + this.subnet = subnet; } - public String getDestination() { - return destination; + public String getGateway() { + return gateway; } - public void setDestination(String destination) { - this.destination = destination; + public void setGateway(String gateway) { + this.gateway = gateway; } } } diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 10351c533b0d..b210c17ba07a 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2345,6 +2345,14 @@ && isDhcpAccrossMultipleSubnetsSupported(dhcpServiceProvider)) { } s_logger.debug("Removed nic id=" + nic.getId()); + // release assigned IPv6 for Isolated Network VR NIC + + if (Type.DomainRouter.equals(vm.getType()) + && TrafficType.Guest.equals(network.getTrafficType()) + && GuestType.Isolated.equals(network.getGuestType())) { + ipv6Service.releasePublicIpv6ForNic(nic.getNetworkId(), nic.getMacAddress()); + } + //remove the secondary ip addresses corresponding to to this nic if (!removeVmSecondaryIpsOfNic(nic.getId())) { s_logger.debug("Removing nic " + nic.getId() + " secondary ip addreses failed"); diff --git a/engine/schema/src/main/java/com/cloud/dc/VlanVO.java b/engine/schema/src/main/java/com/cloud/dc/VlanVO.java index 20b07e983b86..7423ded598f3 100644 --- a/engine/schema/src/main/java/com/cloud/dc/VlanVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/VlanVO.java @@ -205,8 +205,8 @@ public String toString() { .append("|") .append(ipRange) .append("|") - .append("|") .append(ip6Range) + .append("|") .append(networkId) .append("]") .toString(); diff --git a/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java b/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java index 28e190a2520c..706064502ff1 100644 --- a/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java +++ b/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java @@ -50,6 +50,9 @@ public class PublicIpv6AddressNetworkMapVO implements PublicIpv6AddressNetworkMa @Column(name = "network_id") private Long networkId; + @Column(name = "nic_mac_address") + private String nicMacAddress; + @Column(name = "state") private PublicIpv6AddressNetworkMap.State state; @@ -63,10 +66,11 @@ protected PublicIpv6AddressNetworkMapVO() { uuid = UUID.randomUUID().toString(); } - protected PublicIpv6AddressNetworkMapVO(long rangeId, String ip6Address, Long networkId, PublicIpv6AddressNetworkMap.State state) { + protected PublicIpv6AddressNetworkMapVO(long rangeId, String ip6Address, Long networkId, String nicMacAddress, State state) { this.rangeId = rangeId; this.ip6Address = ip6Address; this.networkId = networkId; + this.nicMacAddress = nicMacAddress; this.state = state; uuid = UUID.randomUUID().toString(); } @@ -101,6 +105,15 @@ public void setNetworkId(Long networkId) { this.networkId = networkId; } + @Override + public String getNicMacAddress() { + return nicMacAddress; + } + + public void setNicMacAddress(String nicMacAddress) { + this.nicMacAddress = nicMacAddress; + } + @Override public State getState() { return state; diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java index 515368b32473..89780b885944 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java @@ -27,6 +27,7 @@ import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMap; import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMapVO; import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @@ -66,15 +67,18 @@ public Ipv6GuestPrefixSubnetNetworkMapVO findFirstAvailable(long prefixId) { SearchCriteria sc = FreeSubnetSearch.create(); sc.setParameters("prefixId", prefixId); sc.setParameters("state", Ipv6GuestPrefixSubnetNetworkMap.State.Free); - return findOneBy(sc); + Filter searchFilter = new Filter(Ipv6GuestPrefixSubnetNetworkMapVO.class, "id", true, null, 1L); + List list = listBy(sc, searchFilter); + return CollectionUtils.isNotEmpty(list) ? list.get(0) : null; } @Override public Ipv6GuestPrefixSubnetNetworkMapVO findLast(long prefixId) { SearchCriteria sc = PrefixIdSearch.create(); sc.setParameters("prefixId", prefixId); - List list = listBy(sc); - return CollectionUtils.isNotEmpty(list) ? list.get(list.size() - 1) : null; + Filter searchFilter = new Filter(Ipv6GuestPrefixSubnetNetworkMapVO.class, "id", false, null, 1L); + List list = listBy(sc, searchFilter); + return CollectionUtils.isNotEmpty(list) ? list.get(0) : null; } @Override diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java index 790b4845bb3a..4dbcda670a7a 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java @@ -549,9 +549,7 @@ public boolean equals(Object obj) { @Override public String toString() { - StringBuilder buf = new StringBuilder("Ntwk["); - buf.append(id).append("|").append(trafficType).append("|").append(networkOfferingId).append("]"); - return buf.toString(); + return String.format("Network {\"id\": %s, \"name\": \"%s\", \"uuid\": \"%s\", \"networkofferingid\": %d}", id, name, uuid, networkOfferingId); } @Override diff --git a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java index 1d32026dd305..163f28576054 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java @@ -17,11 +17,14 @@ package com.cloud.network.dao; +import java.util.List; + import com.cloud.network.PublicIpv6AddressNetworkMapVO; import com.cloud.utils.db.GenericDao; public interface PublicIpv6AddressNetworkMapDao extends GenericDao { PublicIpv6AddressNetworkMapVO findFirstAvailable(long rangeId); PublicIpv6AddressNetworkMapVO findLast(long rangeId); - PublicIpv6AddressNetworkMapVO findByNetworkId(long networkId); + List listByNetworkId(long networkId); + PublicIpv6AddressNetworkMapVO findByNetworkIdAndNicMacAddress(long networkId, String macAddress); } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java index 485abc3a73b1..0cf7c0634712 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java @@ -27,6 +27,7 @@ import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMap; import com.cloud.network.PublicIpv6AddressNetworkMapVO; import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @@ -38,6 +39,7 @@ public class PublicIpv6AddressNetworkMapDaoImpl extends GenericDaoBase FreeAddressSearch; protected SearchBuilder RangeIdSearch; protected SearchBuilder NetworkIdSearch; + protected SearchBuilder NetworkIdNicMacAddressSearch; @PostConstruct public void init() { @@ -51,6 +53,10 @@ public void init() { NetworkIdSearch = createSearchBuilder(); NetworkIdSearch.and("networkId", NetworkIdSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); NetworkIdSearch.done(); + NetworkIdNicMacAddressSearch = createSearchBuilder(); + NetworkIdNicMacAddressSearch.and("networkId", NetworkIdNicMacAddressSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); + NetworkIdNicMacAddressSearch.and("nicMacAddress", NetworkIdNicMacAddressSearch.entity().getNicMacAddress(), SearchCriteria.Op.EQ); + NetworkIdNicMacAddressSearch.done(); } @Override @@ -58,21 +64,32 @@ public PublicIpv6AddressNetworkMapVO findFirstAvailable(long prefixId) { SearchCriteria sc = FreeAddressSearch.create(); sc.setParameters("prefixId", prefixId); sc.setParameters("state", Ipv6GuestPrefixSubnetNetworkMap.State.Free); - return findOneBy(sc); + Filter searchFilter = new Filter(PublicIpv6AddressNetworkMapVO.class, "id", true, null, 1L); + List list = listBy(sc, searchFilter); + return CollectionUtils.isNotEmpty(list) ? list.get(0) : null; } @Override public PublicIpv6AddressNetworkMapVO findLast(long prefixId) { SearchCriteria sc = RangeIdSearch.create(); sc.setParameters("prefixId", prefixId); - List list = listBy(sc); - return CollectionUtils.isNotEmpty(list) ? list.get(list.size() - 1) : null; + Filter searchFilter = new Filter(PublicIpv6AddressNetworkMapVO.class, "id", false, null, 1L); + List list = listBy(sc, searchFilter); + return CollectionUtils.isNotEmpty(list) ? list.get(0) : null; } @Override - public PublicIpv6AddressNetworkMapVO findByNetworkId(long networkId) { + public List listByNetworkId(long networkId) { SearchCriteria sc = NetworkIdSearch.create(); sc.setParameters("networkId", networkId); + return listBy(sc); + } + + @Override + public PublicIpv6AddressNetworkMapVO findByNetworkIdAndNicMacAddress(long networkId, String nicMacAddress) { + SearchCriteria sc = NetworkIdNicMacAddressSearch.create(); + sc.setParameters("networkId", networkId); + sc.setParameters("nicMacAddress", nicMacAddress); return findOneBy(sc); } } \ No newline at end of file diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql index adda9a57fbdb..e26c69bb3640 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql @@ -59,6 +59,7 @@ CREATE TABLE `cloud`.`public_ip6_address_network_map` ( `vlan_db_id` bigint(20) unsigned NOT NULL COMMENT 'id of the vlan to which this address belong to', `public_ip_address` varchar(255) NOT NULL COMMENT 'ipv6 address', `network_id` bigint(20) unsigned DEFAULT NULL COMMENT 'network to which this address is associated to', + `nic_mac_address` varchar(17) DEFAULT NULL COMMENT 'mac address of the nic to which this address is assigned to', `state` varchar(255) NOT NULL COMMENT 'state of the address', `created` datetime default NULL, `removed` datetime default NULL, diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 484e4230283e..8c9a39298861 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -2529,9 +2529,11 @@ public NetworkResponse createNetworkResponse(ResponseView view, Network network) response.setIpv6Routing("Static"); response.setIpv6Firewall(networkOfferingDao.isIpv6FirewallEnabled(network.getNetworkOfferingId())); if (Network.GuestType.Isolated.equals(networkOffering.getGuestType())) { - PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.findByNetworkId(network.getId()); - NetworkResponse.Ipv6Route route = new NetworkResponse.Ipv6Route(network.getIp6Cidr(), ipv6AddressNetworkMaps.getIp6Address()); - response.addIpv6Route(route); + List ipv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(network.getId()); + for (PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap : ipv6AddressNetworkMaps) { + NetworkResponse.Ipv6Route route = new NetworkResponse.Ipv6Route(network.getIp6Cidr(), ipv6AddressNetworkMap.getIp6Address()); + response.addIpv6Route(route); + } } } diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java index d6bc5422a409..b3f3e9a33441 100644 --- a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java @@ -35,6 +35,7 @@ import org.apache.cloudstack.api.command.user.ipv6.UpdateIpv6FirewallRuleCmd; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import com.cloud.configuration.Resource; @@ -59,6 +60,7 @@ import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicProfile; +import com.cloud.vm.dao.NicDao; import com.googlecode.ipv6.IPv6Address; import com.googlecode.ipv6.IPv6AddressRange; import com.googlecode.ipv6.IPv6Network; @@ -88,6 +90,8 @@ public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Servi FirewallService firewallService; @Inject NetworkDao networkDao; + @Inject + NicDao nicDao; private IPv6AddressRange getIpv6AddressRangeFromIpv6Vlan(VlanVO vlanVO) { String[] rangeArr = vlanVO.getIp6Range().split("-"); @@ -104,6 +108,16 @@ private IPv6AddressRange getIpv6AddressRangeFromIpv6Vlan(VlanVO vlanVO) { return range; } + private void releasePublicIpv6(PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap) { + if (publicIpv6AddressNetworkMap != null) { + publicIpv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(publicIpv6AddressNetworkMap.getId()); + publicIpv6AddressNetworkMap.setState(PublicIpv6AddressNetworkMap.State.Free); + publicIpv6AddressNetworkMap.setNetworkId(null); + publicIpv6AddressNetworkMap.setNicMacAddress(null); + publicIpv6AddressNetworkMapDao.update(publicIpv6AddressNetworkMap.getId(), publicIpv6AddressNetworkMap); + } + } + protected void releaseIpv6Subnet(long subnetId) { Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO = ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(subnetId); ipv6GuestPrefixSubnetNetworkMapVO.setState(Ipv6GuestPrefixSubnetNetworkMap.State.Free); @@ -112,6 +126,57 @@ protected void releaseIpv6Subnet(long subnetId) { ipv6GuestPrefixSubnetNetworkMapDao.update(ipv6GuestPrefixSubnetNetworkMapVO.getId(), ipv6GuestPrefixSubnetNetworkMapVO); } + private Pair assignPublicIpv6ToNetwork(Network network, String nicMacAddress) { + PublicIpv6AddressNetworkMapVO ip6NetworkMap = null; + VlanVO selectedVlan = null; + final List ranges = vlanDao.listVlansWithIpV6RangeByPhysicalNetworkId(network.getPhysicalNetworkId()); + if (ranges == null) { + s_logger.error(String.format("Unable to find IPv6 range for the zone ID: %d", network.getDataCenterId())); + throw new CloudRuntimeException(String.format("Cannot find IPv6 address for network %s", network.getName())); + } + for (VlanVO range : ranges) { + ip6NetworkMap = publicIpv6AddressNetworkMapDao.findFirstAvailable(range.getId()); + if (ip6NetworkMap == null) { + PublicIpv6AddressNetworkMapVO last = publicIpv6AddressNetworkMapDao.findLast(range.getId()); + String lastUsedIp6Address = last != null ? last.getIp6Address() : null; + final IPv6AddressRange ip6Range = getIpv6AddressRangeFromIpv6Vlan(range); + IPv6Address ip = null; + if (ip6Range != null) { + if (lastUsedIp6Address == null) { + ip = ip6Range.getFirst(); + } else { + IPv6Address lastAddress = IPv6Address.fromString(lastUsedIp6Address); + lastAddress = lastAddress.add(1); + if (ip6Range.contains(lastAddress)) { + ip = lastAddress; + } + } + if (ip != null) { + ip6NetworkMap = new PublicIpv6AddressNetworkMapVO(range.getId(), ip.toString(), network.getId(), nicMacAddress, PublicIpv6AddressNetworkMap.State.Allocated); + } + } + } + if (ip6NetworkMap != null) { + selectedVlan = range; + break; + } + } + if (ip6NetworkMap == null) { + s_logger.error(String.format("Unable to find an IPv6 address available for allocation for network %s in zone ID: %d", network.getName(), network.getDataCenterId())); + throw new CloudRuntimeException(String.format("Cannot find available IPv6 address for network %s", network.getName())); + } + if (PublicIpv6AddressNetworkMap.State.Free.equals(ip6NetworkMap.getState())) { + ip6NetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(ip6NetworkMap.getId()); + ip6NetworkMap.setState(PublicIpv6AddressNetworkMap.State.Allocated); + ip6NetworkMap.setNetworkId(network.getId()); + ip6NetworkMap.setNicMacAddress(nicMacAddress); + publicIpv6AddressNetworkMapDao.update(ip6NetworkMap.getId(), ip6NetworkMap); + } else { + publicIpv6AddressNetworkMapDao.persist(ip6NetworkMap); + } + return new Pair<>(ip6NetworkMap, selectedVlan); + } + @Override public boolean start() { _ipv6GuestPrefixSubnetNetworkMapStateScanner.scheduleWithFixedDelay(new Ipv6GuestPrefixSubnetNetworkMapStateScanner(), 300, 30*60, TimeUnit.SECONDS); @@ -206,57 +271,33 @@ public void releaseIpv6SubnetForNetwork(long networkId) { } @Override - public Pair assignPublicIpv6ToNetwork(Network network) { - PublicIpv6AddressNetworkMapVO ip6NetworkMap = null; - VlanVO selectedVlan = null; - final List ranges = vlanDao.listVlansWithIpV6RangeByPhysicalNetworkId(network.getPhysicalNetworkId()); - if (ranges == null) { - s_logger.error(String.format("Unable to find IPv6 range for the zone ID: %d", network.getDataCenterId())); - throw new CloudRuntimeException(String.format("Cannot find IPv6 range for network %s", network.getName())); - } - for (VlanVO range : ranges) { - ip6NetworkMap = publicIpv6AddressNetworkMapDao.findFirstAvailable(range.getId()); - if (ip6NetworkMap == null) { - PublicIpv6AddressNetworkMapVO last = publicIpv6AddressNetworkMapDao.findLast(range.getId()); - String lastUsedIp6Address = last != null ? last.getIp6Address() : null; - final IPv6AddressRange ip6Range = getIpv6AddressRangeFromIpv6Vlan(range); - IPv6Address ip = null; - if (ip6Range != null) { - if (lastUsedIp6Address == null) { - ip = ip6Range.getFirst(); - } else { - IPv6Address lastAddress = IPv6Address.fromString(lastUsedIp6Address); - lastAddress = lastAddress.add(1); - if (ip6Range.contains(lastAddress)) { - ip = lastAddress; - } - } - if (ip != null) { - selectedVlan = range; - ip6NetworkMap = new PublicIpv6AddressNetworkMapVO(range.getId(), ip.toString(), network.getId(), PublicIpv6AddressNetworkMap.State.Allocated); - break; - } + public Pair checkExistingOrAssignPublicIpv6ToNetwork(Network network, String nicMacAddress) { + PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap = null; + List ipv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(network.getId()); + for (PublicIpv6AddressNetworkMapVO map : ipv6AddressNetworkMaps) { + if (StringUtils.isEmpty(map.getNicMacAddress()) || nicMacAddress.equals(map.getNicMacAddress())) { // || nicDao.findByNetworkIdAndMacAddress(network.getId(), nicMacAddress) == null) { + ipv6AddressNetworkMap = map; + if (!nicMacAddress.equals(map.getNicMacAddress())) { + ipv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(ipv6AddressNetworkMap.getId()); + ipv6AddressNetworkMap.setState(PublicIpv6AddressNetworkMap.State.Allocated); + ipv6AddressNetworkMap.setNicMacAddress(nicMacAddress); + publicIpv6AddressNetworkMapDao.update(ipv6AddressNetworkMap.getId(), ipv6AddressNetworkMap); } + break; } } - if (ip6NetworkMap == null) { - s_logger.error(String.format("Unable to find an IPv6 address available for allocation for network %s in zone ID: %d", network.getName(), network.getDataCenterId())); - throw new CloudRuntimeException(String.format("Cannot find available IPv6 address for network %s", network.getName())); + if (ipv6AddressNetworkMap == null) { + return assignPublicIpv6ToNetwork(network, nicMacAddress); } - if (PublicIpv6AddressNetworkMap.State.Free.equals(ip6NetworkMap.getState())) { - ip6NetworkMap.setState(PublicIpv6AddressNetworkMap.State.Allocated); - publicIpv6AddressNetworkMapDao.update(ip6NetworkMap.getId(), ip6NetworkMap); - } else { - publicIpv6AddressNetworkMapDao.persist(ip6NetworkMap); - } - return new Pair<>(ip6NetworkMap, selectedVlan); + Vlan vlan = vlanDao.findById(ipv6AddressNetworkMap.getRangeId()); + return new Pair<>(ipv6AddressNetworkMap, vlan); } @Override public void updateNicIpv6(NicProfile nic, DataCenter dc, Network network) { boolean isIpv6Supported = networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()); if (nic.getIPv6Address() == null && isIpv6Supported) { - Pair publicIpv6AddressNetworkMapVlanPair = assignPublicIpv6ToNetwork(network); + Pair publicIpv6AddressNetworkMapVlanPair = checkExistingOrAssignPublicIpv6ToNetwork(network, nic.getMacAddress()); final PublicIpv6AddressNetworkMap publicIpv6AddressNetworkMapVO = publicIpv6AddressNetworkMapVlanPair.first(); final Vlan vlan = publicIpv6AddressNetworkMapVlanPair.second(); final String routerIpv6 = publicIpv6AddressNetworkMapVO.getIp6Address(); @@ -277,12 +318,30 @@ public void updateNicIpv6(NicProfile nic, DataCenter dc, Network network) { @Override public void releasePublicIpv6ForNetwork(long networkId) { - PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMapVO = publicIpv6AddressNetworkMapDao.findByNetworkId(networkId); - if (publicIpv6AddressNetworkMapVO != null) { - publicIpv6AddressNetworkMapVO = publicIpv6AddressNetworkMapDao.createForUpdate(publicIpv6AddressNetworkMapVO.getId()); - publicIpv6AddressNetworkMapVO.setState(PublicIpv6AddressNetworkMap.State.Free); - publicIpv6AddressNetworkMapVO.setNetworkId(null); - publicIpv6AddressNetworkMapDao.update(publicIpv6AddressNetworkMapVO.getId(), publicIpv6AddressNetworkMapVO); + List publicIpv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(networkId); + for (PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap : publicIpv6AddressNetworkMaps) { + releasePublicIpv6(publicIpv6AddressNetworkMap); + } + } + + @Override + public void releasePublicIpv6ForNic(long networkId, String nicMacAddress) { + PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.findByNetworkIdAndNicMacAddress(networkId, nicMacAddress); + if (publicIpv6AddressNetworkMap != null) { + publicIpv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(publicIpv6AddressNetworkMap.getId()); + publicIpv6AddressNetworkMap.setNicMacAddress(null); + publicIpv6AddressNetworkMapDao.update(publicIpv6AddressNetworkMap.getId(), publicIpv6AddressNetworkMap); + } + } + + @Override + public void releaseUnusedPublicIpv6ForNetwork(Network network) { + List publicIpv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(network.getId()); + for (PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap : publicIpv6AddressNetworkMaps) { + if (StringUtils.isEmpty(publicIpv6AddressNetworkMap.getNicMacAddress()) || + nicDao.findByNetworkIdAndMacAddress(network.getPhysicalNetworkId(), publicIpv6AddressNetworkMap.getNicMacAddress()) == null) { + releasePublicIpv6(publicIpv6AddressNetworkMap); + } } } @@ -378,9 +437,12 @@ public void reallyRun() { List isolatedNetworks = networkDao.listByGuestType(Network.GuestType.Isolated); for (NetworkVO network : isolatedNetworks) { if (Network.State.Implemented.equals(network.getState()) && networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId())) { - PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.findByNetworkId(network.getId()); - if (ipv6AddressNetworkMap != null && s_logger.isInfoEnabled()) { - s_logger.info(String.format("Add upstream IPv6 route for %s via: %s", network.getIp6Cidr(), ipv6AddressNetworkMap.getIp6Address())); + List ipv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(network.getId()); + for (PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap : ipv6AddressNetworkMaps) { + VlanVO vlan = vlanDao.findById(ipv6AddressNetworkMap.getRangeId()); + if (s_logger.isInfoEnabled()) { + s_logger.info(String.format("Add upstream IPv6 route for %s via: %s for network: %s with vlan: %s", network.getIp6Cidr(), ipv6AddressNetworkMap.getIp6Address(), network, vlan)); + } } } } diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index 4741873af98f..ae2776b07e80 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -2073,6 +2073,11 @@ public boolean restartNetwork(Long networkId, boolean cleanup, boolean makeRedun s_logger.warn("Network id=" + networkId + " failed to restart."); } + if (TrafficType.Guest.equals(network.getTrafficType()) + && GuestType.Isolated.equals(network.getGuestType())) { + ipv6Service.releaseUnusedPublicIpv6ForNetwork(network); + } + return success; } diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 0e9caf6ffa46..20d609436bc6 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -1039,7 +1039,7 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute NicVO publicNic = _nicDao.findDefaultNicForVM(router.getId()); if (publicNic != null) { - updateSetupGuestNetworkCommandIpv6(setupCmd, network, publicNic.getMacAddress(), defaultIp6Dns1, defaultIp6Dns2); + updateSetupGuestNetworkCommandIpv6(setupCmd, network, publicNic, defaultIp6Dns1, defaultIp6Dns2); } final String brd = NetUtils.long2Ip(NetUtils.ip2Long(guestNic.getIPv4Address()) | ~NetUtils.ip2Long(guestNic.getIPv4Netmask())); @@ -1058,22 +1058,15 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute return setupCmd; } - private void updateSetupGuestNetworkCommandIpv6(SetupGuestNetworkCommand setupCmd, Network network, String macAddress, String defaultIp6Dns1, String defaultIp6Dns2) { + private void updateSetupGuestNetworkCommandIpv6(SetupGuestNetworkCommand setupCmd, Network network, Nic nic, String defaultIp6Dns1, String defaultIp6Dns2) { boolean isIpv6Supported = _networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()); if (isIpv6Supported) { setupCmd.setDefaultIp6Dns1(defaultIp6Dns1); setupCmd.setDefaultIp6Dns2(defaultIp6Dns2); - PublicIpv6AddressNetworkMap ipv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.findByNetworkId(network.getId()); - Vlan vlan = null; - if (ipv6AddressNetworkMap == null) { - Pair publicIpv6AddressNetworkMapVlanPair = ipv6Service.assignPublicIpv6ToNetwork(network); - ipv6AddressNetworkMap = publicIpv6AddressNetworkMapVlanPair.first(); - vlan = publicIpv6AddressNetworkMapVlanPair.second(); - } + Pair publicIpv6AddressNetworkMapVlanPair = ipv6Service.checkExistingOrAssignPublicIpv6ToNetwork(network, nic.getMacAddress()); + PublicIpv6AddressNetworkMap ipv6AddressNetworkMap = publicIpv6AddressNetworkMapVlanPair.first(); + Vlan vlan = publicIpv6AddressNetworkMapVlanPair.second(); setupCmd.setRouterIpv6(ipv6AddressNetworkMap.getIp6Address()); - if (vlan == null) { - vlan = _vlanDao.findById(ipv6AddressNetworkMap.getRangeId()); - } final String routerIpv6Gateway = vlan.getIp6Gateway(); final String routerIpv6Cidr = vlan.getIp6Cidr(); setupCmd.setRouterIpv6Gateway(routerIpv6Gateway); diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index e1e288fad0e4..a35f7cff9e55 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -859,7 +859,6 @@ "label.dpd": "Dead Peer Detection", "label.drag.new.position": "Drag to new position", "label.driver": "Driver", -"label.dual.stack": "Dual Stack", "label.duration.in.sec": "Duration (in sec)", "label.dynamicscalingenabled": "Dynamic Scaling Enabled", "label.dynamicscalingenabled.tooltip": "VM can dynamically scale only when dynamic scaling is enabled on template, service offering and global setting", @@ -1159,6 +1158,7 @@ "label.ip.range.type": "IP Range Type", "label.ip.v4": "IPv4", "label.ip.v6": "IPv6", +"label.ip.v4.v6": "IPv4 + IPv6 (Dual Stack)", "label.ip.v6.firewall": "IPv6 Firewall", "label.ip.allocations": "IP Allocations", "label.ip.or.fqdn": "IP or FQDN", diff --git a/ui/src/components/view/DetailsTab.vue b/ui/src/components/view/DetailsTab.vue index 634551e126b7..fa7953f273f9 100644 --- a/ui/src/components/view/DetailsTab.vue +++ b/ui/src/components/view/DetailsTab.vue @@ -39,8 +39,9 @@
+ {{ 'Add upstream IPv6 route for:' }}
- {{ 'Add upstream IPv6 route for ' + route.source + ' via ' + route.destination }} + {{ route.subnet + ' via ' + route.gateway }}
diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index c5d2f6d6bb2f..02e707b7fbef 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -224,12 +224,12 @@ + v-decorator="['startipv6', { rules: [{ message: `${$t('label.required')}` }] }]"> + v-decorator="['endipv6', { rules: [{ message: `${$t('label.required')}` }] }]">
@@ -256,7 +256,7 @@
-
+
{{ $t('label.set.reservation') }}
diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue index 21a0086f04af..601247d4421f 100644 --- a/ui/src/views/offering/AddNetworkOffering.vue +++ b/ui/src/views/offering/AddNetworkOffering.vue @@ -83,11 +83,8 @@ {{ $t('label.ip.v4') }} - - {{ $t('label.ip.v6') }} - - {{ $t('label.dual.stack') }} + {{ $t('label.ip.v4.v6') }} From 7663a3c42eaf26d0c55df8fd11c8560e9a4964a5 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 23 Dec 2021 17:29:38 +0530 Subject: [PATCH 022/109] minor ui refactor Signed-off-by: Abhishek Kumar --- ui/src/views/infra/network/IpRangesTabPublic.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index 02e707b7fbef..84bb53255f8f 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -224,12 +224,12 @@ + v-decorator="['startipv6']"> + v-decorator="['endipv6']">
From e66270b7459d82a54025c801b70d650a78b74b46 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 24 Dec 2021 17:13:48 +0530 Subject: [PATCH 023/109] ip6 events Signed-off-by: Abhishek Kumar --- .../main/java/com/cloud/event/EventTypes.java | 15 ++++++-- .../CreateGuestNetworkIpv6PrefixCmd.java | 3 +- .../DeleteGuestNetworkIpv6PrefixCmd.java | 15 ++++++-- .../com/cloud/network/Ipv6ServiceImpl.java | 36 ++++++++++++------- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 47da9de9b36c..10a083ac1ea8 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.usage.Usage; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterGuestIpv6Prefix; import com.cloud.dc.Pod; import com.cloud.dc.StorageNetworkIpRange; import com.cloud.dc.Vlan; @@ -147,6 +148,10 @@ public class EventTypes { public static final String EVENT_FIREWALL_CLOSE = "FIREWALL.CLOSE"; public static final String EVENT_FIREWALL_UPDATE = "FIREWALL.UPDATE"; + public static final String EVENT_NET_IP6_ASSIGN = "NET.IP6ASSIGN"; + public static final String EVENT_NET_IP6_RELEASE = "NET.IP6RELEASE"; + public static final String EVENT_NET_IP6_UPDATE = "NET.IP6UPDATE"; + public static final String EVENT_FIREWALL_EGRESS_OPEN = "FIREWALL.EGRESS.OPEN"; public static final String EVENT_FIREWALL_EGRESS_CLOSE = "FIREWALL.EGRESS.CLOSE"; public static final String EVENT_FIREWALL_EGRESS_UPDATE = "FIREWALL.EGRESS.UPDATE"; @@ -330,8 +335,8 @@ public class EventTypes { public static final String EVENT_MANAGEMENT_IP_RANGE_DELETE = "MANAGEMENT.IP.RANGE.DELETE"; public static final String EVENT_MANAGEMENT_IP_RANGE_UPDATE = "MANAGEMENT.IP.RANGE.UPDATE"; - public static final String EVENT_PUBLIC_IP6_PREFIX_CREATE = "PUBLIC.IP6.PREFIX.CREATE"; - public static final String EVENT_PUBLIC_IP6_PREFIX_DELETE = "PUBLIC.IP6.PREFIX.DELETE"; + public static final String EVENT_GUEST_IP6_PREFIX_CREATE = "GUEST.IP6.PREFIX.CREATE"; + public static final String EVENT_GUEST_IP6_PREFIX_DELETE = "GUEST.IP6.PREFIX.DELETE"; public static final String EVENT_STORAGE_IP_RANGE_CREATE = "STORAGE.IP.RANGE.CREATE"; public static final String EVENT_STORAGE_IP_RANGE_DELETE = "STORAGE.IP.RANGE.DELETE"; @@ -705,6 +710,9 @@ public class EventTypes { entityEventDetails.put(EVENT_FIREWALL_EGRESS_OPEN, FirewallRule.class); entityEventDetails.put(EVENT_FIREWALL_EGRESS_CLOSE, FirewallRule.class); entityEventDetails.put(EVENT_FIREWALL_EGRESS_UPDATE, FirewallRule.class); + entityEventDetails.put(EVENT_NET_IP6_ASSIGN, Network.class); + entityEventDetails.put(EVENT_NET_IP6_RELEASE, Network.class); + entityEventDetails.put(EVENT_NET_IP6_UPDATE, Network.class); // Nic Events entityEventDetails.put(EVENT_NIC_CREATE, Nic.class); @@ -845,6 +853,9 @@ public class EventTypes { entityEventDetails.put(EVENT_MANAGEMENT_IP_RANGE_CREATE, Pod.class); entityEventDetails.put(EVENT_MANAGEMENT_IP_RANGE_DELETE, Pod.class); + entityEventDetails.put(EVENT_GUEST_IP6_PREFIX_CREATE, DataCenterGuestIpv6Prefix.class); + entityEventDetails.put(EVENT_GUEST_IP6_PREFIX_DELETE, DataCenterGuestIpv6Prefix.class); + entityEventDetails.put(EVENT_STORAGE_IP_RANGE_CREATE, StorageNetworkIpRange.class); entityEventDetails.put(EVENT_STORAGE_IP_RANGE_DELETE, StorageNetworkIpRange.class); entityEventDetails.put(EVENT_STORAGE_IP_RANGE_UPDATE, StorageNetworkIpRange.class); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java index 945f9da74c85..2095ee79529f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java @@ -89,9 +89,10 @@ public Long getPodId() { public String getPrefix() { return prefix; } + @Override public String getEventType() { - return EventTypes.EVENT_PUBLIC_IP6_PREFIX_CREATE; + return EventTypes.EVENT_GUEST_IP6_PREFIX_CREATE; } @Override diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6PrefixCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6PrefixCmd.java index ac5534514d6e..830aeac8daef 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6PrefixCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteGuestNetworkIpv6PrefixCmd.java @@ -21,13 +21,14 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DataCenterGuestIpv6PrefixResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.log4j.Logger; +import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; @@ -43,7 +44,7 @@ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin}) -public class DeleteGuestNetworkIpv6PrefixCmd extends BaseCmd { +public class DeleteGuestNetworkIpv6PrefixCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(DeleteGuestNetworkIpv6PrefixCmd.class); public static final String APINAME = "deleteGuestNetworkIpv6Prefix"; @@ -58,6 +59,16 @@ public Long getId() { return id; } + @Override + public String getEventType() { + return EventTypes.EVENT_GUEST_IP6_PREFIX_DELETE; + } + + @Override + public String getEventDescription() { + return "Deleting guest IPv6 prefix " + getId(); + } + @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java index b3f3e9a33441..966a0c3feafb 100644 --- a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java @@ -45,6 +45,8 @@ import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao; import com.cloud.dc.dao.VlanDao; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; import com.cloud.exception.ResourceAllocationException; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; @@ -108,6 +110,15 @@ private IPv6AddressRange getIpv6AddressRangeFromIpv6Vlan(VlanVO vlanVO) { return range; } + protected void releaseIpv6Subnet(long subnetId) { + Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO = ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(subnetId); + ipv6GuestPrefixSubnetNetworkMapVO.setState(Ipv6GuestPrefixSubnetNetworkMap.State.Free); + ipv6GuestPrefixSubnetNetworkMapVO.setNetworkId(null); + ipv6GuestPrefixSubnetNetworkMapVO.setUpdated(new Date()); + ipv6GuestPrefixSubnetNetworkMapDao.update(ipv6GuestPrefixSubnetNetworkMapVO.getId(), ipv6GuestPrefixSubnetNetworkMapVO); + } + + @ActionEvent(eventType = EventTypes.EVENT_NET_IP6_RELEASE, eventDescription = "releasing public IPv6", create = true) private void releasePublicIpv6(PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap) { if (publicIpv6AddressNetworkMap != null) { publicIpv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(publicIpv6AddressNetworkMap.getId()); @@ -118,14 +129,7 @@ private void releasePublicIpv6(PublicIpv6AddressNetworkMapVO publicIpv6AddressNe } } - protected void releaseIpv6Subnet(long subnetId) { - Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO = ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(subnetId); - ipv6GuestPrefixSubnetNetworkMapVO.setState(Ipv6GuestPrefixSubnetNetworkMap.State.Free); - ipv6GuestPrefixSubnetNetworkMapVO.setNetworkId(null); - ipv6GuestPrefixSubnetNetworkMapVO.setUpdated(new Date()); - ipv6GuestPrefixSubnetNetworkMapDao.update(ipv6GuestPrefixSubnetNetworkMapVO.getId(), ipv6GuestPrefixSubnetNetworkMapVO); - } - + @ActionEvent(eventType = EventTypes.EVENT_NET_IP6_ASSIGN, eventDescription = "releasing public IPv6", create = true) private Pair assignPublicIpv6ToNetwork(Network network, String nicMacAddress) { PublicIpv6AddressNetworkMapVO ip6NetworkMap = null; VlanVO selectedVlan = null; @@ -177,6 +181,15 @@ protected void releaseIpv6Subnet(long subnetId) { return new Pair<>(ip6NetworkMap, selectedVlan); } + @ActionEvent(eventType = EventTypes.EVENT_NET_IP6_UPDATE, eventDescription = "releasing public IPv6", create = true) + private PublicIpv6AddressNetworkMapVO updatePublicIpv6NicMacAddress(long id, String nicMacAddress) { + PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(id); + ipv6AddressNetworkMap.setState(PublicIpv6AddressNetworkMap.State.Allocated); + ipv6AddressNetworkMap.setNicMacAddress(nicMacAddress); + publicIpv6AddressNetworkMapDao.update(ipv6AddressNetworkMap.getId(), ipv6AddressNetworkMap); + return ipv6AddressNetworkMap; + } + @Override public boolean start() { _ipv6GuestPrefixSubnetNetworkMapStateScanner.scheduleWithFixedDelay(new Ipv6GuestPrefixSubnetNetworkMapStateScanner(), 300, 30*60, TimeUnit.SECONDS); @@ -275,13 +288,10 @@ public void releaseIpv6SubnetForNetwork(long networkId) { PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap = null; List ipv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(network.getId()); for (PublicIpv6AddressNetworkMapVO map : ipv6AddressNetworkMaps) { - if (StringUtils.isEmpty(map.getNicMacAddress()) || nicMacAddress.equals(map.getNicMacAddress())) { // || nicDao.findByNetworkIdAndMacAddress(network.getId(), nicMacAddress) == null) { + if (StringUtils.isEmpty(map.getNicMacAddress()) || nicMacAddress.equals(map.getNicMacAddress())) { ipv6AddressNetworkMap = map; if (!nicMacAddress.equals(map.getNicMacAddress())) { - ipv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(ipv6AddressNetworkMap.getId()); - ipv6AddressNetworkMap.setState(PublicIpv6AddressNetworkMap.State.Allocated); - ipv6AddressNetworkMap.setNicMacAddress(nicMacAddress); - publicIpv6AddressNetworkMapDao.update(ipv6AddressNetworkMap.getId(), ipv6AddressNetworkMap); + ipv6AddressNetworkMap = updatePublicIpv6NicMacAddress(map.getId(), nicMacAddress); } break; } From be6b68859252221c5e171ee363ea9fc6e628dcfb Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 30 Dec 2021 01:23:29 +0530 Subject: [PATCH 024/109] ip6 usage Signed-off-by: Abhishek Kumar --- .../orchestration/NetworkOrchestrator.java | 17 ++++++++++---- .../cloud/network/dao/NetworkDetailsDao.java | 2 +- .../network/dao/NetworkDetailsDaoImpl.java | 7 ++++++ .../offerings/dao/NetworkOfferingDao.java | 6 ++--- .../offerings/dao/NetworkOfferingDaoImpl.java | 8 +++---- .../cloud/network/Ipv6AddressManagerImpl.java | 13 +++++++++-- .../com/cloud/network/Ipv6ServiceImpl.java | 22 +++++++++++++++++-- 7 files changed, 59 insertions(+), 16 deletions(-) diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index b210c17ba07a..edccb6dbd53c 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -244,6 +244,7 @@ import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import com.googlecode.ipv6.IPv6Address; /** * NetworkManagerImpl implements NetworkManager. @@ -2347,10 +2348,18 @@ && isDhcpAccrossMultipleSubnetsSupported(dhcpServiceProvider)) { s_logger.debug("Removed nic id=" + nic.getId()); // release assigned IPv6 for Isolated Network VR NIC - if (Type.DomainRouter.equals(vm.getType()) - && TrafficType.Guest.equals(network.getTrafficType()) - && GuestType.Isolated.equals(network.getGuestType())) { - ipv6Service.releasePublicIpv6ForNic(nic.getNetworkId(), nic.getMacAddress()); + if (GuestType.Isolated.equals(network.getGuestType()) + && _networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId())) { + if (Type.DomainRouter.equals(vm.getType()) + && TrafficType.Guest.equals(network.getTrafficType())) { + ipv6Service.releasePublicIpv6ForNic(nic.getNetworkId(), nic.getMacAddress()); + } + if (Type.User.equals(vm.getType())) { + final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_RELEASE, network.getAccountId(), network.getDataCenterId(), 0L, + nic.getIPv6Address(), false, Vlan.VlanType.VirtualNetwork.toString(), false, usageHidden, + IPv6Address.class.getName(), null); + } } //remove the secondary ip addresses corresponding to to this nic diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDetailsDao.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDetailsDao.java index efe84f6bff20..f2d297fbd214 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDetailsDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDetailsDao.java @@ -21,5 +21,5 @@ import com.cloud.utils.db.GenericDao; public interface NetworkDetailsDao extends GenericDao, ResourceDetailsDao { - + boolean isNetworkUsageHidden(long networkId); } \ No newline at end of file diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDetailsDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDetailsDaoImpl.java index 7fc8cdab0b05..d036b1319008 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDetailsDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDetailsDaoImpl.java @@ -21,6 +21,8 @@ import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; +import com.cloud.network.Network; + @Component public class NetworkDetailsDaoImpl extends ResourceDetailsDaoBase implements NetworkDetailsDao { @@ -29,4 +31,9 @@ public void addDetail(long resourceId, String key, String value, boolean display super.addDetail(new NetworkDetailVO(resourceId, key, value, display)); } + @Override + public boolean isNetworkUsageHidden(long networkId) { + NetworkDetailVO networkDetail = findDetail(networkId, Network.hideIpAddressUsage); + return networkDetail != null && "true".equals(networkDetail.getValue()); + } } diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java index b59f2d78ca6b..3ada3e8c8404 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDao.java @@ -70,9 +70,9 @@ public interface NetworkOfferingDao extends GenericDao */ void persistDefaultL2NetworkOfferings(); - NetworkOffering.InternetProtocol getNetworkOfferingInternetProtocol(Long offeringId); + NetworkOffering.InternetProtocol getNetworkOfferingInternetProtocol(long offeringId); - boolean isIpv6Supported(Long offeringId); + boolean isIpv6Supported(long offeringId); - boolean isIpv6FirewallEnabled(Long offeringId); + boolean isIpv6FirewallEnabled(long offeringId); } diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java index a3735e2c1326..7f8842c7d54e 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java @@ -275,19 +275,19 @@ public void persistDefaultL2NetworkOfferings() { } @Override - public NetworkOffering.InternetProtocol getNetworkOfferingInternetProtocol(Long offeringId) { + public NetworkOffering.InternetProtocol getNetworkOfferingInternetProtocol(long offeringId) { String internetProtocolStr = _detailsDao.getDetail(offeringId, NetworkOffering.Detail.internetProtocol); return NetworkOffering.InternetProtocol.fromValue(internetProtocolStr); } @Override - public boolean isIpv6Supported(Long offeringId) { - NetworkOffering.InternetProtocol internetProtocol = getNetworkOfferingInternetProtocol( offeringId); + public boolean isIpv6Supported(long offeringId) { + NetworkOffering.InternetProtocol internetProtocol = getNetworkOfferingInternetProtocol(offeringId); return ipv6EnabledProtocols.contains(internetProtocol); } @Override - public boolean isIpv6FirewallEnabled(Long offeringId) { + public boolean isIpv6FirewallEnabled(long offeringId) { String ipv6FirewallStr = _detailsDao.getDetail(offeringId, NetworkOffering.Detail.ipv6Firewall); return Boolean.parseBoolean(ipv6FirewallStr); } diff --git a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java index c1f3f39dced3..2777e2f8a0d2 100644 --- a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java @@ -22,15 +22,16 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.vm.NicProfile; -import com.googlecode.ipv6.IPv6Address; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.log4j.Logger; import com.cloud.configuration.Config; import com.cloud.dc.DataCenter; +import com.cloud.dc.Vlan; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.VlanDao; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventUtils; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.IpAddress.State; @@ -43,8 +44,10 @@ import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.net.NetUtils; +import com.cloud.vm.NicProfile; import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpVO; +import com.googlecode.ipv6.IPv6Address; public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressManager { public static final Logger s_logger = Logger.getLogger(Ipv6AddressManagerImpl.class.getName()); @@ -213,6 +216,12 @@ public void setNicIp6Address(final NicProfile nic, final DataCenter dc, final Ne } else { nic.setFormat(Networks.AddressFormat.Ip6); } + if (network.getGuestType().equals(Network.GuestType.Isolated)) { + final boolean usageHidden = false; // isNetworkUsageHidden(network.getId()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_ASSIGN, network.getAccountId(), network.getDataCenterId(), 0L, + ipv6addr.toString(), false, Vlan.VlanType.VirtualNetwork.toString(), false, usageHidden, + IPv6Address.class.getName(), null); + } } nic.setIPv6Dns1(dc.getIp6Dns1()); nic.setIPv6Dns2(dc.getIp6Dns2()); diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java index 966a0c3feafb..2522f807ca53 100644 --- a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java @@ -47,10 +47,12 @@ import com.cloud.dc.dao.VlanDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventUtils; import com.cloud.exception.ResourceAllocationException; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PublicIpv6AddressNetworkMapDao; import com.cloud.network.firewall.FirewallService; @@ -93,6 +95,8 @@ public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Servi @Inject NetworkDao networkDao; @Inject + NetworkDetailsDao networkDetailsDao; + @Inject NicDao nicDao; private IPv6AddressRange getIpv6AddressRangeFromIpv6Vlan(VlanVO vlanVO) { @@ -121,11 +125,21 @@ protected void releaseIpv6Subnet(long subnetId) { @ActionEvent(eventType = EventTypes.EVENT_NET_IP6_RELEASE, eventDescription = "releasing public IPv6", create = true) private void releasePublicIpv6(PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap) { if (publicIpv6AddressNetworkMap != null) { - publicIpv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(publicIpv6AddressNetworkMap.getId()); + Long networkId = publicIpv6AddressNetworkMap.getNetworkId(); + long vlanId = publicIpv6AddressNetworkMap.getRangeId(); publicIpv6AddressNetworkMap.setState(PublicIpv6AddressNetworkMap.State.Free); publicIpv6AddressNetworkMap.setNetworkId(null); publicIpv6AddressNetworkMap.setNicMacAddress(null); publicIpv6AddressNetworkMapDao.update(publicIpv6AddressNetworkMap.getId(), publicIpv6AddressNetworkMap); + if (networkId != null) { + VlanVO vlan = vlanDao.findById(vlanId); + String guestType = vlan.getVlanType().toString(); + Network network = networkDao.findById(networkId); + final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_RELEASE, network.getAccountId(), network.getDataCenterId(), publicIpv6AddressNetworkMap.getId(), + publicIpv6AddressNetworkMap.getIp6Address(), false, guestType, false, usageHidden, + publicIpv6AddressNetworkMap.getClass().getName(), publicIpv6AddressNetworkMap.getUuid()); + } } } @@ -170,7 +184,6 @@ private void releasePublicIpv6(PublicIpv6AddressNetworkMapVO publicIpv6AddressNe throw new CloudRuntimeException(String.format("Cannot find available IPv6 address for network %s", network.getName())); } if (PublicIpv6AddressNetworkMap.State.Free.equals(ip6NetworkMap.getState())) { - ip6NetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(ip6NetworkMap.getId()); ip6NetworkMap.setState(PublicIpv6AddressNetworkMap.State.Allocated); ip6NetworkMap.setNetworkId(network.getId()); ip6NetworkMap.setNicMacAddress(nicMacAddress); @@ -178,6 +191,11 @@ private void releasePublicIpv6(PublicIpv6AddressNetworkMapVO publicIpv6AddressNe } else { publicIpv6AddressNetworkMapDao.persist(ip6NetworkMap); } + final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); + final String guestType = selectedVlan.getVlanType().toString(); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_ASSIGN, network.getAccountId(), network.getDataCenterId(), ip6NetworkMap.getId(), + ip6NetworkMap.getIp6Address(), false, guestType, false, usageHidden, + ip6NetworkMap.getClass().getName(), ip6NetworkMap.getUuid()); return new Pair<>(ip6NetworkMap, selectedVlan); } From 50a5d6391ec5425562aa05049a3de9a589693e1c Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 30 Dec 2021 01:31:41 +0530 Subject: [PATCH 025/109] unused Signed-off-by: Abhishek Kumar --- .../CreateManagementNetworkIpRangeCmd.java | 19 +----------- .../ConfigurationManagerImpl.java | 30 ++----------------- 2 files changed, 4 insertions(+), 45 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java index 0fc6d019579a..54c191a1be64 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java @@ -67,14 +67,10 @@ public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.NETMASK, type = CommandType.STRING, + required = true, description = "The netmask for the management network.") private String netmask; - @Parameter(name = ApiConstants.CIDR, - type = CommandType.STRING, - description = "The CIDR for the management network.") - private String cidr; - @Parameter(name = ApiConstants.START_IP, type = CommandType.STRING, required = true, @@ -96,11 +92,6 @@ public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd { description = "Optional. The vlan id the ip range sits on, default to Null when it is not specified which means you network is not on any Vlan") private String vlan; - @Parameter(name = ApiConstants.IP6_RANGE, - type = CommandType.BOOLEAN, - description = "Optional. Specify if the range is for IPv6. Default value is false") - private Boolean ip6Range; - ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -117,10 +108,6 @@ public String getNetmask() { return netmask; } - public String getCidr() { - return cidr; - } - public String getStartIp() { return startIp; } @@ -140,10 +127,6 @@ public String getVlan() { return vlan; } - public boolean isIp6Range() { - return Boolean.TRUE.equals(ip6Range); - } - @Override public String getEventType() { return EventTypes.EVENT_MANAGEMENT_IP_RANGE_CREATE; diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index b5bc1deba20c..ead9d1011d45 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1313,8 +1313,6 @@ public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) { final String gateway = cmd.getGateWay(); final String netmask = cmd.getNetmask(); final String startIp = cmd.getStartIp(); - final String ip6Cidr = cmd.getCidr(); - final boolean isIp6Range = cmd.isIp6Range(); String endIp = cmd.getEndIp(); final boolean forSystemVms = cmd.isForSystemVms(); String vlan = cmd.getVlan(); @@ -1337,7 +1335,7 @@ public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) { throw new InvalidParameterValueException("The gateway IP address is invalid."); } - if(!isIp6Range && !NetUtils.isValidIp4Netmask(netmask)) { + if(!NetUtils.isValidIp4Netmask(netmask)) { throw new InvalidParameterValueException("The netmask IP address is invalid."); } @@ -1345,20 +1343,12 @@ public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) { endIp = startIp; } - final String cidr = isIp6Range ? ip6Cidr : NetUtils.ipAndNetMaskToCidr(gateway, netmask); - - if(!isIp6Range && !NetUtils.isValidIp4Cidr(cidr)) { - throw new InvalidParameterValueException("The CIDR is invalid " + cidr); - } + final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask); - if(isIp6Range && !NetUtils.isValidIp6Cidr(cidr)) { + if(!NetUtils.isValidIp4Cidr(cidr)) { throw new InvalidParameterValueException("The CIDR is invalid " + cidr); } - if (isIp6Range) { - return createPodIp6Range(pod, gateway, cidr, startIp, endIp, cmd.getVlan()); - } - final String cidrAddress = pod.getCidrAddress(); final long cidrSize = pod.getCidrSize(); @@ -1450,20 +1440,6 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { return pod; } - private Pod createPodIp6Range(HostPodVO pod, String gateway, String cidr, String startIp, String endIp, String vlan) { -// Integer vlanId = null; -// if (vlan != null && !vlan.equalsIgnoreCase("untagged")) { -// try { -// vlanId = Integer.valueOf(vlan); -// } catch (NumberFormatException nfe) { -// throw new InvalidParameterValueException("The VLAN is invalid"); -// } -// } -// PodManagementIp6RangeVO ip6RangeVO = new PodManagementIp6RangeVO(pod.getDataCenterId(), pod.getId(), gateway, cidr, vlanId, startIp, endIp); -// podManagementIp6RangeDao.persist(ip6RangeVO); - return pod; - } - @Override @DB public void deletePodIpRange(final DeleteManagementNetworkIpRangeCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException { From fd27b86c61e3211e42070b1e64292ca90e0acbb8 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 30 Dec 2021 14:35:06 +0530 Subject: [PATCH 026/109] slaac based public ip Signed-off-by: Abhishek Kumar --- .../java/com/cloud/network/Ipv6Service.java | 10 +- .../network/PublicIpv6AddressNetworkMap.java | 38 ---- .../orchestration/NetworkOrchestrator.java | 31 ++- .../java/com/cloud/dc/dao/VlanDaoImpl.java | 1 - .../PublicIpv6AddressNetworkMapVO.java | 125 ----------- .../dao/PublicIpv6AddressNetworkMapDao.java | 30 --- .../PublicIpv6AddressNetworkMapDaoImpl.java | 95 -------- ...spring-engine-schema-core-daos-context.xml | 1 - .../META-INF/db/schema-41610to41700.sql | 16 -- .../java/com/cloud/api/ApiResponseHelper.java | 14 +- .../ConfigurationManagerImpl.java | 11 +- .../com/cloud/network/Ipv6ServiceImpl.java | 205 +++++------------- .../com/cloud/network/NetworkServiceImpl.java | 5 - .../network/router/CommandSetupHelper.java | 11 +- .../views/infra/network/IpRangesTabPublic.vue | 12 +- 15 files changed, 95 insertions(+), 510 deletions(-) delete mode 100644 api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java delete mode 100644 engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java delete mode 100644 engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java delete mode 100644 engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java diff --git a/api/src/main/java/com/cloud/network/Ipv6Service.java b/api/src/main/java/com/cloud/network/Ipv6Service.java index ca3402f96830..a33aed76d173 100644 --- a/api/src/main/java/com/cloud/network/Ipv6Service.java +++ b/api/src/main/java/com/cloud/network/Ipv6Service.java @@ -32,7 +32,7 @@ public interface Ipv6Service extends PluggableService { - public static final int IPV6_GUEST_SUBNET_NETMASK = 64; + public static final int IPV6_SLAAC_CIDR_NETMASK = 64; Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws ResourceAllocationException; @@ -40,15 +40,13 @@ public interface Ipv6Service extends PluggableService { void releaseIpv6SubnetForNetwork(long networkId); - Pair checkExistingOrAssignPublicIpv6ToNetwork(Network network, String nicMacAddress); + Pair assignPublicIpv6ToNetwork(Network network, String nicMacAddress); void updateNicIpv6(NicProfile nic, DataCenter dc, Network network); - void releasePublicIpv6ForNetwork(long networkId); + void releasePublicIpv6ForNic(Network network, String nicIpv6Address); - void releasePublicIpv6ForNic(long networkId, String nicMacAddress); - - void releaseUnusedPublicIpv6ForNetwork(Network network); + List getPublicIpv6AddressesForNetwork(Network network); FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd); diff --git a/api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java b/api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java deleted file mode 100644 index 83a3efb139c5..000000000000 --- a/api/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMap.java +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package com.cloud.network; - -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.api.InternalIdentity; - -public interface PublicIpv6AddressNetworkMap extends Identity, InternalIdentity { - enum State { - Allocated, // The subnet is in use. - Free // The subnet is ready to be allocated. - } - - long getRangeId(); - - String getIp6Address(); - - Long getNetworkId(); - - String getNicMacAddress(); - - PublicIpv6AddressNetworkMap.State getState(); -} diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index edccb6dbd53c..9fc84af72cbc 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -53,6 +53,7 @@ import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; @@ -156,6 +157,7 @@ import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.dao.RemoteAccessVpnVO; +import com.cloud.network.dao.RouterNetworkDao; import com.cloud.network.element.AggregatedCommandExecutor; import com.cloud.network.element.ConfigDriveNetworkElement; import com.cloud.network.element.DhcpServiceProvider; @@ -169,6 +171,7 @@ import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.guru.NetworkGuruAdditionalFunctions; +import com.cloud.network.guru.PublicNetworkGuru; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallManager; @@ -322,6 +325,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra private AnnotationDao annotationDao; @Inject Ipv6Service ipv6Service; + @Inject + RouterNetworkDao routerNetworkDao; List networkGurus; @@ -2348,20 +2353,23 @@ && isDhcpAccrossMultipleSubnetsSupported(dhcpServiceProvider)) { s_logger.debug("Removed nic id=" + nic.getId()); // release assigned IPv6 for Isolated Network VR NIC - if (GuestType.Isolated.equals(network.getGuestType()) - && _networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId())) { - if (Type.DomainRouter.equals(vm.getType()) - && TrafficType.Guest.equals(network.getTrafficType())) { - ipv6Service.releasePublicIpv6ForNic(nic.getNetworkId(), nic.getMacAddress()); - } - if (Type.User.equals(vm.getType())) { - final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_RELEASE, network.getAccountId(), network.getDataCenterId(), 0L, - nic.getIPv6Address(), false, Vlan.VlanType.VirtualNetwork.toString(), false, usageHidden, - IPv6Address.class.getName(), null); + if (Type.DomainRouter.equals(vm.getType()) && PublicNetworkGuru.class.getSimpleName().equals(nic.getReserver()) + && StringUtils.isNotEmpty(nic.getIPv6Address())) { + List routerNetworks = routerNetworkDao.getRouterNetworks(vm.getId()); + if (CollectionUtils.isNotEmpty(routerNetworks)) { + Network guestNetwork = _networksDao.findById(routerNetworks.get(0)); + ipv6Service.releasePublicIpv6ForNic(guestNetwork, nic.getIPv6Address()); } } + if (Type.User.equals(vm.getType()) && GuestType.Isolated.equals(network.getGuestType()) + && _networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()) && StringUtils.isNotEmpty(nic.getIPv6Address())) { + final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_RELEASE, network.getAccountId(), network.getDataCenterId(), 0L, + nic.getIPv6Address(), false, Vlan.VlanType.VirtualNetwork.toString(), false, usageHidden, + IPv6Address.class.getName(), null); + } + //remove the secondary ip addresses corresponding to to this nic if (!removeVmSecondaryIpsOfNic(nic.getId())) { s_logger.debug("Removing nic " + nic.getId() + " secondary ip addreses failed"); @@ -3120,7 +3128,6 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { // commit transaction only when ips and vlans for the network are released successfully ipv6Service.releaseIpv6SubnetForNetwork(networkId); - ipv6Service.releasePublicIpv6ForNetwork(networkId); try { stateTransitTo(networkFinal, Event.DestroyNetwork); } catch (final NoTransitionException e) { diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java index 96df26dc86dc..3ba3506c3e18 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java @@ -260,7 +260,6 @@ public boolean configure(String name, Map params) throws Configu PhysicalNetworkVlanIp6Search.and("physicalNetworkId", PhysicalNetworkVlanIp6Search.entity().getPhysicalNetworkId(), SearchCriteria.Op.EQ); PhysicalNetworkVlanIp6Search.and("ip6Gateway", PhysicalNetworkVlanIp6Search.entity().getIp6Gateway(), SearchCriteria.Op.NNULL); PhysicalNetworkVlanIp6Search.and("ip6Cidr", PhysicalNetworkVlanIp6Search.entity().getIp6Cidr(), SearchCriteria.Op.NNULL); - PhysicalNetworkVlanIp6Search.and("ip6range", PhysicalNetworkVlanIp6Search.entity().getIp6Range(), SearchCriteria.Op.NNULL); PhysicalNetworkVlanIp6Search.done(); return result; diff --git a/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java b/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java deleted file mode 100644 index 706064502ff1..000000000000 --- a/engine/schema/src/main/java/com/cloud/network/PublicIpv6AddressNetworkMapVO.java +++ /dev/null @@ -1,125 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package com.cloud.network; - -import java.util.Date; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; - -import com.cloud.utils.db.GenericDao; - -@Entity -@Table(name = "public_ip6_address_network_map") -public class PublicIpv6AddressNetworkMapVO implements PublicIpv6AddressNetworkMap { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - long id; - - @Column(name = "uuid") - private String uuid; - - @Column(name = "vlan_db_id") - private Long rangeId; - - @Column(name = "public_ip_address") - private String ip6Address; - - @Column(name = "network_id") - private Long networkId; - - @Column(name = "nic_mac_address") - private String nicMacAddress; - - @Column(name = "state") - private PublicIpv6AddressNetworkMap.State state; - - @Column(name = GenericDao.CREATED_COLUMN) - private Date created; - - @Column(name= GenericDao.REMOVED_COLUMN) - private Date removed; - - protected PublicIpv6AddressNetworkMapVO() { - uuid = UUID.randomUUID().toString(); - } - - protected PublicIpv6AddressNetworkMapVO(long rangeId, String ip6Address, Long networkId, String nicMacAddress, State state) { - this.rangeId = rangeId; - this.ip6Address = ip6Address; - this.networkId = networkId; - this.nicMacAddress = nicMacAddress; - this.state = state; - uuid = UUID.randomUUID().toString(); - } - - - @Override - public long getId() { - return id; - } - - @Override - public String getUuid() { - return uuid; - } - - @Override - public long getRangeId() { - return rangeId; - } - - @Override - public String getIp6Address() { - return ip6Address; - } - - @Override - public Long getNetworkId() { - return networkId; - } - - public void setNetworkId(Long networkId) { - this.networkId = networkId; - } - - @Override - public String getNicMacAddress() { - return nicMacAddress; - } - - public void setNicMacAddress(String nicMacAddress) { - this.nicMacAddress = nicMacAddress; - } - - @Override - public State getState() { - return state; - } - - public void setState(PublicIpv6AddressNetworkMap.State state) { - this.state = state; - } -} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java deleted file mode 100644 index 163f28576054..000000000000 --- a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDao.java +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package com.cloud.network.dao; - -import java.util.List; - -import com.cloud.network.PublicIpv6AddressNetworkMapVO; -import com.cloud.utils.db.GenericDao; - -public interface PublicIpv6AddressNetworkMapDao extends GenericDao { - PublicIpv6AddressNetworkMapVO findFirstAvailable(long rangeId); - PublicIpv6AddressNetworkMapVO findLast(long rangeId); - List listByNetworkId(long networkId); - PublicIpv6AddressNetworkMapVO findByNetworkIdAndNicMacAddress(long networkId, String macAddress); -} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java deleted file mode 100644 index 0cf7c0634712..000000000000 --- a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpv6AddressNetworkMapDaoImpl.java +++ /dev/null @@ -1,95 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package com.cloud.network.dao; - -import java.util.List; - -import javax.annotation.PostConstruct; - -import org.apache.commons.collections.CollectionUtils; -import org.springframework.stereotype.Component; - -import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMap; -import com.cloud.network.PublicIpv6AddressNetworkMapVO; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Filter; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; - -@Component -@DB -public class PublicIpv6AddressNetworkMapDaoImpl extends GenericDaoBase implements PublicIpv6AddressNetworkMapDao { - - protected SearchBuilder FreeAddressSearch; - protected SearchBuilder RangeIdSearch; - protected SearchBuilder NetworkIdSearch; - protected SearchBuilder NetworkIdNicMacAddressSearch; - - @PostConstruct - public void init() { - FreeAddressSearch = createSearchBuilder(); - FreeAddressSearch.and("prefixId", FreeAddressSearch.entity().getRangeId(), SearchCriteria.Op.EQ); - FreeAddressSearch.and("state", FreeAddressSearch.entity().getState(), SearchCriteria.Op.EQ); - FreeAddressSearch.done(); - RangeIdSearch = createSearchBuilder(); - RangeIdSearch.and("prefixId", RangeIdSearch.entity().getRangeId(), SearchCriteria.Op.EQ); - RangeIdSearch.done(); - NetworkIdSearch = createSearchBuilder(); - NetworkIdSearch.and("networkId", NetworkIdSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); - NetworkIdSearch.done(); - NetworkIdNicMacAddressSearch = createSearchBuilder(); - NetworkIdNicMacAddressSearch.and("networkId", NetworkIdNicMacAddressSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); - NetworkIdNicMacAddressSearch.and("nicMacAddress", NetworkIdNicMacAddressSearch.entity().getNicMacAddress(), SearchCriteria.Op.EQ); - NetworkIdNicMacAddressSearch.done(); - } - - @Override - public PublicIpv6AddressNetworkMapVO findFirstAvailable(long prefixId) { - SearchCriteria sc = FreeAddressSearch.create(); - sc.setParameters("prefixId", prefixId); - sc.setParameters("state", Ipv6GuestPrefixSubnetNetworkMap.State.Free); - Filter searchFilter = new Filter(PublicIpv6AddressNetworkMapVO.class, "id", true, null, 1L); - List list = listBy(sc, searchFilter); - return CollectionUtils.isNotEmpty(list) ? list.get(0) : null; - } - - @Override - public PublicIpv6AddressNetworkMapVO findLast(long prefixId) { - SearchCriteria sc = RangeIdSearch.create(); - sc.setParameters("prefixId", prefixId); - Filter searchFilter = new Filter(PublicIpv6AddressNetworkMapVO.class, "id", false, null, 1L); - List list = listBy(sc, searchFilter); - return CollectionUtils.isNotEmpty(list) ? list.get(0) : null; - } - - @Override - public List listByNetworkId(long networkId) { - SearchCriteria sc = NetworkIdSearch.create(); - sc.setParameters("networkId", networkId); - return listBy(sc); - } - - @Override - public PublicIpv6AddressNetworkMapVO findByNetworkIdAndNicMacAddress(long networkId, String nicMacAddress) { - SearchCriteria sc = NetworkIdNicMacAddressSearch.create(); - sc.setParameters("networkId", networkId); - sc.setParameters("nicMacAddress", nicMacAddress); - return findOneBy(sc); - } -} \ No newline at end of file diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 7d358b4b74b4..fb11a03f54db 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -108,7 +108,6 @@ - diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql index e26c69bb3640..988097c18726 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql @@ -52,19 +52,3 @@ CREATE TABLE `cloud`.`ip6_guest_prefix_subnet_network_map` ( CONSTRAINT `fk_ip6_guest_prefix_subnet_network_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), CONSTRAINT `uc_ip6_guest_prefix_subnet_network_map__uuid` UNIQUE (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`public_ip6_address_network_map` ( - `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', - `uuid` varchar(40) DEFAULT NULL, - `vlan_db_id` bigint(20) unsigned NOT NULL COMMENT 'id of the vlan to which this address belong to', - `public_ip_address` varchar(255) NOT NULL COMMENT 'ipv6 address', - `network_id` bigint(20) unsigned DEFAULT NULL COMMENT 'network to which this address is associated to', - `nic_mac_address` varchar(17) DEFAULT NULL COMMENT 'mac address of the nic to which this address is assigned to', - `state` varchar(255) NOT NULL COMMENT 'state of the address', - `created` datetime default NULL, - `removed` datetime default NULL, - PRIMARY KEY (`id`), - CONSTRAINT `fk_public_ip6_address_network_map__prefix_id` FOREIGN KEY (`vlan_db_id`) REFERENCES `vlan`(`id`), - CONSTRAINT `fk_public_ip6_address_network_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`), - CONSTRAINT `uc_public_ip6_address_network_map__uuid` UNIQUE (`uuid`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 8c9a39298861..ee9a86209657 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -230,7 +230,6 @@ import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; -import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.event.Event; @@ -242,6 +241,7 @@ import com.cloud.hypervisor.HypervisorCapabilities; import com.cloud.network.GuestVlan; import com.cloud.network.IpAddress; +import com.cloud.network.Ipv6Service; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; @@ -255,7 +255,6 @@ import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PhysicalNetworkTrafficType; -import com.cloud.network.PublicIpv6AddressNetworkMapVO; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.RouterHealthCheckResult; import com.cloud.network.Site2SiteCustomerGateway; @@ -278,7 +277,6 @@ import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkVO; -import com.cloud.network.dao.PublicIpv6AddressNetworkMapDao; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRuleVO; @@ -425,9 +423,7 @@ public class ApiResponseHelper implements ResponseGenerator { @Inject NetworkOfferingDao networkOfferingDao; @Inject - PublicIpv6AddressNetworkMapDao publicIpv6AddressNetworkMapDao; - @Inject - DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao; + Ipv6Service ipv6Service; @Override public UserResponse createUserResponse(User user) { @@ -2529,9 +2525,9 @@ public NetworkResponse createNetworkResponse(ResponseView view, Network network) response.setIpv6Routing("Static"); response.setIpv6Firewall(networkOfferingDao.isIpv6FirewallEnabled(network.getNetworkOfferingId())); if (Network.GuestType.Isolated.equals(networkOffering.getGuestType())) { - List ipv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(network.getId()); - for (PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap : ipv6AddressNetworkMaps) { - NetworkResponse.Ipv6Route route = new NetworkResponse.Ipv6Route(network.getIp6Cidr(), ipv6AddressNetworkMap.getIp6Address()); + List ipv6Addresses = ipv6Service.getPublicIpv6AddressesForNetwork(network); + for (String address : ipv6Addresses) { + NetworkResponse.Ipv6Route route = new NetworkResponse.Ipv6Route(network.getIp6Cidr(), address); response.addIpv6Route(route); } } diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index ead9d1011d45..c1abee8ab9c5 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1742,8 +1742,8 @@ public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(final CreateGue } final String prefix = cmd.getPrefix(); IPv6Network prefixNet = IPv6Network.fromString(prefix); - if (prefixNet.getNetmask().asPrefixLength() > Ipv6Service.IPV6_GUEST_SUBNET_NETMASK) { - throw new InvalidParameterValueException(String.format("IPv6 prefix must be /%d or less", Ipv6Service.IPV6_GUEST_SUBNET_NETMASK)); + if (prefixNet.getNetmask().asPrefixLength() > Ipv6Service.IPV6_SLAAC_CIDR_NETMASK) { + throw new InvalidParameterValueException(String.format("IPv6 prefix must be /%d or less", Ipv6Service.IPV6_SLAAC_CIDR_NETMASK)); } List existingPrefixes = dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); for (DataCenterGuestIpv6PrefixVO existingPrefix : existingPrefixes) { @@ -3868,6 +3868,13 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In if (endIPv6 == null && startIPv6 != null) { endIPv6 = startIPv6; } + + if (startIPv6 == null && endIPv6 == null) { + IPv6Network iPv6Network = IPv6Network.fromString(ip6Cidr); + if (iPv6Network.getNetmask().asPrefixLength() > Ipv6Service.IPV6_SLAAC_CIDR_NETMASK) { + throw new InvalidParameterValueException(String.format("For IPv6 range, prefix must be /%d or less", Ipv6Service.IPV6_SLAAC_CIDR_NETMASK)); + } + } } if (projectId != null) { diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java index 2522f807ca53..238797e7b4b0 100644 --- a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java @@ -18,6 +18,7 @@ package com.cloud.network; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -54,7 +55,6 @@ import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; -import com.cloud.network.dao.PublicIpv6AddressNetworkMapDao; import com.cloud.network.firewall.FirewallService; import com.cloud.network.rules.FirewallRule; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -63,10 +63,13 @@ import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; import com.googlecode.ipv6.IPv6Address; -import com.googlecode.ipv6.IPv6AddressRange; import com.googlecode.ipv6.IPv6Network; import com.googlecode.ipv6.IPv6NetworkMask; @@ -87,8 +90,6 @@ public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Servi @Inject Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao; @Inject - PublicIpv6AddressNetworkMapDao publicIpv6AddressNetworkMapDao; - @Inject FirewallRulesDao firewallDao; @Inject FirewallService firewallService; @@ -98,21 +99,8 @@ public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Servi NetworkDetailsDao networkDetailsDao; @Inject NicDao nicDao; - - private IPv6AddressRange getIpv6AddressRangeFromIpv6Vlan(VlanVO vlanVO) { - String[] rangeArr = vlanVO.getIp6Range().split("-"); - String firstStr = rangeArr[0].trim(); - String lastStr = rangeArr[1].trim(); - IPv6AddressRange range = null; - try { - IPv6Address first = IPv6Address.fromString(firstStr); - IPv6Address last = IPv6Address.fromString(lastStr); - range = IPv6AddressRange.fromFirstAndLast(first, last); - } catch (IllegalArgumentException ex) { - s_logger.warn(String.format("Unable to retrieve IPv6 address range for vlan ID: %d, range: %s", vlanVO.getId(), vlanVO.getIp6Range()), ex); - } - return range; - } + @Inject + DomainRouterDao domainRouterDao; protected void releaseIpv6Subnet(long subnetId) { Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO = ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(subnetId); @@ -122,92 +110,6 @@ protected void releaseIpv6Subnet(long subnetId) { ipv6GuestPrefixSubnetNetworkMapDao.update(ipv6GuestPrefixSubnetNetworkMapVO.getId(), ipv6GuestPrefixSubnetNetworkMapVO); } - @ActionEvent(eventType = EventTypes.EVENT_NET_IP6_RELEASE, eventDescription = "releasing public IPv6", create = true) - private void releasePublicIpv6(PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap) { - if (publicIpv6AddressNetworkMap != null) { - Long networkId = publicIpv6AddressNetworkMap.getNetworkId(); - long vlanId = publicIpv6AddressNetworkMap.getRangeId(); - publicIpv6AddressNetworkMap.setState(PublicIpv6AddressNetworkMap.State.Free); - publicIpv6AddressNetworkMap.setNetworkId(null); - publicIpv6AddressNetworkMap.setNicMacAddress(null); - publicIpv6AddressNetworkMapDao.update(publicIpv6AddressNetworkMap.getId(), publicIpv6AddressNetworkMap); - if (networkId != null) { - VlanVO vlan = vlanDao.findById(vlanId); - String guestType = vlan.getVlanType().toString(); - Network network = networkDao.findById(networkId); - final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_RELEASE, network.getAccountId(), network.getDataCenterId(), publicIpv6AddressNetworkMap.getId(), - publicIpv6AddressNetworkMap.getIp6Address(), false, guestType, false, usageHidden, - publicIpv6AddressNetworkMap.getClass().getName(), publicIpv6AddressNetworkMap.getUuid()); - } - } - } - - @ActionEvent(eventType = EventTypes.EVENT_NET_IP6_ASSIGN, eventDescription = "releasing public IPv6", create = true) - private Pair assignPublicIpv6ToNetwork(Network network, String nicMacAddress) { - PublicIpv6AddressNetworkMapVO ip6NetworkMap = null; - VlanVO selectedVlan = null; - final List ranges = vlanDao.listVlansWithIpV6RangeByPhysicalNetworkId(network.getPhysicalNetworkId()); - if (ranges == null) { - s_logger.error(String.format("Unable to find IPv6 range for the zone ID: %d", network.getDataCenterId())); - throw new CloudRuntimeException(String.format("Cannot find IPv6 address for network %s", network.getName())); - } - for (VlanVO range : ranges) { - ip6NetworkMap = publicIpv6AddressNetworkMapDao.findFirstAvailable(range.getId()); - if (ip6NetworkMap == null) { - PublicIpv6AddressNetworkMapVO last = publicIpv6AddressNetworkMapDao.findLast(range.getId()); - String lastUsedIp6Address = last != null ? last.getIp6Address() : null; - final IPv6AddressRange ip6Range = getIpv6AddressRangeFromIpv6Vlan(range); - IPv6Address ip = null; - if (ip6Range != null) { - if (lastUsedIp6Address == null) { - ip = ip6Range.getFirst(); - } else { - IPv6Address lastAddress = IPv6Address.fromString(lastUsedIp6Address); - lastAddress = lastAddress.add(1); - if (ip6Range.contains(lastAddress)) { - ip = lastAddress; - } - } - if (ip != null) { - ip6NetworkMap = new PublicIpv6AddressNetworkMapVO(range.getId(), ip.toString(), network.getId(), nicMacAddress, PublicIpv6AddressNetworkMap.State.Allocated); - } - } - } - if (ip6NetworkMap != null) { - selectedVlan = range; - break; - } - } - if (ip6NetworkMap == null) { - s_logger.error(String.format("Unable to find an IPv6 address available for allocation for network %s in zone ID: %d", network.getName(), network.getDataCenterId())); - throw new CloudRuntimeException(String.format("Cannot find available IPv6 address for network %s", network.getName())); - } - if (PublicIpv6AddressNetworkMap.State.Free.equals(ip6NetworkMap.getState())) { - ip6NetworkMap.setState(PublicIpv6AddressNetworkMap.State.Allocated); - ip6NetworkMap.setNetworkId(network.getId()); - ip6NetworkMap.setNicMacAddress(nicMacAddress); - publicIpv6AddressNetworkMapDao.update(ip6NetworkMap.getId(), ip6NetworkMap); - } else { - publicIpv6AddressNetworkMapDao.persist(ip6NetworkMap); - } - final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); - final String guestType = selectedVlan.getVlanType().toString(); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_ASSIGN, network.getAccountId(), network.getDataCenterId(), ip6NetworkMap.getId(), - ip6NetworkMap.getIp6Address(), false, guestType, false, usageHidden, - ip6NetworkMap.getClass().getName(), ip6NetworkMap.getUuid()); - return new Pair<>(ip6NetworkMap, selectedVlan); - } - - @ActionEvent(eventType = EventTypes.EVENT_NET_IP6_UPDATE, eventDescription = "releasing public IPv6", create = true) - private PublicIpv6AddressNetworkMapVO updatePublicIpv6NicMacAddress(long id, String nicMacAddress) { - PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(id); - ipv6AddressNetworkMap.setState(PublicIpv6AddressNetworkMap.State.Allocated); - ipv6AddressNetworkMap.setNicMacAddress(nicMacAddress); - publicIpv6AddressNetworkMapDao.update(ipv6AddressNetworkMap.getId(), ipv6AddressNetworkMap); - return ipv6AddressNetworkMap; - } - @Override public boolean start() { _ipv6GuestPrefixSubnetNetworkMapStateScanner.scheduleWithFixedDelay(new Ipv6GuestPrefixSubnetNetworkMapStateScanner(), 300, 30*60, TimeUnit.SECONDS); @@ -248,7 +150,7 @@ public Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws Ipv6GuestPrefixSubnetNetworkMapVO last = ipv6GuestPrefixSubnetNetworkMapDao.findLast(prefix.getId()); String lastUsedSubnet = last != null ? last.getSubnet() : null; final IPv6Network ip6Prefix = IPv6Network.fromString(prefix.getPrefix()); - Iterator splits = ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(IPV6_GUEST_SUBNET_NETMASK)); + Iterator splits = ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(IPV6_SLAAC_CIDR_NETMASK)); if (splits.hasNext()) { splits.next(); } @@ -301,34 +203,42 @@ public void releaseIpv6SubnetForNetwork(long networkId) { } } - @Override - public Pair checkExistingOrAssignPublicIpv6ToNetwork(Network network, String nicMacAddress) { - PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap = null; - List ipv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(network.getId()); - for (PublicIpv6AddressNetworkMapVO map : ipv6AddressNetworkMaps) { - if (StringUtils.isEmpty(map.getNicMacAddress()) || nicMacAddress.equals(map.getNicMacAddress())) { - ipv6AddressNetworkMap = map; - if (!nicMacAddress.equals(map.getNicMacAddress())) { - ipv6AddressNetworkMap = updatePublicIpv6NicMacAddress(map.getId(), nicMacAddress); - } - break; - } + @ActionEvent(eventType = EventTypes.EVENT_NET_IP6_ASSIGN, eventDescription = "releasing public IPv6", create = true) + public Pair assignPublicIpv6ToNetwork(Network network, String nicMacAddress) { + final List ranges = vlanDao.listVlansWithIpV6RangeByPhysicalNetworkId(network.getPhysicalNetworkId()); + if (CollectionUtils.isEmpty(ranges)) { + s_logger.error(String.format("Unable to find IPv6 range for the zone ID: %d", network.getDataCenterId())); + throw new CloudRuntimeException(String.format("Cannot find IPv6 address for network %s", network.getName())); } - if (ipv6AddressNetworkMap == null) { - return assignPublicIpv6ToNetwork(network, nicMacAddress); + Collections.shuffle(ranges); + VlanVO selectedVlan = ranges.get(0); + IPv6Network iPv6Network = IPv6Network.fromString(selectedVlan.getIp6Cidr()); + if (iPv6Network.getNetmask().asPrefixLength() < IPV6_SLAAC_CIDR_NETMASK) { + Iterator splits = iPv6Network.split(IPv6NetworkMask.fromPrefixLength(IPV6_SLAAC_CIDR_NETMASK)); + if (splits.hasNext()) { + splits.next(); + } + if (splits.hasNext()) { + iPv6Network = splits.next(); + } } - Vlan vlan = vlanDao.findById(ipv6AddressNetworkMap.getRangeId()); - return new Pair<>(ipv6AddressNetworkMap, vlan); + IPv6Address ipv6Addr = NetUtils.EUI64Address(iPv6Network, nicMacAddress); + s_logger.info("Calculated IPv6 address " + ipv6Addr + " using EUI-64 for NIC with MAC " + nicMacAddress); + final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); + final String guestType = selectedVlan.getVlanType().toString(); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_ASSIGN, network.getAccountId(), network.getDataCenterId(), 0l, + ipv6Addr.toString(), false, guestType, false, usageHidden, + IPv6Network.class.getName(), null); + return new Pair<>(ipv6Addr.toString(), selectedVlan); } @Override public void updateNicIpv6(NicProfile nic, DataCenter dc, Network network) { boolean isIpv6Supported = networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()); if (nic.getIPv6Address() == null && isIpv6Supported) { - Pair publicIpv6AddressNetworkMapVlanPair = checkExistingOrAssignPublicIpv6ToNetwork(network, nic.getMacAddress()); - final PublicIpv6AddressNetworkMap publicIpv6AddressNetworkMapVO = publicIpv6AddressNetworkMapVlanPair.first(); - final Vlan vlan = publicIpv6AddressNetworkMapVlanPair.second(); - final String routerIpv6 = publicIpv6AddressNetworkMapVO.getIp6Address(); + Pair publicIpv6AddressVlanPair = assignPublicIpv6ToNetwork(network, nic.getMacAddress()); + final Vlan vlan = publicIpv6AddressVlanPair.second(); + final String routerIpv6 = publicIpv6AddressVlanPair.first(); final String routerIpv6Gateway = vlan.getIp6Gateway(); final String routerIpv6Cidr = vlan.getIp6Cidr(); nic.setIPv6Address(routerIpv6); @@ -345,32 +255,26 @@ public void updateNicIpv6(NicProfile nic, DataCenter dc, Network network) { } @Override - public void releasePublicIpv6ForNetwork(long networkId) { - List publicIpv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(networkId); - for (PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap : publicIpv6AddressNetworkMaps) { - releasePublicIpv6(publicIpv6AddressNetworkMap); - } - } - - @Override - public void releasePublicIpv6ForNic(long networkId, String nicMacAddress) { - PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.findByNetworkIdAndNicMacAddress(networkId, nicMacAddress); - if (publicIpv6AddressNetworkMap != null) { - publicIpv6AddressNetworkMap = publicIpv6AddressNetworkMapDao.createForUpdate(publicIpv6AddressNetworkMap.getId()); - publicIpv6AddressNetworkMap.setNicMacAddress(null); - publicIpv6AddressNetworkMapDao.update(publicIpv6AddressNetworkMap.getId(), publicIpv6AddressNetworkMap); - } + @ActionEvent(eventType = EventTypes.EVENT_NET_IP6_RELEASE, eventDescription = "releasing public IPv6", create = true) + public void releasePublicIpv6ForNic(Network network, String nicIpv6Address) { + final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_RELEASE, network.getAccountId(), network.getDataCenterId(), 0L, + nicIpv6Address, false, Vlan.VlanType.VirtualNetwork.toString(), false, usageHidden, + IPv6Address.class.getName(), null); } @Override - public void releaseUnusedPublicIpv6ForNetwork(Network network) { - List publicIpv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(network.getId()); - for (PublicIpv6AddressNetworkMapVO publicIpv6AddressNetworkMap : publicIpv6AddressNetworkMaps) { - if (StringUtils.isEmpty(publicIpv6AddressNetworkMap.getNicMacAddress()) || - nicDao.findByNetworkIdAndMacAddress(network.getPhysicalNetworkId(), publicIpv6AddressNetworkMap.getNicMacAddress()) == null) { - releasePublicIpv6(publicIpv6AddressNetworkMap); + public List getPublicIpv6AddressesForNetwork(Network network) { + List addresses = new ArrayList<>(); + List routers = domainRouterDao.findByNetwork(network.getId()); + for (DomainRouterVO router : routers) { + NicVO nic = nicDao.findByNtwkIdAndInstanceId(network.getPhysicalNetworkId(), router.getId()); + String address = nic.getIPv6Address(); + if (StringUtils.isNotEmpty(address)) { + addresses.add(nic.getIPv6Address()); } } + return addresses; } public FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd) { @@ -465,11 +369,10 @@ public void reallyRun() { List isolatedNetworks = networkDao.listByGuestType(Network.GuestType.Isolated); for (NetworkVO network : isolatedNetworks) { if (Network.State.Implemented.equals(network.getState()) && networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId())) { - List ipv6AddressNetworkMaps = publicIpv6AddressNetworkMapDao.listByNetworkId(network.getId()); - for (PublicIpv6AddressNetworkMapVO ipv6AddressNetworkMap : ipv6AddressNetworkMaps) { - VlanVO vlan = vlanDao.findById(ipv6AddressNetworkMap.getRangeId()); + List ipv6Addresses = getPublicIpv6AddressesForNetwork(network); + for (String address : ipv6Addresses) { if (s_logger.isInfoEnabled()) { - s_logger.info(String.format("Add upstream IPv6 route for %s via: %s for network: %s with vlan: %s", network.getIp6Cidr(), ipv6AddressNetworkMap.getIp6Address(), network, vlan)); + s_logger.info(String.format("Add upstream IPv6 route for %s via: %s for network: %s", network.getIp6Cidr(), address, network)); } } } diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index ae2776b07e80..4741873af98f 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -2073,11 +2073,6 @@ public boolean restartNetwork(Long networkId, boolean cleanup, boolean makeRedun s_logger.warn("Network id=" + networkId + " failed to restart."); } - if (TrafficType.Guest.equals(network.getTrafficType()) - && GuestType.Isolated.equals(network.getGuestType())) { - ipv6Service.releaseUnusedPublicIpv6ForNetwork(network); - } - return success; } diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 20d609436bc6..f34b1e3b771c 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -80,7 +80,6 @@ import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.PublicIpAddress; -import com.cloud.network.PublicIpv6AddressNetworkMap; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.Site2SiteVpnConnection; import com.cloud.network.VpnUser; @@ -90,7 +89,6 @@ import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; -import com.cloud.network.dao.PublicIpv6AddressNetworkMapDao; import com.cloud.network.dao.Site2SiteCustomerGatewayDao; import com.cloud.network.dao.Site2SiteCustomerGatewayVO; import com.cloud.network.dao.Site2SiteVpnGatewayDao; @@ -185,8 +183,6 @@ public class CommandSetupHelper { private HostDao _hostDao; @Inject private Ipv6Service ipv6Service; - @Inject - private PublicIpv6AddressNetworkMapDao publicIpv6AddressNetworkMapDao; @Autowired @Qualifier("networkHelper") @@ -1063,10 +1059,9 @@ private void updateSetupGuestNetworkCommandIpv6(SetupGuestNetworkCommand setupCm if (isIpv6Supported) { setupCmd.setDefaultIp6Dns1(defaultIp6Dns1); setupCmd.setDefaultIp6Dns2(defaultIp6Dns2); - Pair publicIpv6AddressNetworkMapVlanPair = ipv6Service.checkExistingOrAssignPublicIpv6ToNetwork(network, nic.getMacAddress()); - PublicIpv6AddressNetworkMap ipv6AddressNetworkMap = publicIpv6AddressNetworkMapVlanPair.first(); - Vlan vlan = publicIpv6AddressNetworkMapVlanPair.second(); - setupCmd.setRouterIpv6(ipv6AddressNetworkMap.getIp6Address()); + Pair publicIpv6AddressVlanPair = ipv6Service.assignPublicIpv6ToNetwork(network, nic.getMacAddress()); + Vlan vlan = publicIpv6AddressVlanPair.second(); + setupCmd.setRouterIpv6(publicIpv6AddressVlanPair.first()); final String routerIpv6Gateway = vlan.getIp6Gateway(); final String routerIpv6Cidr = vlan.getIp6Cidr(); setupCmd.setRouterIpv6Gateway(routerIpv6Gateway); diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index 84bb53255f8f..564b3e6c0d2f 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -222,16 +222,6 @@ v-decorator="['ip6cidr', { rules: [{ required: true, message: `${$t('label.required')}` }] }]">
- - - - - - - -
@@ -580,7 +570,7 @@ export default { this.addIpRangeModal = false var ipRangeKeys = ['gateway', 'netmask', 'startip', 'endip'] if (values.iptype === 'ip6') { - ipRangeKeys = ['ip6gateway', 'ip6cidr', 'startipv6', 'endipv6'] + ipRangeKeys = ['ip6gateway', 'ip6cidr'] } var params = {} for (const key of ipRangeKeys) { From 110a99a8f8dad65614a1fad5ec5b926aabe026fc Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 31 Dec 2021 11:41:25 +0530 Subject: [PATCH 027/109] fix Signed-off-by: Abhishek Kumar --- .../java/com/cloud/network/Ipv6AddressManagerImpl.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java index 2777e2f8a0d2..2a53708fc59b 100644 --- a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java @@ -38,6 +38,7 @@ import com.cloud.network.Network.IpAddresses; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.UserIpv6AddressDao; import com.cloud.user.Account; import com.cloud.utils.NumbersUtil; @@ -71,6 +72,8 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa NicSecondaryIpDao nicSecondaryIpDao; @Inject IPAddressDao ipAddressDao; + @Inject + NetworkDetailsDao networkDetailsDao; @Override public boolean configure(String name, Map params) throws ConfigurationException { @@ -216,8 +219,8 @@ public void setNicIp6Address(final NicProfile nic, final DataCenter dc, final Ne } else { nic.setFormat(Networks.AddressFormat.Ip6); } - if (network.getGuestType().equals(Network.GuestType.Isolated)) { - final boolean usageHidden = false; // isNetworkUsageHidden(network.getId()); + if (Network.GuestType.Isolated.equals(network.getGuestType())) { + final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_ASSIGN, network.getAccountId(), network.getDataCenterId(), 0L, ipv6addr.toString(), false, Vlan.VlanType.VirtualNetwork.toString(), false, usageHidden, IPv6Address.class.getName(), null); From f0172b280c27c8b6c27ad8813b46a413cfca7e0a Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 31 Dec 2021 11:41:42 +0530 Subject: [PATCH 028/109] remove unused Signed-off-by: Abhishek Kumar --- .../com/cloud/dc/DataCenterGuestIpv6Prefix.java | 2 -- .../network/CreateGuestNetworkIpv6PrefixCmd.java | 11 ----------- .../DataCenterGuestIpv6PrefixResponse.java | 8 -------- .../com/cloud/dc/DataCenterGuestIpv6PrefixVO.java | 15 +-------------- .../dc/dao/DataCenterGuestIpv6PrefixDao.java | 2 -- .../dc/dao/DataCenterGuestIpv6PrefixDaoImpl.java | 8 -------- .../resources/META-INF/db/schema-41610to41700.sql | 2 -- .../java/com/cloud/api/ApiResponseHelper.java | 4 ---- .../configuration/ConfigurationManagerImpl.java | 9 +-------- 9 files changed, 2 insertions(+), 59 deletions(-) diff --git a/api/src/main/java/com/cloud/dc/DataCenterGuestIpv6Prefix.java b/api/src/main/java/com/cloud/dc/DataCenterGuestIpv6Prefix.java index 0a1d451a6621..e3b385464855 100644 --- a/api/src/main/java/com/cloud/dc/DataCenterGuestIpv6Prefix.java +++ b/api/src/main/java/com/cloud/dc/DataCenterGuestIpv6Prefix.java @@ -26,8 +26,6 @@ public interface DataCenterGuestIpv6Prefix extends InfrastructureEntity, InternalIdentity, Identity { Long getDataCenterId(); - Long getPodId(); - String getPrefix(); Date getCreated(); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java index 2095ee79529f..488cfcfe42b9 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateGuestNetworkIpv6PrefixCmd.java @@ -26,7 +26,6 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DataCenterGuestIpv6PrefixResponse; -import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.log4j.Logger; @@ -60,12 +59,6 @@ public class CreateGuestNetworkIpv6PrefixCmd extends BaseAsyncCmd { description = "UUID of zone to which the IPv6 prefix belongs to.", validations = {ApiArgValidator.PositiveNumber}) private Long zoneId; - @Parameter(name = ApiConstants.POD_ID, - type = CommandType.UUID, - entityType = PodResponse.class, - description = "UUID of POD to which the IPv6 prefix belongs to.", - validations = {ApiArgValidator.PositiveNumber}) - private Long podId; @Parameter(name = ApiConstants.PREFIX, type = CommandType.STRING, @@ -82,10 +75,6 @@ public Long getZoneId() { return zoneId; } - public Long getPodId() { - return podId; - } - public String getPrefix() { return prefix; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java index f4c8e636aaac..e58395b29b80 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java @@ -41,10 +41,6 @@ public class DataCenterGuestIpv6PrefixResponse extends BaseResponse { @Param(description = "id of zone to which the IPv6 prefix belongs to." ) private String zoneId; - @SerializedName(ApiConstants.POD_ID) - @Param(description = "id of pod to which the IPv6 prefix belongs to." ) - private String pod; - @SerializedName(ApiConstants.CREATED) @Param(description = " date when this IPv6 prefix was created." ) private Date created; @@ -61,10 +57,6 @@ public void setZoneId(String zoneId) { this.zoneId = zoneId; } - public void setPod(String pod) { - this.pod = pod; - } - public void setCreated(Date created) { this.created = created; } diff --git a/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java b/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java index f213cff83c24..ff48510e4d2c 100644 --- a/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/DataCenterGuestIpv6PrefixVO.java @@ -43,9 +43,6 @@ public class DataCenterGuestIpv6PrefixVO implements DataCenterGuestIpv6Prefix { @Column(name = "data_center_id") private long dataCenterId; - @Column(name = "pod_id") - private Long podId; - @Column(name = "prefix") private String prefix; @@ -55,10 +52,9 @@ public class DataCenterGuestIpv6PrefixVO implements DataCenterGuestIpv6Prefix { @Column(name= GenericDao.REMOVED_COLUMN) private Date removed; - public DataCenterGuestIpv6PrefixVO(long dcId, Long podId, String prefix) { + public DataCenterGuestIpv6PrefixVO(long dcId, String prefix) { this(); this.dataCenterId = dcId; - this.podId = podId; this.prefix = prefix; this.created = new Date(); } @@ -86,15 +82,6 @@ public void setDataCenterId(long dcId) { this.dataCenterId = dcId; } - @Override - public Long getPodId() { - return podId; - } - - public void setPodId(long podId) { - this.podId = podId; - } - public String getPrefix() { return prefix; } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDao.java index 278c0cc61864..2d8e5fcba000 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDao.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDao.java @@ -24,7 +24,5 @@ public interface DataCenterGuestIpv6PrefixDao extends GenericDao { - List listByPodId(long podId); - List listByDataCenterId(long dcId); } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDaoImpl.java index f0d140c1bcb8..8e8f79895e7e 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/DataCenterGuestIpv6PrefixDaoImpl.java @@ -34,14 +34,6 @@ public class DataCenterGuestIpv6PrefixDaoImpl extends GenericDaoBase listByPodId(long podId) { - SearchCriteria sc = createSearchCriteria(); - sc.addOr("podId", SearchCriteria.Op.NULL); - sc.addOr("podId", SearchCriteria.Op.EQ, podId); - return listBy(sc); - } - @Override public List listByDataCenterId(long dcId) { QueryBuilder sc = QueryBuilder.create(DataCenterGuestIpv6PrefixVO.class); diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql index 988097c18726..d3ac08cd6d31 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql @@ -27,13 +27,11 @@ CREATE TABLE `cloud`.`dc_ip6_guest_prefix` ( `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', `uuid` varchar(40) DEFAULT NULL, `data_center_id` bigint(20) unsigned NOT NULL COMMENT 'zone it belongs to', - `pod_id` bigint(20) unsigned DEFAULT NULL COMMENT 'pod it belongs to', `prefix` varchar(255) NOT NULL COMMENT 'prefix of the ipv6 network', `created` datetime default NULL, `removed` datetime default NULL, PRIMARY KEY (`id`), CONSTRAINT `fk_dc_ip6_guest_prefix__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`), - CONSTRAINT `fk_dc_ip6_guest_prefix__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `host_pod_ref`(`id`), CONSTRAINT `uc_dc_ip6_guest_prefix__uuid` UNIQUE (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index ee9a86209657..b6f9aa20c92d 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -1268,10 +1268,6 @@ public DataCenterGuestIpv6PrefixResponse createDataCenterGuestIpv6PrefixResponse response.setPrefix(prefix.getPrefix()); DataCenter dc = ApiDBUtils.findZoneById(prefix.getDataCenterId()); response.setZoneId(dc.getUuid()); - if (prefix.getPodId() != null) { - Pod pod = ApiDBUtils.findPodById(prefix.getPodId()); - response.setPod(pod.getUuid()); - } response.setCreated(prefix.getCreated()); return response; } diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index c1abee8ab9c5..b1348935f330 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1733,13 +1733,6 @@ public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(final CreateGue if (zone == null) { throw new InvalidParameterValueException("Unable to find zone by id: " + zoneId); } - final Long podId = cmd.getPodId(); - if (podId != null) { - final HostPodVO pod = _podDao.findById(podId); - if (pod == null) { - throw new InvalidParameterValueException("Unable to find pod by id: " + podId); - } - } final String prefix = cmd.getPrefix(); IPv6Network prefixNet = IPv6Network.fromString(prefix); if (prefixNet.getNetmask().asPrefixLength() > Ipv6Service.IPV6_SLAAC_CIDR_NETMASK) { @@ -1757,7 +1750,7 @@ public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(final CreateGue dataCenterGuestIpv6Prefix = Transaction.execute(new TransactionCallback() { @Override public DataCenterGuestIpv6Prefix doInTransaction(TransactionStatus status) { - DataCenterGuestIpv6PrefixVO dataCenterGuestIpv6PrefixVO = new DataCenterGuestIpv6PrefixVO(zoneId, podId, prefix); + DataCenterGuestIpv6PrefixVO dataCenterGuestIpv6PrefixVO = new DataCenterGuestIpv6PrefixVO(zoneId, prefix); dataCenterGuestIpv6PrefixDao.persist(dataCenterGuestIpv6PrefixVO); return dataCenterGuestIpv6PrefixVO; } From 57e392ca55fc4959d6561103e4f0a00b1fb413f0 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Mon, 3 Jan 2022 11:29:52 +0530 Subject: [PATCH 029/109] diagnostics fix for vr Signed-off-by: Abhishek Kumar --- .../java/org/apache/cloudstack/diagnostics/DiagnosticsType.java | 2 +- ui/src/config/section/infra/routers.js | 2 +- ui/src/config/section/infra/systemVms.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/diagnostics/DiagnosticsType.java b/api/src/main/java/org/apache/cloudstack/diagnostics/DiagnosticsType.java index 0e3a1dad2c62..d3c15c8d5a34 100644 --- a/api/src/main/java/org/apache/cloudstack/diagnostics/DiagnosticsType.java +++ b/api/src/main/java/org/apache/cloudstack/diagnostics/DiagnosticsType.java @@ -19,7 +19,7 @@ package org.apache.cloudstack.diagnostics; public enum DiagnosticsType { - PING("ping"), TRACEROUTE("traceroute"), ARPING("arping"); + PING("ping"), PING6("ping6"), TRACEROUTE("traceroute"), TRACEROUTE6("traceroute6"), ARPING("arping"); private String value; diff --git a/ui/src/config/section/infra/routers.js b/ui/src/config/section/infra/routers.js index 00b2a90e5e36..b0754c00ba5f 100644 --- a/ui/src/config/section/infra/routers.js +++ b/ui/src/config/section/infra/routers.js @@ -144,7 +144,7 @@ export default { value: (record) => { return record.id } }, type: { - options: ['ping', 'traceroute', 'arping'] + options: ['ping', 'ping6', 'traceroute', 'traceroute6', 'arping'] } }, response: (result) => { return result && result.diagnostics ? `Output:
${result.diagnostics.stdout}
Error: ${result.diagnostics.stderr}
Exit Code: ${result.diagnostics.exitcode}` : 'Invalid response' } diff --git a/ui/src/config/section/infra/systemVms.js b/ui/src/config/section/infra/systemVms.js index ebbec969c957..2c0bd1d6e593 100644 --- a/ui/src/config/section/infra/systemVms.js +++ b/ui/src/config/section/infra/systemVms.js @@ -116,7 +116,7 @@ export default { value: (record) => { return record.id } }, type: { - options: ['ping', 'ping6', 'traceroute', 'traceroute6', 'arping'] + options: ['ping', 'traceroute', 'arping'] } }, response: (result) => { return result && result.diagnostics ? `Output:
${result.diagnostics.stdout}
Error: ${result.diagnostics.stderr}
Exit Code: ${result.diagnostics.exitcode}` : 'Invalid response' } From ee12754e9cdcbdc32d88943ae1cbb381f2fceacf Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 6 Jan 2022 12:29:48 +0530 Subject: [PATCH 030/109] firewall changes Signed-off-by: Abhishek Kumar --- .../java/com/cloud/network/Ipv6Service.java | 3 +- .../cloudstack/api/ResponseGenerator.java | 2 +- .../user/ipv6/CreateIpv6FirewallRuleCmd.java | 42 +++-- .../user/ipv6/ListIpv6FirewallRulesCmd.java | 7 +- .../user/ipv6/UpdateIpv6FirewallRuleCmd.java | 3 +- .../api/response/FirewallResponse.java | 8 + .../routing/SetIpv6FirewallRulesAnswer.java | 39 +++++ .../routing/SetIpv6FirewallRulesCommand.java | 49 ++++++ .../resource/virtualnetwork/VRScripts.java | 1 + .../facade/AbstractConfigItemFacade.java | 3 + .../SetIpv6FirewallRulesConfigItem.java | 59 +++++++ .../virtualnetwork/model/ConfigBase.java | 1 + .../java/com/cloud/api/ApiResponseHelper.java | 13 +- .../com/cloud/network/Ipv6ServiceImpl.java | 152 ++++++++++++++++-- .../network/firewall/FirewallManagerImpl.java | 37 +++-- .../network/router/CommandSetupHelper.java | 84 ++++++++++ .../VirtualNetworkApplianceManagerImpl.java | 32 ++++ .../network/topology/BasicNetworkVisitor.java | 6 + systemvm/debian/opt/cloud/bin/configure.py | 119 ++++++++++++-- systemvm/debian/opt/cloud/bin/cs/CsConfig.py | 4 + .../debian/opt/cloud/bin/cs/CsNetfilter.py | 10 ++ systemvm/debian/opt/cloud/bin/merge.py | 5 + ui/public/locales/en.json | 8 + ui/src/views/network/Ipv6FirewallRulesTab.vue | 24 +-- 24 files changed, 641 insertions(+), 70 deletions(-) create mode 100644 core/src/main/java/com/cloud/agent/api/routing/SetIpv6FirewallRulesAnswer.java create mode 100644 core/src/main/java/com/cloud/agent/api/routing/SetIpv6FirewallRulesCommand.java create mode 100644 core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetIpv6FirewallRulesConfigItem.java diff --git a/api/src/main/java/com/cloud/network/Ipv6Service.java b/api/src/main/java/com/cloud/network/Ipv6Service.java index a33aed76d173..4a106614eb93 100644 --- a/api/src/main/java/com/cloud/network/Ipv6Service.java +++ b/api/src/main/java/com/cloud/network/Ipv6Service.java @@ -24,6 +24,7 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.Vlan; +import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.network.rules.FirewallRule; import com.cloud.utils.Pair; @@ -54,7 +55,7 @@ public interface Ipv6Service extends PluggableService { boolean revokeIpv6FirewallRule(Long id); - FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd createIpv6FirewallRuleCmd); + FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd createIpv6FirewallRuleCmd) throws NetworkRuleConflictException; FirewallRule getIpv6FirewallRule(Long entityId); diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java index c546571c58c3..c36b45087451 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java @@ -495,5 +495,5 @@ List createTemplateResponses(ResponseView view, VirtualMachine ResourceIconResponse createResourceIconResponse(ResourceIcon resourceIcon); - FirewallRuleResponse createIpv6FirewallRuleResponse(FirewallRule acl); + FirewallResponse createIpv6FirewallRuleResponse(FirewallRule acl); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java index 3ca50558f386..370554cbf1a7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.api.BaseAsyncCreateCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.FirewallResponse; import org.apache.cloudstack.api.response.FirewallRuleResponse; import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.context.CallContext; @@ -36,6 +37,7 @@ import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Ipv6Service; import com.cloud.network.rules.FirewallRule; @@ -63,8 +65,11 @@ public class CreateIpv6FirewallRuleCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.END_PORT, type = CommandType.INTEGER, description = "the ending port of Ipv6 firewall rule") private Integer publicEndPort; - @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the CIDR list to allow traffic from/to. Multiple entries must be separated by a single comma character (,).") - private List cidrlist; + @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the source CIDR list to allow traffic from. Multiple entries must be separated by a single comma character (,).") + private List sourceCidrList; + + @Parameter(name = ApiConstants.DEST_CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the destination CIDR list to allow traffic to. Multiple entries must be separated by a single comma character (,).") + private List destinationCidrlist; @Parameter(name = ApiConstants.ICMP_TYPE, type = CommandType.INTEGER, description = "type of the ICMP message being sent") private Integer icmpType; @@ -72,10 +77,10 @@ public class CreateIpv6FirewallRuleCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.ICMP_CODE, type = CommandType.INTEGER, description = "error code for this ICMP message") private Integer icmpCode; - @Parameter(name = ApiConstants.NETWORK_ID, type = CommandType.UUID, entityType = NetworkResponse.class, description = "The network of the VM the Ipv6 firewall rule will be created for") + @Parameter(name = ApiConstants.NETWORK_ID, type = CommandType.UUID, entityType = NetworkResponse.class, description = "The network of the VM the Ipv6 firewall rule will be created for", required = true) private Long networkId; - @Parameter(name = ApiConstants.TRAFFIC_TYPE, type = CommandType.STRING, description = "the traffic type for the Ipv6 firewall rule," + "can be ingress or egress, defaulted to ingress if not specified") + @Parameter(name = ApiConstants.TRAFFIC_TYPE, type = CommandType.STRING, description = "the traffic type for the Ipv6 firewall rule, can be ingress or egress, defaulted to ingress if not specified") private String trafficType; @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the rule to the end user or not", authorized = {RoleType.Admin}) @@ -107,11 +112,21 @@ public String getProtocol() { } public List getSourceCidrList() { - if (cidrlist != null) { - return cidrlist; + if (sourceCidrList != null) { + return sourceCidrList; } else { List oneCidrList = new ArrayList(); - oneCidrList.add(NetUtils.ALL_IP4_CIDRS); + oneCidrList.add(NetUtils.ALL_IP6_CIDRS); + return oneCidrList; + } + } + + public List getDestinationCidrList() { + if (destinationCidrlist != null) { + return destinationCidrlist; + } else { + List oneCidrList = new ArrayList(); + oneCidrList.add(NetUtils.ALL_IP6_CIDRS); return oneCidrList; } } @@ -194,9 +209,14 @@ public Integer getIcmpType() { @Override public void create() { - FirewallRule result = ipv6Service.createIpv6FirewallRule(this); - setEntityId(result.getId()); - setEntityUuid(result.getUuid()); + try { + FirewallRule result = ipv6Service.createIpv6FirewallRule(this); + setEntityId(result.getId()); + setEntityUuid(result.getUuid()); + } catch (NetworkRuleConflictException e) { + s_logger.trace("Network Rule Conflict: ", e); + throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, e.getMessage(), e); + } } @Override @@ -209,7 +229,7 @@ public void execute() throws ResourceUnavailableException { // State is different after the rule is applied, so get new object here rule = ipv6Service.getIpv6FirewallRule(getEntityId()); - FirewallRuleResponse ruleResponse = new FirewallRuleResponse(); + FirewallResponse ruleResponse = new FirewallResponse(); if (rule != null) { ruleResponse = _responseGenerator.createIpv6FirewallRuleResponse(rule); setResponseObject(ruleResponse); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java index 2f902a9aea26..5f8fcd59a1ac 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java @@ -27,6 +27,7 @@ import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.command.user.firewall.IListFirewallRulesCmd; +import org.apache.cloudstack.api.response.FirewallResponse; import org.apache.cloudstack.api.response.FirewallRuleResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.NetworkResponse; @@ -122,11 +123,11 @@ public String getCommandName() { @Override public void execute() { Pair, Integer> result = ipv6Service.listIpv6FirewallRules(this); - ListResponse response = new ListResponse(); - List ruleResponses = new ArrayList(); + ListResponse response = new ListResponse<>(); + List ruleResponses = new ArrayList<>(); for (FirewallRule rule : result.first()) { - FirewallRuleResponse ruleData = _responseGenerator.createIpv6FirewallRuleResponse(rule); + FirewallResponse ruleData = _responseGenerator.createIpv6FirewallRuleResponse(rule); ruleResponses.add(ruleData); } response.setResponses(ruleResponses, result.second()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java index ac9b24f10e3d..bbabeb5615f5 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseAsyncCustomIdCmd; import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.FirewallResponse; import org.apache.cloudstack.api.response.FirewallRuleResponse; import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; @@ -161,7 +162,7 @@ public Integer getIcmpType() { public void execute() throws ResourceUnavailableException { CallContext.current().setEventDetails("Rule Id: " + getId()); FirewallRule rules = ipv6Service.updateIpv6FirewallRule(this); - FirewallRuleResponse ruleResponse = _responseGenerator.createIpv6FirewallRuleResponse(rules); + FirewallResponse ruleResponse = _responseGenerator.createIpv6FirewallRuleResponse(rules); setResponseObject(ruleResponse); ruleResponse.setResponseName(getCommandName()); } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/FirewallResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/FirewallResponse.java index 3ab4472737f8..a9ecdd8e3393 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/FirewallResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/FirewallResponse.java @@ -83,6 +83,10 @@ public class FirewallResponse extends BaseResponse { @Param(description = "the cidr list to forward traffic to. Multiple entries are separated by a single comma character (,).") private String destCidr; + @SerializedName(ApiConstants.TRAFFIC_TYPE) + @Param(description = "the traffic type for the firewall rule", since = "4.17.0") + private String trafficType; + public void setId(String id) { this.id = id; } @@ -138,4 +142,8 @@ public void setForDisplay(Boolean forDisplay) { public void setDestCidr(String cidrList){ this.destCidr = cidrList; } + + public void setTrafficType(String trafficType) { + this.trafficType = trafficType; + } } diff --git a/core/src/main/java/com/cloud/agent/api/routing/SetIpv6FirewallRulesAnswer.java b/core/src/main/java/com/cloud/agent/api/routing/SetIpv6FirewallRulesAnswer.java new file mode 100644 index 000000000000..bb8584caf488 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/routing/SetIpv6FirewallRulesAnswer.java @@ -0,0 +1,39 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.agent.api.routing; + +import com.cloud.agent.api.Answer; + +public class SetIpv6FirewallRulesAnswer extends Answer { + String[] results; + + protected SetIpv6FirewallRulesAnswer() { + } + + public SetIpv6FirewallRulesAnswer(SetIpv6FirewallRulesCommand cmd, boolean success, String[] results) { + super(cmd, success, null); + assert (cmd.getRules().length == results.length) : "rules and their results should be the same length don't you think?"; + this.results = results; + } + + public String[] getResults() { + return results; + } +} diff --git a/core/src/main/java/com/cloud/agent/api/routing/SetIpv6FirewallRulesCommand.java b/core/src/main/java/com/cloud/agent/api/routing/SetIpv6FirewallRulesCommand.java new file mode 100644 index 000000000000..62cc2cabaaae --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/routing/SetIpv6FirewallRulesCommand.java @@ -0,0 +1,49 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.agent.api.routing; + +import java.util.List; + +import com.cloud.agent.api.to.FirewallRuleTO; + +/** + * + * AccessDetails allow different components to put in information about + * how to access the components inside the command. + */ +public class SetIpv6FirewallRulesCommand extends NetworkElementCommand { + FirewallRuleTO[] rules; + + protected SetIpv6FirewallRulesCommand() { + } + + public SetIpv6FirewallRulesCommand(List rules) { + this.rules = rules.toArray(new FirewallRuleTO[rules.size()]); + } + + public FirewallRuleTO[] getRules() { + return rules; + } + + @Override + public int getAnswersCount() { + return rules.length; + } +} diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VRScripts.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VRScripts.java index 834a11c8d6eb..af5390b4ba68 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VRScripts.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VRScripts.java @@ -31,6 +31,7 @@ public class VRScripts { public final static String VM_PASSWORD_CONFIG = "vm_password.json"; public static final String FORWARDING_RULES_CONFIG = "forwarding_rules.json"; public static final String FIREWALL_RULES_CONFIG = "firewall_rules.json"; + public static final String IPV6_FIREWALL_RULES_CONFIG = "ipv6_firewall_rules.json"; public static final String VPN_USER_LIST_CONFIG = "vpn_user_list.json"; public static final String STATICNAT_RULES_CONFIG = "staticnat_rules.json"; public static final String SITE_2_SITE_VPN_CONFIG = "site_2_site_vpn.json"; diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/AbstractConfigItemFacade.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/AbstractConfigItemFacade.java index 1042d23e7b0c..bed472b68808 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/AbstractConfigItemFacade.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/AbstractConfigItemFacade.java @@ -23,6 +23,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; + import org.apache.log4j.Logger; import com.cloud.agent.api.BumpUpPriorityCommand; @@ -38,6 +39,7 @@ import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; import com.cloud.agent.api.routing.SavePasswordCommand; import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetIpv6FirewallRulesCommand; import com.cloud.agent.api.routing.SetMonitorServiceCommand; import com.cloud.agent.api.routing.SetNetworkACLCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; @@ -84,6 +86,7 @@ public abstract class AbstractConfigItemFacade { flyweight.put(DeleteIpAliasCommand.class, new DeleteIpAliasConfigItem()); flyweight.put(VmDataCommand.class, new VmDataConfigItem()); flyweight.put(SetFirewallRulesCommand.class, new SetFirewallRulesConfigItem()); + flyweight.put(SetIpv6FirewallRulesCommand.class, new SetIpv6FirewallRulesConfigItem()); flyweight.put(BumpUpPriorityCommand.class, new BumpUpPriorityConfigItem()); flyweight.put(RemoteAccessVpnCfgCommand.class, new RemoteAccessVpnConfigItem()); flyweight.put(VpnUsersCfgCommand.class, new VpnUsersConfigItem()); diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetIpv6FirewallRulesConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetIpv6FirewallRulesConfigItem.java new file mode 100644 index 000000000000..ff4f266f9951 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetIpv6FirewallRulesConfigItem.java @@ -0,0 +1,59 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.agent.resource.virtualnetwork.facade; + +import java.util.ArrayList; +import java.util.List; + +import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.routing.SetIpv6FirewallRulesCommand; +import com.cloud.agent.api.to.FirewallRuleTO; +import com.cloud.agent.resource.virtualnetwork.ConfigItem; +import com.cloud.agent.resource.virtualnetwork.VRScripts; +import com.cloud.agent.resource.virtualnetwork.model.ConfigBase; +import com.cloud.agent.resource.virtualnetwork.model.FirewallRule; +import com.cloud.agent.resource.virtualnetwork.model.FirewallRules; + +public class SetIpv6FirewallRulesConfigItem extends AbstractConfigItemFacade{ + + @Override + public List generateConfig(final NetworkElementCommand cmd) { + final SetIpv6FirewallRulesCommand command = (SetIpv6FirewallRulesCommand) cmd; + + final List rules = new ArrayList(); + for (final FirewallRuleTO rule : command.getRules()) { + final FirewallRule fwRule = new FirewallRule(rule.getId(), rule.getSrcVlanTag(), rule.getSrcIp(), rule.getProtocol(), rule.getSrcPortRange(), rule.revoked(), + rule.isAlreadyAdded(), rule.getSourceCidrList(), rule.getDestCidrList(), rule.getPurpose().toString(), rule.getIcmpType(), rule.getIcmpCode(), rule.getTrafficType().toString(), + rule.getGuestCidr(), rule.isDefaultEgressPolicy()); + rules.add(fwRule); + } + + final FirewallRules ruleSet = new FirewallRules(rules.toArray(new FirewallRule[rules.size()])); + ruleSet.setType(ConfigBase.IPV6_FIREWALL_RULES); + return generateConfigItems(ruleSet); + } + + @Override + protected List generateConfigItems(final ConfigBase configuration) { + destinationFile = VRScripts.IPV6_FIREWALL_RULES_CONFIG; + + return super.generateConfigItems(configuration); + } +} \ No newline at end of file diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/ConfigBase.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/ConfigBase.java index 51424ea3115d..ade80d71384f 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/ConfigBase.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/ConfigBase.java @@ -29,6 +29,7 @@ public abstract class ConfigBase { public static final String VM_PASSWORD = "vmpassword"; public static final String FORWARDING_RULES = "forwardrules"; public static final String FIREWALL_RULES = "firewallrules"; + public static final String IPV6_FIREWALL_RULES = "ipv6firewallrules"; public static final String VPN_USER_LIST = "vpnuserlist"; public static final String STATICNAT_RULES = "staticnatrules"; public static final String IP_ALIAS_CONFIG = "ipaliases"; diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index b6f9aa20c92d..7b8f95fb27e3 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -4599,14 +4599,21 @@ public ResourceIconResponse createResourceIconResponse(ResourceIcon resourceIcon } @Override - public FirewallRuleResponse createIpv6FirewallRuleResponse(FirewallRule fwRule) { - FirewallRuleResponse response = new FirewallRuleResponse(); + public FirewallResponse createIpv6FirewallRuleResponse(FirewallRule fwRule) { + FirewallResponse response = new FirewallResponse(); response.setId(fwRule.getUuid()); response.setProtocol(fwRule.getProtocol()); - List cidrs = ApiDBUtils.findFirewallSourceCidrs(fwRule.getId()); response.setCidrList(StringUtils.join(cidrs, ",")); + List destinationCidrs = ApiDBUtils.findFirewallDestCidrs(fwRule.getId()); + response.setDestCidr(StringUtils.join(destinationCidrs, ",")); + response.setTrafficType(fwRule.getTrafficType().toString()); + response.setProtocol(fwRule.getProtocol()); + response.setStartPort(fwRule.getSourcePortStart()); + response.setEndPort(fwRule.getSourcePortEnd()); + response.setIcmpCode(fwRule.getIcmpCode()); + response.setIcmpType(fwRule.getIcmpType()); Network network = ApiDBUtils.findNetworkById(fwRule.getNetworkId()); response.setNetworkId(network.getUuid()); diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java index 238797e7b4b0..e99b3fe6171a 100644 --- a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java @@ -34,6 +34,7 @@ import org.apache.cloudstack.api.command.user.ipv6.DeleteIpv6FirewallRuleCmd; import org.apache.cloudstack.api.command.user.ipv6.ListIpv6FirewallRulesCmd; import org.apache.cloudstack.api.command.user.ipv6.UpdateIpv6FirewallRuleCmd; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -49,6 +50,8 @@ import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; @@ -56,12 +59,19 @@ import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.firewall.FirewallService; +import com.cloud.network.rules.FirewallManager; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRuleVO; import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentLifecycleBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallbackWithException; +import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.DomainRouterVO; @@ -101,6 +111,12 @@ public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Servi NicDao nicDao; @Inject DomainRouterDao domainRouterDao; + @Inject + AccountManager accountManager; + @Inject + NetworkModel networkModel; + @Inject + FirewallManager firewallManager; protected void releaseIpv6Subnet(long subnetId) { Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO = ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(subnetId); @@ -277,25 +293,128 @@ public List getPublicIpv6AddressesForNetwork(Network network) { return addresses; } - public FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd updateIpv6FirewallRuleCmd) { - // TODO - return firewallDao.findById(updateIpv6FirewallRuleCmd.getId()); - } - @Override public Pair, Integer> listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd) { return firewallService.listFirewallRules(listIpv6FirewallRulesCmd); } @Override - public boolean revokeIpv6FirewallRule(Long id) { - // TODO - return true; + @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription = "creating IPv6 firewall rule", create = true) + public FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd cmd) throws NetworkRuleConflictException { + final Account caller = CallContext.current().getCallingAccount(); + final long networkId = cmd.getNetworkId(); + final Integer portStart = cmd.getSourcePortStart(); + final Integer portEnd = cmd.getSourcePortEnd(); + final FirewallRule.TrafficType trafficType = cmd.getTrafficType(); + final String protocol = cmd.getProtocol(); + final Integer icmpCode = cmd.getIcmpCode(); + final Integer icmpType = cmd.getIcmpType(); + final boolean forDisplay = cmd.isDisplay(); + final FirewallRule.FirewallRuleType type = FirewallRule.FirewallRuleType.User; + final List sourceCidrList = cmd.getSourceCidrList(); + final List destinationCidrList = cmd.getDestinationCidrList(); + + if (portStart != null && !NetUtils.isValidPort(portStart)) { + throw new InvalidParameterValueException("publicPort is an invalid value: " + portStart); + } + if (portEnd != null && !NetUtils.isValidPort(portEnd)) { + throw new InvalidParameterValueException("Public port range is an invalid value: " + portEnd); + } + + // start port can't be bigger than end port + if (portStart != null && portEnd != null && portStart > portEnd) { + throw new InvalidParameterValueException("Start port can't be bigger than end port"); + } + + Network network = networkModel.getNetwork(networkId); + assert network != null : "Can't create rule as network is null?"; + + final long accountId = network.getAccountId(); + final long domainId = network.getDomainId(); + + if (FirewallRule.TrafficType.Egress.equals(trafficType)) { + accountManager.checkAccess(caller, null, true, network); + } + + // Verify that the network guru supports the protocol specified + Map caps = networkModel.getNetworkServiceCapabilities(network.getId(), Network.Service.Firewall); + + if (caps != null) { + String supportedProtocols; + String supportedTrafficTypes = null; + supportedTrafficTypes = caps.get(Network.Capability.SupportedTrafficDirection).toLowerCase(); + + if (trafficType == FirewallRule.TrafficType.Egress) { + supportedProtocols = caps.get(Network.Capability.SupportedEgressProtocols).toLowerCase(); + } else { + supportedProtocols = caps.get(Network.Capability.SupportedProtocols).toLowerCase(); + } + + if (!supportedProtocols.contains(protocol.toLowerCase())) { + throw new InvalidParameterValueException(String.format("Protocol %s is not supported in zone", protocol)); + } else if (!supportedTrafficTypes.contains(trafficType.toString().toLowerCase())) { + throw new InvalidParameterValueException("Traffic Type " + trafficType + " is currently supported by Firewall in network " + networkId); + } + } + + // icmp code and icmp type can't be passed in for any other protocol rather than icmp + if (!protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (icmpCode != null || icmpType != null)) { + throw new InvalidParameterValueException("Can specify icmpCode and icmpType for ICMP protocol only"); + } + + if (protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (portStart != null || portEnd != null)) { + throw new InvalidParameterValueException("Can't specify start/end port when protocol is ICMP"); + } + + return Transaction.execute(new TransactionCallbackWithException() { + @Override + public FirewallRuleVO doInTransaction(TransactionStatus status) throws NetworkRuleConflictException { + FirewallRuleVO newRule = + new FirewallRuleVO(null, null, portStart, portEnd, protocol.toLowerCase(), networkId, accountId, domainId, FirewallRule.Purpose.Ipv6Firewall, + sourceCidrList, destinationCidrList, icmpCode, icmpType, null, trafficType); + newRule.setType(type); + newRule.setDisplay(forDisplay); + newRule = firewallDao.persist(newRule); + + if (FirewallRule.FirewallRuleType.User.equals(type)) { + firewallManager.detectRulesConflict(newRule); + } + + if (!firewallDao.setStateToAdd(newRule)) { + throw new CloudRuntimeException("Unable to update the state to add for " + newRule); + } + CallContext.current().setEventDetails("Rule Id: " + newRule.getId()); + + return newRule; + } + }); } @Override - public FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd createIpv6FirewallRuleCmd) { - return null; + @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_CLOSE, eventDescription = "revoking IPv6 firewall rule", create = true) + public boolean revokeIpv6FirewallRule(Long id) { + FirewallRuleVO rule = firewallDao.findById(id); + if (rule == null) { + throw new InvalidParameterValueException(String.format("Unable to find IPv6 firewall rule with id %d", id)); + } + if (FirewallRule.TrafficType.Ingress.equals(rule.getTrafficType())) { + return firewallManager.revokeIngressFirewallRule(rule.getId(), true); + } + return firewallManager.revokeEgressFirewallRule(rule.getId(), true); + } + + @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_UPDATE, eventDescription = "updating IPv6 firewall rule", create = true) + public FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd cmd) { + final long id = cmd.getId(); + final boolean forDisplay = cmd.isDisplay(); + FirewallRuleVO rule = firewallDao.findById(id); + if (rule == null) { + throw new InvalidParameterValueException(String.format("Unable to find IPv6 firewall rule with id %d", id)); + } + if (FirewallRule.TrafficType.Ingress.equals(rule.getTrafficType())) { + return firewallManager.updateIngressFirewallRule(rule.getId(), null, forDisplay); + } + return firewallManager.updateEgressFirewallRule(rule.getId(), null, forDisplay); } @Override @@ -305,7 +424,18 @@ public FirewallRule getIpv6FirewallRule(Long entityId) { @Override public boolean applyIpv6FirewallRule(long id) { - return false; + FirewallRuleVO rule = firewallDao.findById(id); + if (rule == null) { + s_logger.error(String.format("Unable to find IPv6 firewall rule with ID: %d", id)); + return false; + } + if (!FirewallRule.Purpose.Ipv6Firewall.equals(rule.getPurpose())) { + s_logger.error(String.format("Cannot apply IPv6 firewall rule with ID: %d as purpose %s is not %s", id, rule.getPurpose(), FirewallRule.Purpose.Ipv6Firewall)); + } + s_logger.debug(String.format("Applying IPv6 firewall rules for rule with ID: %s", rule.getUuid())); + List rules = firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), rule.getPurpose(), FirewallRule.TrafficType.Egress); + rules.addAll(firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), FirewallRule.Purpose.Ipv6Firewall, FirewallRule.TrafficType.Ingress)); + return firewallManager.applyFirewallRules(rules, false, CallContext.current().getCallingAccount()); } public class Ipv6GuestPrefixSubnetNetworkMapStateScanner extends ManagedContextRunnable { diff --git a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java index d6a3c63df318..2a2cf1c072e6 100644 --- a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java @@ -17,6 +17,7 @@ package com.cloud.network.firewall; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -346,7 +347,10 @@ public Pair, Integer> listFirewallRules(IListFirewa } else { sc.setParameters("purpose", Purpose.Firewall); } - sc.setParameters("trafficType", trafficType); + + if (trafficType != null) { + sc.setParameters("trafficType", trafficType); + } Pair, Integer> result = _firewallDao.searchAndCount(sc, filter); return new Pair, Integer>(result.first(), result.second()); @@ -559,7 +563,14 @@ public boolean applyRules(List rules, boolean continueOn return true; } Purpose purpose = rules.get(0).getPurpose(); - if (!_ipAddrMgr.applyRules(rules, purpose, this, continueOnError)) { + boolean applied; + if (purpose.equals(Purpose.Ipv6Firewall)) { + Network network = _networkDao.findById(rules.get(0).getNetworkId()); + applied = applyRules(network, purpose, rules); + } else { + applied = _ipAddrMgr.applyRules(rules, purpose, this, continueOnError); + } + if (!applied) { s_logger.warn("Rules are not completely applied"); return false; } else { @@ -598,7 +609,8 @@ public boolean applyRules(Network network, Purpose purpose, List rules = _firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), Purpose.Firewall, FirewallRule.TrafficType.Egress); - return applyFirewallRules(rules, false, caller); + List rules = _firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), Purpose.Firewall, FirewallRule.TrafficType.Egress); + return applyFirewallRules(rules, false, caller); } @Override @@ -730,10 +742,9 @@ public boolean applyDefaultEgressFirewallRule(Long networkId, boolean defaultPol } protected boolean revokeFirewallRule(long ruleId, boolean apply, Account caller, long userId) { - FirewallRuleVO rule = _firewallDao.findById(ruleId); - if (rule == null || rule.getPurpose() != Purpose.Firewall) { - throw new InvalidParameterValueException("Unable to find " + ruleId + " having purpose " + Purpose.Firewall); + if (rule == null || !Arrays.asList(Purpose.Firewall, Purpose.Ipv6Firewall).contains(rule.getPurpose())) { + throw new InvalidParameterValueException("Unable to find " + ruleId + " having purpose " + Arrays.asList(Purpose.Firewall, Purpose.Ipv6Firewall)); } if (rule.getType() == FirewallRuleType.System && !_accountMgr.isRootAdmin(caller.getId())) { @@ -751,11 +762,15 @@ protected boolean revokeFirewallRule(long ruleId, boolean apply, Account caller, // ingress firewall rule if (rule.getSourceIpAddressId() != null) { //feteches ingress firewall, ingress firewall rules associated with the ip - List rules = _firewallDao.listByIpAndPurpose(rule.getSourceIpAddressId(), Purpose.Firewall); - return applyFirewallRules(rules, false, caller); + List rules = _firewallDao.listByIpAndPurpose(rule.getSourceIpAddressId(), Purpose.Firewall); + return applyFirewallRules(rules, false, caller); //egress firewall rule } else if (networkId != null) { - List rules = _firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), Purpose.Firewall, FirewallRule.TrafficType.Egress); + boolean isIpv6 = Purpose.Ipv6Firewall.equals(rule.getPurpose()); + List rules = _firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), rule.getPurpose(), FirewallRule.TrafficType.Egress); + if (isIpv6) { + rules.addAll(_firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), Purpose.Ipv6Firewall, FirewallRule.TrafficType.Ingress)); + } return applyFirewallRules(rules, false, caller); } } else { diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index f34b1e3b771c..0a559e2de107 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -44,6 +44,7 @@ import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; import com.cloud.agent.api.routing.SavePasswordCommand; import com.cloud.agent.api.routing.SetFirewallRulesCommand; +import com.cloud.agent.api.routing.SetIpv6FirewallRulesCommand; import com.cloud.agent.api.routing.SetNetworkACLCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand; @@ -444,6 +445,47 @@ public void createApplyFirewallRulesCommands(final List cmds.addCommand(cmd); } + public void createApplyIpv6FirewallRulesCommands(final List rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) { + final List rulesTO = new ArrayList(); + String systemRule = null; + Boolean defaultEgressPolicy = false; + if (rules != null) { + if (rules.size() > 0) { + if (rules.get(0).getTrafficType() == FirewallRule.TrafficType.Egress && rules.get(0).getType() == FirewallRule.FirewallRuleType.System) { + systemRule = String.valueOf(FirewallRule.FirewallRuleType.System); + } + } + for (final FirewallRule rule : rules) { + _rulesDao.loadSourceCidrs((FirewallRuleVO) rule); + final FirewallRule.TrafficType trafficType = rule.getTrafficType(); + if (trafficType == FirewallRule.TrafficType.Ingress) { + final FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, null, Purpose.Ipv6Firewall, trafficType); + rulesTO.add(ruleTO); + } else if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) { + final NetworkVO network = _networkDao.findById(guestNetworkId); + final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + defaultEgressPolicy = offering.isEgressDefaultPolicy(); + final FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, "", Purpose.Ipv6Firewall, trafficType, defaultEgressPolicy); + rulesTO.add(ruleTO); + } + } + } + + final SetIpv6FirewallRulesCommand cmd = new SetIpv6FirewallRulesCommand(rulesTO); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId())); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId())); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + final DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId()); + cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); + if (systemRule != null) { + cmd.setAccessDetail(NetworkElementCommand.FIREWALL_EGRESS_DEFAULT, systemRule); + } else { + cmd.setAccessDetail(NetworkElementCommand.FIREWALL_EGRESS_DEFAULT, String.valueOf(defaultEgressPolicy)); + } + + cmds.addCommand(cmd); + } + public void createFirewallRulesCommands(final List rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) { final List rulesTO = new ArrayList(); String systemRule = null; @@ -488,6 +530,48 @@ public void createFirewallRulesCommands(final List rules cmds.addCommand(cmd); } + public void createIpv6FirewallRulesCommands(final List rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) { + final List rulesTO = new ArrayList(); + String systemRule = null; + Boolean defaultEgressPolicy = false; + if (rules != null) { + if (rules.size() > 0) { + if (rules.get(0).getTrafficType() == FirewallRule.TrafficType.Egress && rules.get(0).getType() == FirewallRule.FirewallRuleType.System) { + systemRule = String.valueOf(FirewallRule.FirewallRuleType.System); + } + } + for (final FirewallRule rule : rules) { + _rulesDao.loadSourceCidrs((FirewallRuleVO) rule); + _rulesDao.loadDestinationCidrs((FirewallRuleVO)rule); + final FirewallRule.TrafficType traffictype = rule.getTrafficType(); + if (traffictype == FirewallRule.TrafficType.Ingress) { + final FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, null, Purpose.Firewall, traffictype); + rulesTO.add(ruleTO); + } else if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) { + final NetworkVO network = _networkDao.findById(guestNetworkId); + final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + defaultEgressPolicy = offering.isEgressDefaultPolicy(); + final FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, "", Purpose.Firewall, traffictype, defaultEgressPolicy); + rulesTO.add(ruleTO); + } + } + } + + final SetIpv6FirewallRulesCommand cmd = new SetIpv6FirewallRulesCommand(rulesTO); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId())); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId())); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + final DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId()); + cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); + if (systemRule != null) { + cmd.setAccessDetail(NetworkElementCommand.FIREWALL_EGRESS_DEFAULT, systemRule); + } else { + cmd.setAccessDetail(NetworkElementCommand.FIREWALL_EGRESS_DEFAULT, String.valueOf(defaultEgressPolicy)); + } + + cmds.addCommand(cmd); + } + public void createAssociateIPCommands(final VirtualRouter router, final List ips, final Commands cmds, final long vmId) { final String ipAssocCommand = "IPAssocCommand"; createRedundantAssociateIPCommands(router, ips, cmds, ipAssocCommand, false); diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 51a3928ecee8..10adfa4d8cd7 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2424,12 +2424,17 @@ protected void finalizeNetworkRulesForNetwork(final Commands cmds, final DomainR final ArrayList publicIps = getPublicIpsToApply(router, provider, guestNetworkId); final List firewallRulesEgress = new ArrayList(); + final List ipv6firewallRules = new ArrayList<>(); // Fetch firewall Egress rules. if (_networkModel.isProviderSupportServiceInNetwork(guestNetworkId, Service.Firewall, provider)) { firewallRulesEgress.addAll(_rulesDao.listByNetworkPurposeTrafficType(guestNetworkId, Purpose.Firewall, FirewallRule.TrafficType.Egress)); //create egress default rule for VR createDefaultEgressFirewallRule(firewallRulesEgress, guestNetworkId); + + ipv6firewallRules.addAll(_rulesDao.listByNetworkPurposeTrafficType(guestNetworkId, Purpose.Ipv6Firewall, FirewallRule.TrafficType.Egress)); + createDefaultEgressIpv6FirewallRule(firewallRulesEgress, guestNetworkId); + ipv6firewallRules.addAll(_rulesDao.listByNetworkPurposeTrafficType(guestNetworkId, Purpose.Ipv6Firewall, FirewallRule.TrafficType.Ingress)); } // Re-apply firewall Egress rules @@ -2438,6 +2443,11 @@ protected void finalizeNetworkRulesForNetwork(final Commands cmds, final DomainR _commandSetupHelper.createFirewallRulesCommands(firewallRulesEgress, router, cmds, guestNetworkId); } + s_logger.debug(String.format("Found %d Ipv6 firewall rule(s) to apply as a part of domR %s start.", ipv6firewallRules.size(), router)); + if (!ipv6firewallRules.isEmpty()) { + _commandSetupHelper.createIpv6FirewallRulesCommands(ipv6firewallRules, router, cmds, guestNetworkId); + } + if (publicIps != null && !publicIps.isEmpty()) { final List vpns = new ArrayList(); final List pfRules = new ArrayList(); @@ -2584,6 +2594,28 @@ private void createDefaultEgressFirewallRule(final List rules, fin } } + private void createDefaultEgressIpv6FirewallRule(final List rules, final long networkId) { + final NetworkVO network = _networkDao.findById(networkId); + final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + final Boolean defaultEgressPolicy = offering.isEgressDefaultPolicy(); + + // The default on the router is set to Deny all. So, if the default configuration in the offering is set to true (Allow), we change the Egress here + if (defaultEgressPolicy) { + final List sourceCidr = new ArrayList(); + final List destCidr = new ArrayList(); + + sourceCidr.add(network.getCidr()); + destCidr.add(NetUtils.ALL_IP6_CIDRS); + + final FirewallRule rule = new FirewallRuleVO(null, null, null, null, "all", networkId, network.getAccountId(), network.getDomainId(), Purpose.Ipv6Firewall, sourceCidr, + destCidr, null, null, null, FirewallRule.TrafficType.Egress, FirewallRule.FirewallRuleType.System); + + rules.add(rule); + } else { + s_logger.debug("Egress policy for the Network " + networkId + " is already defined as Deny. So, no need to default the IPv6 rule to Allow. "); + } + } + private void removeRevokedIpAliasFromDb(final List revokedIpAliasVOs) { for (final NicIpAliasVO ipalias : revokedIpAliasVOs) { _nicIpAliasDao.expunge(ipalias.getId()); diff --git a/server/src/main/java/org/apache/cloudstack/network/topology/BasicNetworkVisitor.java b/server/src/main/java/org/apache/cloudstack/network/topology/BasicNetworkVisitor.java index d7a94faac0c4..c25c80f5fc22 100644 --- a/server/src/main/java/org/apache/cloudstack/network/topology/BasicNetworkVisitor.java +++ b/server/src/main/java/org/apache/cloudstack/network/topology/BasicNetworkVisitor.java @@ -150,6 +150,12 @@ public boolean visit(final FirewallRules firewall) throws ResourceUnavailableExc return _networkGeneralHelper.sendCommandsToRouter(router, cmds); + } else if (purpose == Purpose.Ipv6Firewall) { + + _commandSetupHelper.createApplyIpv6FirewallRulesCommands(rules, router, cmds, network.getId()); + + return _networkGeneralHelper.sendCommandsToRouter(router, cmds); + } s_logger.warn("Unable to apply rules of purpose: " + rules.get(0).getPurpose()); diff --git a/systemvm/debian/opt/cloud/bin/configure.py b/systemvm/debian/opt/cloud/bin/configure.py index 253065185c14..f5020f06c7b3 100755 --- a/systemvm/debian/opt/cloud/bin/configure.py +++ b/systemvm/debian/opt/cloud/bin/configure.py @@ -333,6 +333,84 @@ def process(self): self.AclIP(self.dbag[item], self.config).create() +class CsIpv6Firewall(CsDataBag): + """ + Deal with IPv6 Firewall + """ + + def flushAllRules(self): + logging.info("Flush all IPv6 firewall rules") + address_family = 'ip6' + table = 'ip6_firewall' + tables = CsHelper.execute("nft list tables %s | grep %s" % (address_family, table)) + if any(table in t for t in tables): + CsHelper.execute("nft delete table %s %s" % (address_family, table)) + + def process(self): + logging.info("Processing IPv6 firewall rules %s" % self.dbag) + fw = self.config.get_ipv6_fw() + for item in self.dbag: + if item == "id": + continue + rule = self.dbag[item] + rstr = "" + + saddr = "" + if 'source_cidr_list' in rule: + source_cidrs = rule['source_cidr_list'] + if len(source_cidrs) == 1: + source_cidrs = source_cidrs[0] + else: + source_cidrs = "{" + (",".join(source_cidrs)) + "}" + saddr = "ip6 saddr " + source_cidrs + daddr = "" + if 'dest_cidr_list' in rule: + dest_cidrs = rule['dest_cidr_list'] + if len(dest_cidrs) == 1: + dest_cidrs = dest_cidrs[0] + else: + dest_cidrs = "{" + (",".join(dest_cidrs)) + "}" + saddr = "ip6 daddr " + dest_cidrs + + proto = "" + protocol = rule['protocol'] + if protocol != "all": + icmp_type = "" + proto = protocol + if protocol == "icmp": + protocol = "icmpv6" + icmp_type = "any" + if 'icmp_type' in rule and rule['icmp_type'] != -1: + icmp_type = rule['icmp_type'] + if proto and icmp_type: + proto = proto + " type " + icmp_type + if 'icmp_code' in rule and rule['icmp_code'] != -1: + proto = proto + " code " + rule['icmp_code'] + first_port = "" + last_port = "" + if 'src_port_range' in rule: + first_port = rule['src_port_range'][0] + last_port = rule['src_port_range'][1] + port = "" + if first_port: + port = first_port + if last_port and port and \ + last_port != first_port: + port = "{%s-%s}" % (port, last_port) + proto = "%s dport %s" % (proto, port) + + action = "accept" + + rstr = saddr + if rstr and daddr: + rstr = rstr + " " + daddr + if rstr and proto: + rstr = rstr + " " + proto + rstr = rstr + " " + action + logging.debug("Process IPv6 firewall rule %s" % rstr) + fw.append(rstr) + + class CsVmMetadata(CsDataBag): def process(self): @@ -1027,6 +1105,10 @@ def process(self): acls.flushAllowAllEgressRules() acls.process() + ip6_fw = CsIpv6Firewall('ipv6firewallrules', self.config) + ip6_fw.flushAllRules() + ip6_fw.process() + fwd = CsForwardingRules("forwardingrules", self.config) fwd.process() @@ -1043,6 +1125,10 @@ def process(self): nf = CsNetfilters() nf.compare(self.config.get_fw()) + logging.info("Configuring nftables IPv6 rules %s" % self.config.get_ipv6_fw()) + nf = CsNetfilters() + nf.apply_ip6_rules(self.config.get_ipv6_fw()) + logging.debug("Configuring iptables rules done ...saving rules") # Save iptables configuration - will be loaded on reboot by the iptables-restore that is configured on /etc/rc.local @@ -1070,22 +1156,23 @@ def main(argv): config.address().compare() config.address().process() - databag_map = OrderedDict([("guest_network", {"process_iptables": True, "executor": [CsVpcGuestNetwork("guestnetwork", config)]}), - ("ip_aliases", {"process_iptables": True, "executor": []}), - ("vm_password", {"process_iptables": False, "executor": [CsPassword("vmpassword", config)]}), - ("vm_metadata", {"process_iptables": False, "executor": [CsVmMetadata('vmdata', config)]}), - ("network_acl", {"process_iptables": True, "executor": []}), - ("firewall_rules", {"process_iptables": True, "executor": []}), - ("forwarding_rules", {"process_iptables": True, "executor": []}), - ("staticnat_rules", {"process_iptables": True, "executor": []}), - ("site_2_site_vpn", {"process_iptables": True, "executor": []}), - ("remote_access_vpn", {"process_iptables": True, "executor": []}), - ("vpn_user_list", {"process_iptables": False, "executor": [CsVpnUser("vpnuserlist", config)]}), - ("vm_dhcp_entry", {"process_iptables": False, "executor": [CsDhcp("dhcpentry", config)]}), - ("dhcp", {"process_iptables": False, "executor": [CsDhcp("dhcpentry", config)]}), - ("load_balancer", {"process_iptables": True, "executor": []}), - ("monitor_service", {"process_iptables": False, "executor": [CsMonitor("monitorservice", config)]}), - ("static_routes", {"process_iptables": False, "executor": [CsStaticRoutes("staticroutes", config)]}) + databag_map = OrderedDict([("guest_network", {"process_iptables": True, "executor": [CsVpcGuestNetwork("guestnetwork", config)]}), + ("ip_aliases", {"process_iptables": True, "executor": []}), + ("vm_password", {"process_iptables": False, "executor": [CsPassword("vmpassword", config)]}), + ("vm_metadata", {"process_iptables": False, "executor": [CsVmMetadata('vmdata', config)]}), + ("network_acl", {"process_iptables": True, "executor": []}), + ("firewall_rules", {"process_iptables": True, "executor": []}), + ("ipv6_firewall_rules", {"process_iptables": True, "executor": []}), + ("forwarding_rules", {"process_iptables": True, "executor": []}), + ("staticnat_rules", {"process_iptables": True, "executor": []}), + ("site_2_site_vpn", {"process_iptables": True, "executor": []}), + ("remote_access_vpn", {"process_iptables": True, "executor": []}), + ("vpn_user_list", {"process_iptables": False, "executor": [CsVpnUser("vpnuserlist", config)]}), + ("vm_dhcp_entry", {"process_iptables": False, "executor": [CsDhcp("dhcpentry", config)]}), + ("dhcp", {"process_iptables": False, "executor": [CsDhcp("dhcpentry", config)]}), + ("load_balancer", {"process_iptables": True, "executor": []}), + ("monitor_service", {"process_iptables": False, "executor": [CsMonitor("monitorservice", config)]}), + ("static_routes", {"process_iptables": False, "executor": [CsStaticRoutes("staticroutes", config)]}) ]) def execDatabag(key, db): diff --git a/systemvm/debian/opt/cloud/bin/cs/CsConfig.py b/systemvm/debian/opt/cloud/bin/cs/CsConfig.py index 390f563c243a..11b16bae2013 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsConfig.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsConfig.py @@ -32,6 +32,7 @@ class CsConfig(object): def __init__(self): self.fw = [] + self.ipv6_fw = [] def set_address(self): self.ips = CsAddress("ips", self) @@ -51,6 +52,9 @@ def address(self): def get_fw(self): return self.fw + def get_ipv6_fw(self): + return self.ipv6_fw + def get_logger(self): return self.__LOG_FILE diff --git a/systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py b/systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py index 01dfa7cac399..12bd67c37b5b 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py @@ -222,6 +222,16 @@ def delete(self, rule): The rule will not actually be removed on the host """ self.rules[:] = [x for x in self.rules if not x == rule] + def apply_ip6_rules(self, list): + address_family = 'ip6' + table = 'ip6_firewall' + chain = 'fw_chain' + CsHelper.execute("nft add table %s %s" % (address_family, table)) + CsHelper.execute("nft add chain %s %s %s '{type filter hook input priority 0; policy drop; }'" % (address_family, table, chain)) + for fw in list: + logging.info("Add: rule=%s in address_family=%s table=%s chain=%s", fw, address_family, table, chain) + CsHelper.execute("nft add rule ip6 ip6_firewall fw_chain %s" % fw) + class CsNetfilter(object): diff --git a/systemvm/debian/opt/cloud/bin/merge.py b/systemvm/debian/opt/cloud/bin/merge.py index 4ab9911824d2..caa3c6bff84b 100755 --- a/systemvm/debian/opt/cloud/bin/merge.py +++ b/systemvm/debian/opt/cloud/bin/merge.py @@ -112,6 +112,8 @@ def process(self): dbag = self.process_network_acl(self.db.getDataBag()) elif self.qFile.type == 'firewallrules': dbag = self.process_firewallrules(self.db.getDataBag()) + elif self.qFile.type == 'ipv6firewallrules': + dbag = self.process_ipv6firewallrules(self.db.getDataBag()) elif self.qFile.type == 'loadbalancer': dbag = self.process_loadbalancer(self.db.getDataBag()) elif self.qFile.type == 'monitorservice': @@ -177,6 +179,9 @@ def process_network_acl(self, dbag): def process_firewallrules(self, dbag): return cs_firewallrules.merge(dbag, self.qFile.data) + def process_ipv6firewallrules(self, dbag): + return cs_firewallrules.merge(dbag, self.qFile.data) + def process_loadbalancer(self, dbag): return cs_loadbalancer.merge(dbag, self.qFile.data) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index a35f7cff9e55..4d332ec41983 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -73,6 +73,7 @@ "label.action.attach.iso.processing": "Attaching ISO....", "label.action.bulk.delete.egress.firewall.rules": "Bulk delete egress firewall rules", "label.action.bulk.delete.firewall.rules": "Bulk delete firewall rules", +"label.action.bulk.delete.ip.v6.firewall.rules": "Bulk remove IPv6 firewall rules", "label.action.bulk.delete.isos": "Bulk delete ISOs", "label.action.bulk.delete.load.balancer.rules": "Bulk delete load balancer rules", "label.action.bulk.delete.portforward.rules": "Bulk delete Port Forward rules", @@ -611,6 +612,7 @@ "label.configure.vpc": "Configure VPC", "label.confirm.delete.egress.firewall.rules": "Please confirm you wish to delete the selected egress firewall rules", "label.confirm.delete.firewall.rules": "Please confirm you wish to delete the selected firewall rules", +"label.confirm.delete.ip.v6.firewall.rules": "Please confirm you wish to delete the selected IPv6 firewall rules", "label.confirm.delete.isos": "Please confirm you wish to delete the selected isos", "label.confirm.delete.loadbalancer.rules": "Please confirm you wish to delete the selected load balancing rules", "label.confirm.delete.portforward.rules": "Please confirm you wish to delete the selected port-forward rules", @@ -2616,6 +2618,12 @@ "message.add.ip.range.to.pod": "

Add an IP range to pod:

", "message.add.iprange.processing": "Adding IP Range...", "message.add.ip.v6.prefix.processing": "Adding IPv6 Prefix...", +"message.add.ip.v6.firewall.rule.failed": "Failed to add IPv6 firewall rule", +"message.add.ip.v6.firewall.rule.processing": "Adding IPv6 firewall rule...", +"message.add.ip.v6.firewall.rule.success": "Added IPv6 firewall rule", +"message.remove.ip.v6.firewall.rule.failed": "Failed to remove IPv6 firewall rule", +"message.remove.ip.v6.firewall.rule.processing": "Removing IPv6 firewall rule...", +"message.remove.ip.v6.firewall.rule.success": "Removed IPv6 firewall rule", "message.add.load.balancer": "Add a load balancer to zone", "message.add.load.balancer.under.ip": "The load balancer rule has been added under IP:", "message.add.network": "Add a new network for zone: ", diff --git a/ui/src/views/network/Ipv6FirewallRulesTab.vue b/ui/src/views/network/Ipv6FirewallRulesTab.vue index 1a3f74459dd8..4b7d56f2b014 100644 --- a/ui/src/views/network/Ipv6FirewallRulesTab.vue +++ b/ui/src/views/network/Ipv6FirewallRulesTab.vue @@ -19,11 +19,11 @@
-
+
{{ $t('label.sourcecidr') }}
-
+
{{ $t('label.destcidr') }}
@@ -86,7 +86,7 @@ icon="delete" style="width: 100%; margin-bottom: 15px" @click="bulkActionConfirmation()"> - {{ $t('label.action.bulk.delete.ipv6.firewall.rules') }} + {{ $t('label.action.bulk.delete.ip.v6.firewall.rules') }} { if (this.selectedItems.length > 0) { eventBus.$emit('update-resource-state', this.selectedItems, rule.id, 'success') } this.fetchData() }, - errorMessage: this.$t('message.remove.ipv6.rule.failed'), + errorMessage: this.$t('message.remove.ip.v6.firewall.rule.failed'), errorMethod: () => { if (this.selectedItems.length > 0) { eventBus.$emit('update-resource-state', this.selectedItems, rule.id, 'failed') } this.fetchData() }, - loadingMessage: this.$t('message.remove.ipv6.rule.processing'), + loadingMessage: this.$t('message.remove.ip.v6.firewall.rule.processing'), catchMessage: this.$t('error.fetching.async.job.result'), catchMethod: () => this.fetchData(), bulkAction: `${this.selectedItems.length > 0}` && this.showGroupActionModal @@ -357,17 +357,17 @@ export default { api('createIpv6FirewallRule', { ...this.newRule }).then(response => { this.$pollJob({ jobId: response.createipv6firewallruleresponse.jobid, - successMessage: this.$t('message.success.add.ipv6.rule'), + successMessage: this.$t('message.add.ip.v6.firewall.rule.success'), successMethod: () => { this.resetAllRules() this.fetchData() }, - errorMessage: this.$t('message.add.ipv6.rule.failed'), + errorMessage: this.$t('message.add.ip.v6.firewall.rule.failed'), errorMethod: () => { this.resetAllRules() this.fetchData() }, - loadingMessage: this.$t('message.add.ipv6.rule.processing'), + loadingMessage: this.$t('message.add.ip.v6.firewall.rule.processing'), catchMessage: this.$t('error.fetching.async.job.result'), catchMethod: () => { this.resetAllRules() From 0e0f3b87b44b2bed5ea3043426c61b8c47ee4fc8 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Mon, 17 Jan 2022 12:27:04 +0530 Subject: [PATCH 031/109] alert and show ipv6 usage Signed-off-by: Abhishek Kumar --- .../java/com/cloud/capacity/Capacity.java | 1 + .../java/com/cloud/network/Ipv6Service.java | 5 ++ .../apache/cloudstack/alert/AlertService.java | 1 + .../apache/cloudstack/api/ApiConstants.java | 5 +- .../DataCenterGuestIpv6PrefixResponse.java | 24 ++++++++ .../java/com/cloud/alert/AlertManager.java | 6 ++ .../java/com/cloud/capacity/CapacityVO.java | 1 + .../Ipv6GuestPrefixSubnetNetworkMapDao.java | 1 + ...pv6GuestPrefixSubnetNetworkMapDaoImpl.java | 23 +++++--- .../com/cloud/alert/AlertManagerImpl.java | 59 ++++++++++++++++--- .../java/com/cloud/api/ApiResponseHelper.java | 6 ++ .../com/cloud/network/Ipv6ServiceImpl.java | 27 +++++++++ ui/public/locales/en.json | 1 + ui/src/views/dashboard/CapacityDashboard.vue | 3 +- .../views/infra/network/IpRangesTabGuest.vue | 9 ++- 15 files changed, 154 insertions(+), 18 deletions(-) diff --git a/api/src/main/java/com/cloud/capacity/Capacity.java b/api/src/main/java/com/cloud/capacity/Capacity.java index ba04a82a5dea..684490a605c3 100644 --- a/api/src/main/java/com/cloud/capacity/Capacity.java +++ b/api/src/main/java/com/cloud/capacity/Capacity.java @@ -30,6 +30,7 @@ public interface Capacity extends InternalIdentity, Identity { public static final short CAPACITY_TYPE_VLAN = 7; public static final short CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP = 8; public static final short CAPACITY_TYPE_LOCAL_STORAGE = 9; + public static final short CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET = 10; public static final short CAPACITY_TYPE_GPU = 19; public static final short CAPACITY_TYPE_CPU_CORE = 90; diff --git a/api/src/main/java/com/cloud/network/Ipv6Service.java b/api/src/main/java/com/cloud/network/Ipv6Service.java index 4a106614eb93..143e51555d97 100644 --- a/api/src/main/java/com/cloud/network/Ipv6Service.java +++ b/api/src/main/java/com/cloud/network/Ipv6Service.java @@ -23,6 +23,7 @@ import org.apache.cloudstack.api.command.user.ipv6.UpdateIpv6FirewallRuleCmd; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterGuestIpv6Prefix; import com.cloud.dc.Vlan; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; @@ -35,6 +36,10 @@ public interface Ipv6Service extends PluggableService { public static final int IPV6_SLAAC_CIDR_NETMASK = 64; + Pair getUsedTotalIpv6SubnetForPrefix(DataCenterGuestIpv6Prefix prefix); + + Pair getUsedTotalIpv6SubnetForZone(long zoneId); + Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws ResourceAllocationException; void assignIpv6SubnetToNetwork(String subnet, long networkId); diff --git a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java index c2cd1b22332e..ff176d8a82ea 100644 --- a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java +++ b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java @@ -42,6 +42,7 @@ private AlertType(short type, String name, boolean isDefault) { public static final AlertType ALERT_TYPE_STORAGE_ALLOCATED = new AlertType(Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, "ALERT.STORAGE.ALLOCATED", true); public static final AlertType ALERT_TYPE_VIRTUAL_NETWORK_PUBLIC_IP = new AlertType(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP, "ALERT.NETWORK.PUBLICIP", true); + public static final AlertType ALERT_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET = new AlertType(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, "ALERT.NETWORK.IPV6SUBNET", true); public static final AlertType ALERT_TYPE_PRIVATE_IP = new AlertType(Capacity.CAPACITY_TYPE_PRIVATE_IP, "ALERT.NETWORK.PRIVATEIP", true); public static final AlertType ALERT_TYPE_SECONDARY_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE, "ALERT.STORAGE.SECONDARY", true); public static final AlertType ALERT_TYPE_HOST = new AlertType((short)7, "ALERT.COMPUTE.HOST", true); diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 28d498a03f50..9b42d32b6726 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -34,6 +34,7 @@ public class ApiConstants { public static final String APPLIED = "applied"; public static final String LIST_LB_VMIPS = "lbvmips"; public static final String AVAILABLE = "available"; + public static final String AVAILABLE_SUBNETS = "availablesubnets"; public static final String BACKUP_ID = "backupid"; public static final String BACKUP_OFFERING_NAME = "backupofferingname"; public static final String BACKUP_OFFERING_ID = "backupofferingid"; @@ -262,6 +263,7 @@ public class ApiConstants { public static final String NEW_END_IP = "newendip"; public static final String NUM_RETRIES = "numretries"; public static final String OFFER_HA = "offerha"; + public static final String ISO_ID = "isoid"; public static final String IS_SYSTEM_OFFERING = "issystem"; public static final String IS_DEFAULT_USE = "defaultuse"; public static final String OLD_FORMAT = "oldformat"; @@ -376,15 +378,16 @@ public class ApiConstants { public static final String TEMPLATE_ID = "templateid"; public static final String TEMPLATE_IDS = "templateids"; public static final String TEMPLATE_NAME = "templatename"; - public static final String ISO_ID = "isoid"; public static final String TIMEOUT = "timeout"; public static final String TIMEZONE = "timezone"; public static final String TIMEZONEOFFSET = "timezoneoffset"; + public static final String TOTAL_SUBNETS = "totalsubnets"; public static final String TYPE = "type"; public static final String TRUST_STORE = "truststore"; public static final String TRUST_STORE_PASSWORD = "truststorepass"; public static final String URL = "url"; public static final String USAGE_INTERFACE = "usageinterface"; + public static final String USED_SUBNETS = "usedsubnets"; public static final String USER_DATA = "userdata"; public static final String USER_FILTER = "userfilter"; public static final String USER_ID = "userid"; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java index e58395b29b80..fd0803f1c581 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/DataCenterGuestIpv6PrefixResponse.java @@ -41,6 +41,18 @@ public class DataCenterGuestIpv6PrefixResponse extends BaseResponse { @Param(description = "id of zone to which the IPv6 prefix belongs to." ) private String zoneId; + @SerializedName(ApiConstants.USED_SUBNETS) + @Param(description = "count of the used IPv6 subnets for the prefix." ) + private Integer usedSubnets; + + @SerializedName(ApiConstants.AVAILABLE_SUBNETS) + @Param(description = "count of the available IPv6 subnets for the prefix." ) + private Integer availableSubnets; + + @SerializedName(ApiConstants.TOTAL_SUBNETS) + @Param(description = "count of the total IPv6 subnets for the prefix." ) + private Integer totalSubnets; + @SerializedName(ApiConstants.CREATED) @Param(description = " date when this IPv6 prefix was created." ) private Date created; @@ -57,6 +69,18 @@ public void setZoneId(String zoneId) { this.zoneId = zoneId; } + public void setUsedSubnets(Integer usedSubnets) { + this.usedSubnets = usedSubnets; + } + + public void setAvailableSubnets(Integer availableSubnets) { + this.availableSubnets = availableSubnets; + } + + public void setTotalSubnets(Integer totalSubnets) { + this.totalSubnets = totalSubnets; + } + public void setCreated(Date created) { this.created = created; } diff --git a/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java b/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java index 6a90e74987f1..2b7ffc9436bd 100644 --- a/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java +++ b/engine/components-api/src/main/java/com/cloud/alert/AlertManager.java @@ -41,6 +41,12 @@ public interface AlertManager extends Manager, AlertService { public static final ConfigKey AlertSmtpEnabledSecurityProtocols = new ConfigKey("Advanced", String.class, "alert.smtp.enabledSecurityProtocols", "", "White-space separated security protocols; ex: \"TLSv1 TLSv1.1\". Supported protocols: SSLv2Hello, SSLv3, TLSv1, TLSv1.1 and TLSv1.2", true); + public static final ConfigKey Ipv6SubnetCapacityThreshold = new ConfigKey("Advanced", Double.class, + "zone.virtualnetwork.ipv6subnet.capacity.notificationthreshold", + "0.75", + "Percentage (as a value between 0 and 1) of guest network IPv6 subnet utilization above which alerts will be sent.", + true); + void clearAlert(AlertType alertType, long dataCenterId, long podId); void recalculateCapacity(); diff --git a/engine/schema/src/main/java/com/cloud/capacity/CapacityVO.java b/engine/schema/src/main/java/com/cloud/capacity/CapacityVO.java index aaae874182fb..50c40134a911 100644 --- a/engine/schema/src/main/java/com/cloud/capacity/CapacityVO.java +++ b/engine/schema/src/main/java/com/cloud/capacity/CapacityVO.java @@ -241,6 +241,7 @@ public String getUuid() { capacityNames.put(CAPACITY_TYPE_LOCAL_STORAGE, "LOCAL_STORAGE"); capacityNames.put(CAPACITY_TYPE_GPU, "GPU"); capacityNames.put(CAPACITY_TYPE_CPU_CORE, "CPU_CORE"); + capacityNames.put(CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, "VIRTUAL_NETWORK_IPV6_SUBNET"); } public static String getCapacityName (Short capacityType) { diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDao.java b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDao.java index 9449a1b4e727..b4f282720ee7 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDao.java @@ -24,6 +24,7 @@ import com.cloud.utils.db.GenericDao; public interface Ipv6GuestPrefixSubnetNetworkMapDao extends GenericDao { + List listUsedByPrefix(long prefixId); Ipv6GuestPrefixSubnetNetworkMapVO findFirstAvailable(long prefixId); Ipv6GuestPrefixSubnetNetworkMapVO findLast(long prefixId); Ipv6GuestPrefixSubnetNetworkMapVO findByNetworkId(long networkId); diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java index 89780b885944..6aa73e415814 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Ipv6GuestPrefixSubnetNetworkMapDaoImpl.java @@ -36,7 +36,7 @@ @DB public class Ipv6GuestPrefixSubnetNetworkMapDaoImpl extends GenericDaoBase implements Ipv6GuestPrefixSubnetNetworkMapDao { - protected SearchBuilder FreeSubnetSearch; + protected SearchBuilder PrefixStateSearch; protected SearchBuilder PrefixIdSearch; protected SearchBuilder NetworkIdSearch; protected SearchBuilder SubnetSearch; @@ -44,10 +44,10 @@ public class Ipv6GuestPrefixSubnetNetworkMapDaoImpl extends GenericDaoBase listUsedByPrefix(long prefixId) { + SearchCriteria sc = PrefixStateSearch.create(); + sc.setParameters("prefixId", prefixId); + sc.setParameters("state", (Object[]) new Ipv6GuestPrefixSubnetNetworkMap.State[]{Ipv6GuestPrefixSubnetNetworkMap.State.Allocated, Ipv6GuestPrefixSubnetNetworkMap.State.Allocating}); + Filter searchFilter = new Filter(Ipv6GuestPrefixSubnetNetworkMapVO.class, "id", true, null, 1L); + return listBy(sc, searchFilter); + } + @Override public Ipv6GuestPrefixSubnetNetworkMapVO findFirstAvailable(long prefixId) { - SearchCriteria sc = FreeSubnetSearch.create(); + SearchCriteria sc = PrefixStateSearch.create(); sc.setParameters("prefixId", prefixId); - sc.setParameters("state", Ipv6GuestPrefixSubnetNetworkMap.State.Free); + sc.setParameters("state", (Object[]) new Ipv6GuestPrefixSubnetNetworkMap.State[]{Ipv6GuestPrefixSubnetNetworkMap.State.Free}); Filter searchFilter = new Filter(Ipv6GuestPrefixSubnetNetworkMapVO.class, "id", true, null, 1L); List list = listBy(sc, searchFilter); return CollectionUtils.isNotEmpty(list) ? list.get(0) : null; diff --git a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java index 51e5051bc9bd..4faa188513cd 100644 --- a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java @@ -21,8 +21,10 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Timer; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -38,6 +40,11 @@ import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.utils.mailing.MailAddress; +import org.apache.cloudstack.utils.mailing.SMTPMailProperties; +import org.apache.cloudstack.utils.mailing.SMTPMailSender; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.apache.log4j.Logger; import com.cloud.alert.dao.AlertDao; @@ -64,22 +71,17 @@ import com.cloud.event.EventTypes; import com.cloud.host.Host; import com.cloud.host.HostVO; +import com.cloud.network.Ipv6Service; import com.cloud.network.dao.IPAddressDao; import com.cloud.org.Grouping.AllocationState; import com.cloud.resource.ResourceManager; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; +import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.SearchCriteria; -import java.util.HashSet; -import java.util.Set; -import org.apache.cloudstack.utils.mailing.MailAddress; -import org.apache.cloudstack.utils.mailing.SMTPMailProperties; -import org.apache.cloudstack.utils.mailing.SMTPMailSender; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.math.NumberUtils; public class AlertManagerImpl extends ManagerBase implements AlertManager, Configurable { protected Logger logger = Logger.getLogger(AlertManagerImpl.class.getName()); @@ -119,6 +121,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi protected ConfigDepot _configDepot; @Inject ServiceOfferingDao _offeringsDao; + @Inject + Ipv6Service ipv6Service; private Timer _timer = null; private long _capacityCheckPeriod = 60L * 60L * 1000L; // One hour by default. @@ -196,6 +200,7 @@ public boolean configure(String name, Map params) throws Configu _capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_VLAN, _vlanCapacityThreshold); _capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP, _directNetworkPublicIpCapacityThreshold); _capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_LOCAL_STORAGE, _localStorageCapacityThreshold); + _capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, Ipv6SubnetCapacityThreshold.value()); String capacityCheckPeriodStr = configs.get("capacity.check.period"); if (capacityCheckPeriodStr != null) { @@ -314,6 +319,7 @@ public void recalculateCapacity() { // Calculate new Public IP capacity for Virtual Network if (datacenter.getNetworkType() == NetworkType.Advanced) { createOrUpdateIpCapacity(dcId, null, Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP, datacenter.getAllocationState()); + createOrUpdateIpv6Capacity(dcId, Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, datacenter.getAllocationState()); } // Calculate new Public IP capacity for Direct Attached Network @@ -416,6 +422,35 @@ public void createOrUpdateIpCapacity(Long dcId, Long podId, short capacityType, } } + public void createOrUpdateIpv6Capacity(Long dcId, short capacityType, AllocationState capacityState) { + SearchCriteria capacitySC = _capacityDao.createSearchCriteria(); + capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, dcId); + capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, capacityType); + + int total = 0; + int allocated = 0; + List capacities = _capacityDao.search(capacitySC, null); + if (capacityType == Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET) { + Pair usedTotal = ipv6Service.getUsedTotalIpv6SubnetForZone(dcId); + total = usedTotal.second(); + allocated = usedTotal.first(); + } + + CapacityState state = (capacityState == AllocationState.Disabled) ? CapacityState.Disabled : CapacityState.Enabled; + if (capacities.size() == 0) { + CapacityVO capacityVO = new CapacityVO(null, dcId, null, null, allocated, total, capacityType); + capacityVO.setCapacityState(state); + _capacityDao.persist(capacityVO); + } else if (!(capacities.get(0).getUsedCapacity() == allocated && capacities.get(0).getTotalCapacity() == total + && capacities.get(0).getCapacityState() == state)) { + CapacityVO capacity = capacities.get(0); + capacity.setUsedCapacity(allocated); + capacity.setTotalCapacity(total); + capacity.setCapacityState(state); + _capacityDao.update(capacity.getId(), capacity); + } + } + class CapacityChecker extends ManagedContextTimerTask { @Override protected void runInContext() { @@ -626,6 +661,13 @@ private void generateEmailAlert(DataCenterVO dc, HostPodVO pod, ClusterVO cluste msgContent = "Number of unallocated VLANs is low, total: " + totalStr + ", allocated: " + usedStr + " (" + pctStr + "%)"; alertType = AlertManager.AlertType.ALERT_TYPE_VLAN; break; + case Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET: + msgSubject = "System Alert: Number of unallocated virtual network guest IPv6 subnets is low in availability zone " + dc.getName(); + totalStr = Double.toString(totalCapacity); + usedStr = Double.toString(usedCapacity); + msgContent = "Number of unallocated virtual network guest IPv6 subnets is low, total: " + totalStr + ", allocated: " + usedStr + " (" + pctStr + "%)"; + alertType = AlertManager.AlertType.ALERT_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET; + break; } try { @@ -646,6 +688,7 @@ private List getCapacityTypesAtZoneLevel() { dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP); dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE); dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_VLAN); + dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET); return dataCenterCapacityTypes; } @@ -760,7 +803,7 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {CPUCapacityThreshold, MemoryCapacityThreshold, StorageAllocatedCapacityThreshold, StorageCapacityThreshold, AlertSmtpEnabledSecurityProtocols, - AlertSmtpUseStartTLS}; + AlertSmtpUseStartTLS, Ipv6SubnetCapacityThreshold}; } @Override diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 7b8f95fb27e3..ff3d163cd476 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -1268,6 +1268,12 @@ public DataCenterGuestIpv6PrefixResponse createDataCenterGuestIpv6PrefixResponse response.setPrefix(prefix.getPrefix()); DataCenter dc = ApiDBUtils.findZoneById(prefix.getDataCenterId()); response.setZoneId(dc.getUuid()); + Pair usedTotal = ipv6Service.getUsedTotalIpv6SubnetForPrefix(prefix); + int used = usedTotal.first(); + int total = usedTotal.second(); + response.setUsedSubnets(used); + response.setAvailableSubnets(total - used); + response.setTotalSubnets(total); response.setCreated(prefix.getCreated()); return response; } diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java index e99b3fe6171a..bc53b7b575e0 100644 --- a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java +++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java @@ -42,6 +42,7 @@ import com.cloud.configuration.Resource; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterGuestIpv6Prefix; import com.cloud.dc.DataCenterGuestIpv6PrefixVO; import com.cloud.dc.Vlan; import com.cloud.dc.VlanVO; @@ -153,6 +154,32 @@ public List> getCommands() { return cmdList; } + @Override + public Pair getUsedTotalIpv6SubnetForPrefix(DataCenterGuestIpv6Prefix prefix) { + List usedSubnets = ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(prefix.getId()); + final IPv6Network ip6Prefix = IPv6Network.fromString(prefix.getPrefix()); + Iterator splits = ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(IPV6_SLAAC_CIDR_NETMASK)); + int total = 0; + while(splits.hasNext()) { + total++; + splits.next(); + } + return new Pair<>(usedSubnets.size(), total); + } + + @Override + public Pair getUsedTotalIpv6SubnetForZone(long zoneId) { + int used = 0; + int total = 0; + List prefixes = dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); + for (DataCenterGuestIpv6PrefixVO prefix : prefixes) { + Pair usedTotal = getUsedTotalIpv6SubnetForPrefix(prefix); + used += usedTotal.first(); + total += usedTotal.second(); + } + return new Pair<>(used, total); + } + public Pair preAllocateIpv6SubnetForNetwork(long zoneId) throws ResourceAllocationException { List prefixes = dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); if (CollectionUtils.isEmpty(prefixes)) { diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 4d332ec41983..381d8bf1f72e 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1188,6 +1188,7 @@ "label.ipv4.dns2": "IPv4 DNS2", "label.ipv6.dns1": "IPv6 DNS1", "label.ipv6.dns2": "IPv6 DNS2", +"label.ipv6.subnets": "IPv6 Subnets", "label.iqn": "Target IQN", "label.is.in.progress": "is in progress", "label.is.redundant.router": "Redundant", diff --git a/ui/src/views/dashboard/CapacityDashboard.vue b/ui/src/views/dashboard/CapacityDashboard.vue index 5c4591cb1af7..3f548e87718a 100644 --- a/ui/src/views/dashboard/CapacityDashboard.vue +++ b/ui/src/views/dashboard/CapacityDashboard.vue @@ -158,7 +158,8 @@ export default { STORAGE: 'label.storage', STORAGE_ALLOCATED: 'label.primary.storage', VIRTUAL_NETWORK_PUBLIC_IP: 'label.public.ips', - VLAN: 'label.vlan' + VLAN: 'label.vlan', + VIRTUAL_NETWORK_IPV6_SUBNET: 'label.ipv6.subnets' } } }, diff --git a/ui/src/views/infra/network/IpRangesTabGuest.vue b/ui/src/views/infra/network/IpRangesTabGuest.vue index f588ca24623d..2a24553e456f 100644 --- a/ui/src/views/infra/network/IpRangesTabGuest.vue +++ b/ui/src/views/infra/network/IpRangesTabGuest.vue @@ -35,6 +35,9 @@ :rowKey="record => record.id + record.prefix" :pagination="false" > +