weizhouapache commented on a change in pull request #5786:
URL: https://github.com/apache/cloudstack/pull/5786#discussion_r814854410



##########
File path: utils/src/main/java/com/cloud/utils/net/NetUtils.java
##########
@@ -1681,7 +1681,7 @@ public static boolean isIpv4(String ipAddr) {
     public static boolean ipv6NetworksOverlap(IPv6Network n1, IPv6Network n2) {
         IPv6Network higher = n1;
         IPv6Network lower = n2;
-        if (lower.getNetmask().asPrefixLength() > 
higher.getNetmask().asPrefixLength()) {
+        if (lower.getNetmask().asPrefixLength() < 
higher.getNetmask().asPrefixLength()) {

Review comment:
       @shwstppr good fix !
   it works well now :1st_place_medal: 

##########
File path: 
api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java
##########
@@ -92,6 +92,12 @@
     @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 ip4 and dualstack. Default is ipv4. dualstack will create a network 
offering that supports both IPv4 and IPv6",

Review comment:
       typo: `ipv4` not `ip4`

##########
File path: 
api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java
##########
@@ -0,0 +1,245 @@
+// 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.FirewallResponse;
+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.NetworkRuleConflictException;
+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 source CIDR list to 
allow traffic from. Multiple entries must be separated by a single comma 
character (,).")
+    private List<String> 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<String> destinationCidrlist;
+
+    @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", required = true)

Review comment:
       is `networkid` a required parameter ?

##########
File path: server/src/main/java/com/cloud/alert/AlertManagerImpl.java
##########
@@ -416,6 +422,35 @@ public void createOrUpdateIpCapacity(Long dcId, Long 
podId, short capacityType,
         }
     }
 
+    public void createOrUpdateIpv6Capacity(Long dcId, short capacityType, 
AllocationState capacityState) {

Review comment:
       is capacityType fixed as CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET ?

##########
File path: 
server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -4067,21 +4166,21 @@ public Vlan createVlanAndPublicIpRange(final 
CreateVlanIpRangeCmd cmd) throws In
                 zoneId = network.getDataCenterId();
                 physicalNetworkId = network.getPhysicalNetworkId();
             }
-        } else if (ipv6) {
+        }/* else if (ipv6) {

Review comment:
       this can be removed

##########
File path: 
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();

Review comment:
       should owner be the owner of the fireawall rule ?

##########
File path: 
api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java
##########
@@ -0,0 +1,245 @@
+// 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.FirewallResponse;
+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.NetworkRuleConflictException;
+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 source CIDR list to 
allow traffic from. Multiple entries must be separated by a single comma 
character (,).")
+    private List<String> 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<String> destinationCidrlist;
+
+    @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", 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")
+    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)) {

Review comment:
       what about 'tcp' and 'udp' ?
   will other protocol numbers be supported also ?
   see https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml

##########
File path: 
api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/ListIpv6FirewallRulesCmd.java
##########
@@ -0,0 +1,137 @@
+// 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.FirewallResponse;
+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")

Review comment:
       if seems `action` is not used anywhere. if so, it can be removed.

##########
File path: 
server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -4024,6 +4116,13 @@ public Vlan createVlanAndPublicIpRange(final 
CreateVlanIpRangeCmd cmd) throws In
             if (endIPv6 == null && startIPv6 != null) {
                 endIPv6 = startIPv6;
             }
+
+            if (startIPv6 == null && endIPv6 == null) {

Review comment:
       is `if (startIPv6 == null && endIPv6 == null) {` check needed ?

##########
File path: server/src/main/java/com/cloud/api/ApiResponseHelper.java
##########
@@ -792,6 +809,20 @@ public VlanIpRangeResponse 
createVlanIpRangeResponse(Class<? extends VlanIpRange
                 String[] range = ip6Range.split("-");
                 vlanResponse.setStartIpv6(range[0]);
                 vlanResponse.setEndIpv6(range[1]);
+
+                IPv6Address first = IPv6Address.fromString(range[0]);

Review comment:
       can this be extracted as a method ?

##########
File path: 
api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java
##########
@@ -0,0 +1,245 @@
+// 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.FirewallResponse;
+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.NetworkRuleConflictException;
+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

Review comment:
       ```    @Inject
       Ipv6Service ipv6Service;
   ```
   
   can be moved to BaseCmd.java, so that it is not needed to inject in  
*Cmd.java

##########
File path: 
server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
##########
@@ -2583,6 +2598,21 @@ private void createDefaultEgressFirewallRule(final 
List<FirewallRule> rules, fin
         }
     }
 
+    private void createDefaultEgressIpv6FirewallRule(final List<FirewallRule> 
rules, final long networkId) {
+        final NetworkVO network = _networkDao.findById(networkId);
+        
if(!_networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId())) {
+            return;
+        }
+        // Since not all networks will IPv6 supported, add a system rule for 
IPv6 networks
+        final List<String> sourceCidr = new ArrayList<String>();
+        final List<String> destCidr = new ArrayList<String>();
+        sourceCidr.add(network.getIp6Cidr());
+        destCidr.add(NetUtils.ALL_IP6_CIDRS);
+        final FirewallRule rule = new FirewallRuleVO(null, null, null, null, 
"all", networkId, network.getAccountId(), network.getDomainId(), 
Purpose.Ipv6Firewall, sourceCidr,

Review comment:
       OK. so by default, all egress rules are allowed, right ?
   can you define a constant for 'all' ?

##########
File path: 
server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -5644,6 +5751,16 @@ public NetworkOffering createNetworkOffering(final 
CreateNetworkOfferingCmd cmd)
             throw new InvalidParameterValueException("Invalid \"type\" 
parameter is given; can have Shared and Isolated values");
         }
 
+        if (internetProtocol != null) {

Review comment:
       good this is fixed. I have encountered an issue here.

##########
File path: 
server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -1884,6 +1899,83 @@ private void checkIpRangeContainsTakenAddresses(final 
HostPodVO pod,final String
         }
     }
 
+    @Override
+    @DB
+    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 String prefix = cmd.getPrefix();
+        IPv6Network prefixNet = IPv6Network.fromString(prefix);
+        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<DataCenterGuestIpv6PrefixVO> 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<DataCenterGuestIpv6Prefix>() {
+                @Override
+                public DataCenterGuestIpv6Prefix 
doInTransaction(TransactionStatus status) {
+                    DataCenterGuestIpv6PrefixVO dataCenterGuestIpv6PrefixVO = 
new DataCenterGuestIpv6PrefixVO(zoneId, prefix);
+                    
dataCenterGuestIpv6PrefixDao.persist(dataCenterGuestIpv6PrefixVO);
+                    return dataCenterGuestIpv6PrefixVO;
+                }
+            });
+        } catch (final Exception e) {
+            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 dataCenterGuestIpv6Prefix;
+    }
+
+    @Override
+    public List<? extends DataCenterGuestIpv6Prefix> 
listDataCenterGuestIpv6Prefixes(final ListGuestNetworkIpv6PrefixesCmd cmd) 
throws ConcurrentOperationException {
+        final Long id = cmd.getId();
+        final Long zoneId = cmd.getZoneId();
+        if (id != null) {
+            DataCenterGuestIpv6PrefixVO prefix = 
dataCenterGuestIpv6PrefixDao.findById(id);
+            List<DataCenterGuestIpv6PrefixVO> prefixes = new ArrayList<>();
+            if (prefix != null) {
+                prefixes.add(prefix);
+            }
+            return prefixes;
+        }
+        if (zoneId != null) {
+            final DataCenterVO zone = _zoneDao.findById(zoneId);
+            if (zone == null) {
+                throw new InvalidParameterValueException("Unable to find zone 
by id: " + zoneId);
+            }
+            return dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId);
+        }
+        return dataCenterGuestIpv6PrefixDao.listAll();
+    }
+
+    @Override
+    public boolean 
deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6PrefixCmd 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<Ipv6GuestPrefixSubnetNetworkMapVO> prefixSubnets = 
ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(prefixId);
+        if (CollectionUtils.isNotEmpty(prefixSubnets)) {
+            List<String> 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(String.format("Unable to delete 
guest network IPv6 prefix ID: %s. Prefix subnets are in use.", 
prefix.getUuid()));
+        }
+        ipv6GuestPrefixSubnetNetworkMapDao.deleteByPrefixId(prefixId);

Review comment:
       `prefixSubnets` is empty, is it needed to delete records by prefixid ?

##########
File path: 
server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
##########
@@ -4067,21 +4166,21 @@ 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);
         if (zone == null) {
             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) {

Review comment:
       remove this, add check on global setting `Ipv6SubnetCapacityThreshold` 
here ?

##########
File path: server/src/main/java/com/cloud/server/ManagementServerImpl.java
##########
@@ -3529,6 +3532,9 @@ public long getMemoryOrCpuCapacityByHost(final Long 
hostId, final short capacity
         cmdList.add(AcquirePodIpCmdByAdmin.class);
         cmdList.add(ReleasePodIpCmdByAdmin.class);
         cmdList.add(CreateManagementNetworkIpRangeCmd.class);
+        cmdList.add(CreateGuestNetworkIpv6PrefixCmd.class);

Review comment:
       in Ipv6ServiceImpl.java ?

##########
File path: 
api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java
##########
@@ -0,0 +1,245 @@
+// 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.FirewallResponse;
+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.NetworkRuleConflictException;
+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 source CIDR list to 
allow traffic from. Multiple entries must be separated by a single comma 
character (,).")
+    private List<String> 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<String> destinationCidrlist;
+
+    @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", 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")
+    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<String> getSourceCidrList() {
+        if (sourceCidrList != null) {
+            return sourceCidrList;
+        } else {
+            List<String> oneCidrList = new ArrayList<String>();
+            oneCidrList.add(NetUtils.ALL_IP6_CIDRS);
+            return oneCidrList;
+        }
+    }
+
+    public List<String> getDestinationCidrList() {
+        if (destinationCidrlist != null) {
+            return destinationCidrlist;
+        } else {
+            List<String> oneCidrList = new ArrayList<String>();
+            oneCidrList.add(NetUtils.ALL_IP6_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();

Review comment:
       should entity owner be the owner of the network ?

##########
File path: 
api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/UpdateIpv6FirewallRuleCmd.java
##########
@@ -0,0 +1,177 @@
+// 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.FirewallResponse;
+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<String> 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<String> 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() {

Review comment:
       owner of the firewall rule ?

##########
File path: server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java
##########
@@ -0,0 +1,517 @@
+// 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.ArrayList;
+import java.util.Collections;
+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.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.context.CallContext;
+import org.apache.cloudstack.framework.config.ConfigKey;
+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;
+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;
+import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.event.ActionEvent;
+import com.cloud.event.ActionEventUtils;
+import com.cloud.event.EventTypes;
+import com.cloud.event.EventVO;
+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;
+import com.cloud.network.dao.NetworkDetailsDao;
+import com.cloud.network.firewall.FirewallService;
+import com.cloud.network.guru.PublicNetworkGuru;
+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;
+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.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
+    FirewallRulesDao firewallDao;
+    @Inject
+    FirewallService firewallService;
+    @Inject
+    NetworkDetailsDao networkDetailsDao;
+    @Inject
+    NicDao nicDao;
+    @Inject
+    DomainRouterDao domainRouterDao;
+    @Inject
+    AccountManager accountManager;
+    @Inject
+    NetworkModel networkModel;
+    @Inject
+    FirewallManager firewallManager;
+
+    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 boolean start() {
+        
_ipv6GuestPrefixSubnetNetworkMapStateScanner.scheduleWithFixedDelay(new 
Ipv6GuestPrefixSubnetNetworkMapStateScanner(), 300, 30*60, TimeUnit.SECONDS);
+        return true;
+    }
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws 
ConfigurationException {
+        _name = name;
+        _configParams = params;
+        _ipv6GuestPrefixSubnetNetworkMapStateScanner = 
Executors.newScheduledThreadPool(1, new 
NamedThreadFactory("Ipv6GuestPrefixSubnet-State-Scanner"));
+
+        return true;
+    }
+
+    @Override
+    public List<Class<?>> getCommands() {
+        final List<Class<?>> cmdList = new ArrayList<Class<?>>();
+        cmdList.add(CreateIpv6FirewallRuleCmd.class);
+        cmdList.add(ListIpv6FirewallRulesCmd.class);
+        cmdList.add(UpdateIpv6FirewallRuleCmd.class);
+        cmdList.add(DeleteIpv6FirewallRuleCmd.class);
+        return cmdList;
+    }
+
+    @Override
+    public String getConfigComponentName() {
+        return Ipv6Service.class.getSimpleName();
+    }
+
+    @Override
+    public ConfigKey<?>[] getConfigKeys() {
+        return new ConfigKey<?>[] {
+                Ipv6NetworkOfferingCreationEnabled
+        };
+    }
+
+    @Override
+    public Pair<Integer, Integer> 
getUsedTotalIpv6SubnetForPrefix(DataCenterGuestIpv6Prefix prefix) {
+        List<Ipv6GuestPrefixSubnetNetworkMapVO> usedSubnets = 
ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(prefix.getId());
+        final IPv6Network ip6Prefix = 
IPv6Network.fromString(prefix.getPrefix());
+        Iterator<IPv6Network> 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<Integer, Integer> getUsedTotalIpv6SubnetForZone(long zoneId) {
+        int used = 0;
+        int total = 0;
+        List<DataCenterGuestIpv6PrefixVO> prefixes = 
dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId);
+        for (DataCenterGuestIpv6PrefixVO prefix : prefixes) {
+            Pair<Integer, Integer> usedTotal = 
getUsedTotalIpv6SubnetForPrefix(prefix);
+            used += usedTotal.first();
+            total += usedTotal.second();
+        }
+        return new Pair<>(used, total);
+    }
+
+    public Pair<String, String> preAllocateIpv6SubnetForNetwork(long zoneId) 
throws ResourceAllocationException {
+        List<DataCenterGuestIpv6PrefixVO> 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<IPv6Network> splits = 
ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(IPV6_SLAAC_CIDR_NETMASK));
+                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());
+        }
+    }
+
+    public Pair<String, ? extends Vlan> assignPublicIpv6ToNetwork(Network 
network, String nicMacAddress) {
+        final List<VlanVO> 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()));
+        }
+        Collections.shuffle(ranges);
+        VlanVO selectedVlan = ranges.get(0);
+        IPv6Network iPv6Network = 
IPv6Network.fromString(selectedVlan.getIp6Cidr());
+        if (iPv6Network.getNetmask().asPrefixLength() < 
IPV6_SLAAC_CIDR_NETMASK) {
+            Iterator<IPv6Network> splits = 
iPv6Network.split(IPv6NetworkMask.fromPrefixLength(IPV6_SLAAC_CIDR_NETMASK));
+            if (splits.hasNext()) {
+                splits.next();
+            }
+            if (splits.hasNext()) {
+                iPv6Network = splits.next();
+            }
+        }
+        IPv6Address ipv6Addr = NetUtils.EUI64Address(iPv6Network, 
nicMacAddress);
+        String event = EventTypes.EVENT_NET_IP6_ASSIGN;
+        String description = String.format("Assigned public IPv6 address: %s 
for network ID: %s", ipv6Addr,  network.getUuid());
+        
ActionEventUtils.onCompletedActionEvent(CallContext.current().getCallingUserId(),
 network.getAccountId(), EventVO.LEVEL_INFO, event, description, 0);
+        final boolean usageHidden = 
networkDetailsDao.isNetworkUsageHidden(network.getId());
+        final String guestType = selectedVlan.getVlanType().toString();
+        UsageEventUtils.publishUsageEvent(event, 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<String, ? extends Vlan> 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);
+            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 releasePublicIpv6ForNic(Network network, String 
nicIpv6Address) {
+        String event = EventTypes.EVENT_NET_IP6_RELEASE;
+        String description = String.format("Releasing public IPv6 address: %s 
from network ID: %s", nicIpv6Address,  network.getUuid());
+        
ActionEventUtils.onCompletedActionEvent(CallContext.current().getCallingUserId(),
 network.getAccountId(), EventVO.LEVEL_INFO, event, description, 0);
+        final boolean usageHidden = 
networkDetailsDao.isNetworkUsageHidden(network.getId());
+        UsageEventUtils.publishUsageEvent(event, network.getAccountId(), 
network.getDataCenterId(), 0L,
+                nicIpv6Address, false, 
Vlan.VlanType.VirtualNetwork.toString(), false, usageHidden,
+                IPv6Address.class.getName(), null);
+    }
+
+    @Override
+    public List<String> getPublicIpv6AddressesForNetwork(Network network) {
+        List<String> addresses = new ArrayList<>();
+        List<DomainRouterVO> routers = 
domainRouterDao.findByNetwork(network.getId());
+        for (DomainRouterVO router : routers) {
+            List<NicVO> nics = nicDao.listByVmId(router.getId());
+            for (NicVO nic : nics) {
+                String address = nic.getIPv6Address();
+                if 
(!PublicNetworkGuru.class.getSimpleName().equals(nic.getReserver()) || 
StringUtils.isEmpty(address)) {
+                    continue;
+                }
+                addresses.add(address);
+            }
+        }
+        return addresses;
+    }
+
+    @Override
+    public Pair<List<? extends FirewallRule>, Integer> 
listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd) {
+        return firewallService.listFirewallRules(listIpv6FirewallRulesCmd);
+    }
+
+    @Override
+    @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<String> sourceCidrList = cmd.getSourceCidrList();
+        final List<String> 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<Network.Capability, String> 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<FirewallRuleVO, 
NetworkRuleConflictException>() {
+            @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
+    @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_CLOSE, eventDescription 
= "revoking IPv6 firewall rule", async = 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", async = 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
+    public FirewallRule getIpv6FirewallRule(Long entityId) {
+        return firewallDao.findById(entityId);
+    }
+
+    @Override
+    public boolean applyIpv6FirewallRule(long id) {
+        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<FirewallRuleVO> 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 {
+        @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<Ipv6GuestPrefixSubnetNetworkMapVO> 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) {

Review comment:
       can this be configurable ?

##########
File path: ui/src/views/infra/network/IpRangesTabPublic.vue
##########
@@ -34,6 +34,18 @@
       :rowKey="record => record.id"
       :pagination="false"
     >
+      <template slot="gateway" slot-scope="record">
+        {{ record.gateway || record.ip6gateway }}
+      </template>
+      <template slot="cidr" slot-scope="record">
+        {{ record.netmask || record.ip6cidr }}

Review comment:
       use `record.cidr` instead of `record.netmask` ?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to