You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ra...@apache.org on 2018/09/11 15:03:25 UTC

[cloudstack] branch master updated: Support IPv6 address in addIpToNic (#2773)

This is an automated email from the ASF dual-hosted git repository.

rafael pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new fbf4884  Support IPv6 address in addIpToNic (#2773)
fbf4884 is described below

commit fbf488497fb863c13fc0908281e3f4f86906df43
Author: Gabriel Beims Bräscher <ga...@gmail.com>
AuthorDate: Tue Sep 11 12:03:19 2018 -0300

    Support IPv6 address in addIpToNic (#2773)
    
    The admin will manually need to add the address to the Instance, but the
    Security Grouping should allow it.
---
 .../main/java/com/cloud/network/NetworkModel.java  |   2 +-
 .../java/com/cloud/network/NetworkService.java     |  20 +-
 .../api/command/user/vm/AddIpToVmNicCmd.java       |  29 +--
 .../api/command/user/vm/RemoveIpFromVmNicCmd.java  |   7 +-
 .../api/command/test/AddIpToVmNicTest.java         |   4 +-
 .../java/com/cloud/network/IpAddressManager.java   |  18 +-
 .../java/com/cloud/vm/dao/NicIpAliasDaoImpl.java   |   1 +
 .../java/com/cloud/vm/dao/NicSecondaryIpDao.java   |   6 +-
 .../com/cloud/vm/dao/NicSecondaryIpDaoImpl.java    |  15 +-
 .../main/java/com/cloud/api/ApiResponseHelper.java |  17 +-
 .../com/cloud/api/query/dao/UserVmJoinDaoImpl.java |   8 +-
 .../com/cloud/network/IpAddressManagerImpl.java    |  44 ++--
 .../java/com/cloud/network/Ipv6AddressManager.java |   7 +
 .../com/cloud/network/Ipv6AddressManagerImpl.java  | 118 ++++++++++-
 .../java/com/cloud/network/NetworkModelImpl.java   |   4 +-
 .../java/com/cloud/network/NetworkServiceImpl.java |  78 ++++---
 .../com/cloud/network/guru/DirectNetworkGuru.java  |  20 +-
 .../java/com/cloud/api/ApiResponseHelperTest.java  |  32 +++
 .../com/cloud/network/IpAddressManagerTest.java    |  87 +++++++-
 .../com/cloud/network/Ipv6AddressManagerTest.java  | 229 +++++++++++++++++++++
 .../com/cloud/network/MockNetworkModelImpl.java    |   2 +-
 .../java/com/cloud/vpc/MockNetworkManagerImpl.java |   3 +-
 .../java/com/cloud/vpc/MockNetworkModelImpl.java   |   2 +-
 ui/lib/jquery.validate.additional-methods.js       |  10 +
 ui/scripts/network.js                              |   2 +-
 .../main/java/com/cloud/utils/net/NetUtils.java    |  18 +-
 .../java/com/cloud/utils/net/NetUtilsTest.java     |  16 ++
 27 files changed, 671 insertions(+), 128 deletions(-)

diff --git a/api/src/main/java/com/cloud/network/NetworkModel.java b/api/src/main/java/com/cloud/network/NetworkModel.java
index a5bf5e4..002271a 100644
--- a/api/src/main/java/com/cloud/network/NetworkModel.java
+++ b/api/src/main/java/com/cloud/network/NetworkModel.java
@@ -282,7 +282,7 @@ public interface NetworkModel {
 
     boolean isNetworkInlineMode(Network network);
 
-    boolean isIP6AddressAvailableInNetwork(long networkId);
+    boolean areThereIPv6AddressAvailableInNetwork(long networkId);
 
     boolean isIP6AddressAvailableInVlan(long vlanId);
 
diff --git a/api/src/main/java/com/cloud/network/NetworkService.java b/api/src/main/java/com/cloud/network/NetworkService.java
index d76d659..aa33def 100644
--- a/api/src/main/java/com/cloud/network/NetworkService.java
+++ b/api/src/main/java/com/cloud/network/NetworkService.java
@@ -34,6 +34,7 @@ import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network.IpAddresses;
 import com.cloud.network.Network.Service;
 import com.cloud.network.Networks.TrafficType;
 import com.cloud.network.vpc.Vpc;
@@ -155,15 +156,6 @@ public interface NetworkService {
 
     List<? extends Network> getIsolatedNetworksWithSourceNATOwnedByAccountInZone(long zoneId, Account owner);
 
-    /**
-     * @param networkId
-     * @param entityId
-     * @return
-     * @throws ConcurrentOperationException
-     * @throws ResourceUnavailableException
-     * @throws ResourceAllocationException
-     * @throws InsufficientAddressCapacityException
-     */
     IpAddress associateIPToNetwork(long ipId, long networkId) throws InsufficientAddressCapacityException, ResourceAllocationException, ResourceUnavailableException,
         ConcurrentOperationException;
 
@@ -189,12 +181,16 @@ public interface NetworkService {
         String netmask, long networkOwnerId, Long vpcId, Boolean sourceNat, Long networkOfferingId) throws ResourceAllocationException, ConcurrentOperationException,
         InsufficientCapacityException;
 
-    /* Requests an IP address for the guest nic */
-    NicSecondaryIp allocateSecondaryGuestIP(long nicId, String ipaddress) throws InsufficientAddressCapacityException;
+    /**
+     * Requests an IP address for the guest NIC
+     */
+    NicSecondaryIp allocateSecondaryGuestIP(long nicId, IpAddresses requestedIpPair) throws InsufficientAddressCapacityException;
 
     boolean releaseSecondaryIpFromNic(long ipAddressId);
 
-    /* lists the nic informaton */
+    /**
+     * lists the NIC information
+     */
     List<? extends Nic> listNics(ListNicsCmd listNicsCmd);
 
     Map<Network.Capability, String> getNetworkOfferingServiceCapabilities(NetworkOffering offering, Service service);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java
index 009c4fd..ba465ad 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java
@@ -29,7 +29,6 @@ import org.apache.cloudstack.context.CallContext;
 import org.apache.log4j.Logger;
 
 import com.cloud.dc.DataCenter;
-import com.cloud.dc.DataCenter.NetworkType;
 import com.cloud.event.EventTypes;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientAddressCapacityException;
@@ -38,6 +37,7 @@ import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.network.Network;
+import com.cloud.network.Network.IpAddresses;
 import com.cloud.utils.net.NetUtils;
 import com.cloud.vm.Nic;
 import com.cloud.vm.NicSecondaryIp;
@@ -78,20 +78,6 @@ public class AddIpToVmNicCmd extends BaseAsyncCreateCmd {
         return nicId;
     }
 
-    private String getIpaddress() {
-        if (ipAddr != null) {
-            return ipAddr;
-        } else {
-            return null;
-        }
-    }
-
-    private NetworkType getNetworkType() {
-        Network ntwk = _entityMgr.findById(Network.class, getNetworkId());
-        DataCenter dc = _entityMgr.findById(DataCenter.class, ntwk.getDataCenterId());
-        return dc.getNetworkType();
-    }
-
     private boolean isZoneSGEnabled() {
         Network ntwk = _entityMgr.findById(Network.class, getNetworkId());
         DataCenter dc = _entityMgr.findById(DataCenter.class, ntwk.getDataCenterId());
@@ -144,7 +130,6 @@ public class AddIpToVmNicCmd extends BaseAsyncCreateCmd {
         }
     }
 
-
     @Override
     public Long getSyncObjId() {
         return getNetworkId();
@@ -169,17 +154,15 @@ public class AddIpToVmNicCmd extends BaseAsyncCreateCmd {
 
     @Override
     public void create() throws ResourceAllocationException {
-        String ip;
         NicSecondaryIp result;
-        String secondaryIp = null;
-        if ((ip = getIpaddress()) != null) {
-            if (!NetUtils.isValidIp4(ip)) {
-                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Invalid ip address " + ip);
-            }
+
+        IpAddresses requestedIpPair = new IpAddresses(ipAddr, null);
+        if (!NetUtils.isIpv4(ipAddr)) {
+            requestedIpPair = new IpAddresses(null, ipAddr);
         }
 
         try {
-            result = _networkService.allocateSecondaryGuestIP(getNicId(), getIpaddress());
+            result = _networkService.allocateSecondaryGuestIP(getNicId(), requestedIpPair);
             if (result != null) {
                 setEntityId(result.getId());
                 setEntityUuid(result.getUuid());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java
index 19da39a..db84dc9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java
@@ -147,10 +147,15 @@ public class RemoveIpFromVmNicCmd extends BaseAsyncCmd {
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Invalid IP id is passed");
         }
 
+        String secIp = nicSecIp.getIp4Address();
+        if (secIp == null) {
+            secIp = nicSecIp.getIp6Address();
+        }
+
         if (isZoneSGEnabled()) {
             //remove the security group rules for this secondary ip
             boolean success = false;
-            success = _securityGroupService.securityGroupRulesForVmSecIp(nicSecIp.getNicId(), nicSecIp.getIp4Address(), false);
+            success = _securityGroupService.securityGroupRulesForVmSecIp(nicSecIp.getNicId(), secIp, false);
             if (success == false) {
                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to set security group rules for the secondary ip");
             }
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java b/api/src/test/java/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java
index 4139543..8a28305 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/test/AddIpToVmNicTest.java
@@ -61,7 +61,7 @@ public class AddIpToVmNicTest extends TestCase {
         NicSecondaryIp secIp = Mockito.mock(NicSecondaryIp.class);
 
         Mockito.when(
-            networkService.allocateSecondaryGuestIP(Matchers.anyLong(), Matchers.anyString()))
+            networkService.allocateSecondaryGuestIP(Matchers.anyLong(), Matchers.any()))
             .thenReturn(secIp);
 
         ipTonicCmd._networkService = networkService;
@@ -81,7 +81,7 @@ public class AddIpToVmNicTest extends TestCase {
         AddIpToVmNicCmd ipTonicCmd = Mockito.mock(AddIpToVmNicCmd.class);
 
         Mockito.when(
-            networkService.allocateSecondaryGuestIP(Matchers.anyLong(), Matchers.anyString()))
+            networkService.allocateSecondaryGuestIP(Matchers.anyLong(), Matchers.any()))
             .thenReturn(null);
 
         ipTonicCmd._networkService = networkService;
diff --git a/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java b/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java
index 256f026..a551278 100644
--- a/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java
+++ b/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java
@@ -166,18 +166,18 @@ public interface IpAddressManager {
      * @throws ConcurrentOperationException
      * @throws InsufficientAddressCapacityException
      */
-    PublicIp assignDedicateIpAddress(Account owner, Long guestNtwkId, Long vpcId, long dcId, boolean isSourceNat) throws ConcurrentOperationException,
-            InsufficientAddressCapacityException;
+    PublicIp assignDedicateIpAddress(Account owner, Long guestNtwkId, Long vpcId, long dcId, boolean isSourceNat)
+            throws ConcurrentOperationException, InsufficientAddressCapacityException;
 
-    IpAddress allocateIp(Account ipOwner, boolean isSystem, Account caller, long callerId, DataCenter zone, Boolean displayIp) throws ConcurrentOperationException,
-            ResourceAllocationException, InsufficientAddressCapacityException;
+    IpAddress allocateIp(Account ipOwner, boolean isSystem, Account caller, long callerId, DataCenter zone, Boolean displayIp)
+            throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException;
 
-    PublicIp assignPublicIpAddressFromVlans(long dcId, Long podId, Account owner, VlanType type, List<Long> vlanDbIds, Long networkId, String requestedIp,
-            boolean isSystem) throws InsufficientAddressCapacityException;
+    PublicIp assignPublicIpAddressFromVlans(long dcId, Long podId, Account owner, VlanType type, List<Long> vlanDbIds, Long networkId, String requestedIp, boolean isSystem)
+            throws InsufficientAddressCapacityException;
 
     @DB
-    void allocateNicValues(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network, String requestedIpv4,
-            String requestedIpv6) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException;
+    void allocateNicValues(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network, String requestedIpv4, String requestedIpv6)
+            throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException;
 
     int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state);
 
@@ -187,6 +187,8 @@ public interface IpAddressManager {
 
     AcquirePodIpCmdResponse allocatePodIp(String zoneId, String podId) throws ConcurrentOperationException, ResourceAllocationException;
 
+    public boolean isIpEqualsGatewayOrNetworkOfferingsEmpty(Network network, String requestedIp);
+
     void releasePodIp(Long id) throws CloudRuntimeException;
 }
 
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicIpAliasDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicIpAliasDaoImpl.java
index d1453aa..887b3d7 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/NicIpAliasDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicIpAliasDaoImpl.java
@@ -113,6 +113,7 @@ public class NicIpAliasDaoImpl extends GenericDaoBase<NicIpAliasVO, Long> implem
         List<String> ips = new ArrayList<String>(results.size());
         for (NicIpAliasVO result : results) {
             ips.add(result.getIp4Address());
+            ips.add(result.getIp6Address());
         }
         return ips;
     }
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicSecondaryIpDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicSecondaryIpDao.java
index 96b80b8..cbb52e5 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/NicSecondaryIpDao.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicSecondaryIpDao.java
@@ -34,11 +34,7 @@ public interface NicSecondaryIpDao extends GenericDao<NicSecondaryIpVO, Long> {
 
     NicSecondaryIpVO findByIp4AddressAndNetworkId(String ip4Address, long networkId);
 
-    /**
-     * @param networkId
-     * @param instanceId
-     * @return
-     */
+    NicSecondaryIpVO findByIp6AddressAndNetworkId(String ip6Address, long networkId);
 
     List<NicSecondaryIpVO> getSecondaryIpAddressesForVm(long vmId);
 
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java
index 01f53bc..ba3a5c7 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicSecondaryIpDaoImpl.java
@@ -19,10 +19,9 @@ package com.cloud.vm.dao;
 import java.util.ArrayList;
 import java.util.List;
 
-
-import com.cloud.utils.StringUtils;
 import org.springframework.stereotype.Component;
 
+import com.cloud.utils.StringUtils;
 import com.cloud.utils.db.GenericDaoBase;
 import com.cloud.utils.db.GenericSearchBuilder;
 import com.cloud.utils.db.SearchBuilder;
@@ -32,16 +31,18 @@ import com.cloud.utils.db.SearchCriteria.Op;
 
 @Component
 public class NicSecondaryIpDaoImpl extends GenericDaoBase<NicSecondaryIpVO, Long> implements NicSecondaryIpDao {
+
     private final SearchBuilder<NicSecondaryIpVO> AllFieldsSearch;
     private final GenericSearchBuilder<NicSecondaryIpVO, String> IpSearch;
     protected GenericSearchBuilder<NicSecondaryIpVO, Long> CountByNicId;
 
-    protected NicSecondaryIpDaoImpl() {
+    public NicSecondaryIpDaoImpl() {
         super();
         AllFieldsSearch = createSearchBuilder();
         AllFieldsSearch.and("instanceId", AllFieldsSearch.entity().getVmId(), Op.EQ);
         AllFieldsSearch.and("network", AllFieldsSearch.entity().getNetworkId(), Op.EQ);
         AllFieldsSearch.and("address", AllFieldsSearch.entity().getIp4Address(), Op.LIKE);
+        AllFieldsSearch.and("ip6address", AllFieldsSearch.entity().getIp6Address(), Op.LIKE);
         AllFieldsSearch.and("nicId", AllFieldsSearch.entity().getNicId(), Op.EQ);
         AllFieldsSearch.done();
 
@@ -133,6 +134,14 @@ public class NicSecondaryIpDaoImpl extends GenericDaoBase<NicSecondaryIpVO, Long
     }
 
     @Override
+    public NicSecondaryIpVO findByIp6AddressAndNetworkId(String ip6Address, long networkId) {
+        SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
+        sc.setParameters("network", networkId);
+        sc.setParameters("ip6address", ip6Address);
+        return findOneBy(sc);
+    }
+
+    @Override
     public NicSecondaryIpVO findByIp4AddressAndNicId(String ip4Address, long nicId) {
         SearchCriteria<NicSecondaryIpVO> sc = AllFieldsSearch.create();
         sc.setParameters("address", ip4Address);
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index ba3d5c3..1bf1f45 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -471,7 +471,7 @@ public class ApiResponseHelper implements ResponseGenerator {
         cfgResponse.setCategory(cfg.getCategory());
         cfgResponse.setDescription(cfg.getDescription());
         cfgResponse.setName(cfg.getName());
-        if(cfg.isEncrypted()) {
+        if (cfg.isEncrypted()) {
             cfgResponse.setValue(DBEncryptionUtil.encrypt(cfg.getValue()));
         } else {
             cfgResponse.setValue(cfg.getValue());
@@ -3623,7 +3623,7 @@ public class ApiResponseHelper implements ResponseGenerator {
         NicVO nic = _entityMgr.findById(NicVO.class, result.getNicId());
         NetworkVO network = _entityMgr.findById(NetworkVO.class, result.getNetworkId());
         response.setId(result.getUuid());
-        response.setIpAddr(result.getIp4Address());
+        setResponseIpAddress(result, response);
         response.setNicId(nic.getUuid());
         response.setNwId(network.getUuid());
         response.setObjectName("nicsecondaryip");
@@ -3631,6 +3631,17 @@ public class ApiResponseHelper implements ResponseGenerator {
     }
 
     /**
+     * Set the NicSecondaryIpResponse object with the IP address that is not null (IPv4 or IPv6)
+     */
+    public static void setResponseIpAddress(NicSecondaryIp result, NicSecondaryIpResponse response) {
+        if (result.getIp4Address() != null) {
+            response.setIpAddr(result.getIp4Address());
+        } else if (result.getIp6Address() != null) {
+            response.setIpAddr(result.getIp6Address());
+        }
+    }
+
+    /**
      * The resulting Response attempts to be in line with what is returned from
      * @see com.cloud.api.query.dao.UserVmJoinDaoImpl#setUserVmResponse(ResponseView, UserVmResponse, UserVmJoinVO)
      */
@@ -3706,7 +3717,7 @@ public class ApiResponseHelper implements ResponseGenerator {
                 for (NicSecondaryIpVO ip : secondaryIps) {
                     NicSecondaryIpResponse ipRes = new NicSecondaryIpResponse();
                     ipRes.setId(ip.getUuid());
-                    ipRes.setIpAddr(ip.getIp4Address());
+                    setResponseIpAddress(ip, ipRes);
                     ipList.add(ipRes);
                 }
                 response.setSecondaryIps(ipList);
diff --git a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
index 00ec61a..58d5e49 100644
--- a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
@@ -41,6 +41,7 @@ import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
 import com.cloud.api.ApiDBUtils;
+import com.cloud.api.ApiResponseHelper;
 import com.cloud.api.query.vo.UserVmJoinVO;
 import com.cloud.gpu.GPU;
 import com.cloud.service.ServiceOfferingDetailsVO;
@@ -267,15 +268,14 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
                     for (NicSecondaryIpVO ip : secondaryIps) {
                         NicSecondaryIpResponse ipRes = new NicSecondaryIpResponse();
                         ipRes.setId(ip.getUuid());
-                        ipRes.setIpAddr(ip.getIp4Address());
+                        ApiResponseHelper.setResponseIpAddress(ip, ipRes);
                         ipList.add(ipRes);
                     }
                     nicResponse.setSecondaryIps(ipList);
                 }
                 nicResponse.setObjectName("nic");
 
-                List<NicExtraDhcpOptionResponse> nicExtraDhcpOptionResponses = _nicExtraDhcpOptionDao.listByNicId(nic_id)
-                        .stream()
+                List<NicExtraDhcpOptionResponse> nicExtraDhcpOptionResponses = _nicExtraDhcpOptionDao.listByNicId(nic_id).stream()
                         .map(vo -> new NicExtraDhcpOptionResponse(Dhcp.DhcpOptionCode.valueOfInt(vo.getCode()).getName(), vo.getCode(), vo.getValue()))
                         .collect(Collectors.toList());
                 nicResponse.setExtraDhcpOptions(nicExtraDhcpOptionResponses);
@@ -400,7 +400,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
                 for (NicSecondaryIpVO ip : secondaryIps) {
                     NicSecondaryIpResponse ipRes = new NicSecondaryIpResponse();
                     ipRes.setId(ip.getUuid());
-                    ipRes.setIpAddr(ip.getIp4Address());
+                    ApiResponseHelper.setResponseIpAddress(ip, ipRes);
                     ipList.add(ipRes);
                 }
                 nicResponse.setSecondaryIps(ipList);
diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
index 71acc83..ec7adfd 100644
--- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
@@ -179,25 +179,25 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
     private static final Logger s_logger = Logger.getLogger(IpAddressManagerImpl.class);
 
     @Inject
-    NetworkOrchestrationService _networkMgr = null;
+    NetworkOrchestrationService _networkMgr;
     @Inject
-    EntityManager _entityMgr = null;
+    EntityManager _entityMgr;
     @Inject
-    DataCenterDao _dcDao = null;
+    DataCenterDao _dcDao;
     @Inject
-    VlanDao _vlanDao = null;
+    VlanDao _vlanDao;
     @Inject
-    IPAddressDao _ipAddressDao = null;
+    IPAddressDao _ipAddressDao;
     @Inject
-    AccountDao _accountDao = null;
+    AccountDao _accountDao;
     @Inject
-    DomainDao _domainDao = null;
+    DomainDao _domainDao;
     @Inject
-    UserDao _userDao = null;
+    UserDao _userDao;
     @Inject
     ConfigurationDao _configDao;
     @Inject
-    UserVmDao _userVmDao = null;
+    UserVmDao _userVmDao;
     @Inject
     AlertManager _alertMgr;
     @Inject
@@ -209,11 +209,11 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
     @Inject
     DomainVlanMapDao _domainVlanMapDao;
     @Inject
-    NetworkOfferingDao _networkOfferingDao = null;
+    NetworkOfferingDao _networkOfferingDao;
     @Inject
-    NetworkDao _networksDao = null;
+    NetworkDao _networksDao;
     @Inject
-    NicDao _nicDao = null;
+    NicDao _nicDao;
     @Inject
     RulesManager _rulesMgr;
     @Inject
@@ -300,6 +300,8 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
             Boolean.class, "system.vm.public.ip.reservation.mode.strictness", "false",
             "If enabled, the use of System VMs public IP reservation is strict, preferred if not.", false, ConfigKey.Scope.Global);
 
+    private Random rand = new Random(System.currentTimeMillis());
+
     @Override
     public boolean configure(String name, Map<String, Object> params) {
         // populate providers
@@ -1840,11 +1842,9 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
             return requestedIp;
         }
 
-        return NetUtils.long2Ip(array[_rand.nextInt(array.length)]);
+        return NetUtils.long2Ip(array[rand.nextInt(array.length)]);
     }
 
-    Random _rand = new Random(System.currentTimeMillis());
-
     /**
      * Get the list of public IPs that need to be applied for a static NAT enable/disable operation.
      * Manipulating only these ips prevents concurrency issues when disabling static nat at the same time.
@@ -2184,4 +2184,18 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey<?>[] {UseSystemPublicIps, RulesContinueOnError, SystemVmPublicIpReservationModeStrictness};
     }
+
+    /**
+     * Returns true if the given IP address is equals the gateway or there is no network offerrings for the given network
+     */
+    @Override
+    public boolean isIpEqualsGatewayOrNetworkOfferingsEmpty(Network network, String requestedIp) {
+        if (requestedIp.equals(network.getGateway()) || requestedIp.equals(network.getIp6Gateway())) {
+            return true;
+        }
+        if (_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty() && network.getCidr() == null) {
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/server/src/main/java/com/cloud/network/Ipv6AddressManager.java b/server/src/main/java/com/cloud/network/Ipv6AddressManager.java
index 8a7049b..4db3ec1 100644
--- a/server/src/main/java/com/cloud/network/Ipv6AddressManager.java
+++ b/server/src/main/java/com/cloud/network/Ipv6AddressManager.java
@@ -26,4 +26,11 @@ public interface Ipv6AddressManager extends Manager {
     public UserIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) throws InsufficientAddressCapacityException;
 
     public void revokeDirectIpv6Address(long networkId, String ip6Address);
+
+    public String allocateGuestIpv6(Network network, String requestedIpv6) throws InsufficientAddressCapacityException;
+
+    public String allocatePublicIp6ForGuestNic(Network network, Long podId, Account ipOwner, String requestedIp) throws InsufficientAddressCapacityException;
+
+    public String acquireGuestIpv6Address(Network network, String requestedIpv6) throws InsufficientAddressCapacityException;
+
 }
diff --git a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java
index 53fb25c..1cb432e 100644
--- a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java
@@ -23,9 +23,8 @@ import java.util.Map;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import org.apache.log4j.Logger;
-
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.log4j.Logger;
 
 import com.cloud.configuration.Config;
 import com.cloud.dc.DataCenter;
@@ -35,13 +34,21 @@ import com.cloud.dc.VlanVO;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.VlanDao;
 import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.network.IpAddress.State;
+import com.cloud.network.Network.IpAddresses;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.UserIpv6AddressDao;
 import com.cloud.user.Account;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.db.DB;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.dao.NicSecondaryIpDao;
+import com.cloud.vm.dao.NicSecondaryIpVO;
 
 public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressManager {
     public static final Logger s_logger = Logger.getLogger(Ipv6AddressManagerImpl.class.getName());
@@ -61,6 +68,12 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa
     NetworkDao _networkDao;
     @Inject
     ConfigurationDao _configDao;
+    @Inject
+    IpAddressManager ipAddressManager;
+    @Inject
+    NicSecondaryIpDao nicSecondaryIpDao;
+    @Inject
+    IPAddressDao ipAddressDao;
 
     @Override
     public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@@ -84,7 +97,7 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa
         String ip = null;
         Vlan ipVlan = null;
         if (requestedIp6 == null) {
-            if (!_networkModel.isIP6AddressAvailableInNetwork(networkId)) {
+            if (!_networkModel.areThereIPv6AddressAvailableInNetwork(networkId)) {
                 throw new InsufficientAddressCapacityException("There is no more address available in the network " + network.getName(), DataCenter.class,
                     network.getDataCenterId());
             }
@@ -132,7 +145,7 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa
         dc.setMacAddress(nextMac);
         _dcDao.update(dc.getId(), dc);
 
-        String macAddress = NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(mac,NetworkModel.MACIdentifier.value()));
+        String macAddress = NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(mac, NetworkModel.MACIdentifier.value()));
         UserIpv6AddressVO ipVO = new UserIpv6AddressVO(ip, dcId, macAddress, ipVlan.getId());
         ipVO.setPhysicalNetworkId(network.getPhysicalNetworkId());
         ipVO.setSourceNetworkId(networkId);
@@ -150,4 +163,101 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa
             _ipv6Dao.remove(ip.getId());
         }
     }
+
+    /**
+     * Executes method {@link #acquireGuestIpv6Address(Network, String)} and returns the requested IPv6 (String) in case of successfully allocating the guest IPv6 address.
+     */
+    @Override
+    public String allocateGuestIpv6(Network network, String requestedIpv6) throws InsufficientAddressCapacityException {
+        return acquireGuestIpv6Address(network, requestedIpv6);
+    }
+
+    /**
+     * Allocates a guest IPv6 address for the guest NIC. It will throw exceptions in the following cases:
+     * <ul>
+     *    <li>there is no IPv6 address available in the network;</li>
+     *    <li>IPv6 address is equals to the Gateway;</li>
+     *    <li>the network offering is empty;</li>
+     *    <li>the IPv6 address is not in the network;</li>
+     *    <li>the requested IPv6 address is already in use in the network.</li>
+     * </ul>
+     */
+    @Override
+    @DB
+    public String acquireGuestIpv6Address(Network network, String requestedIpv6) throws InsufficientAddressCapacityException {
+        if (!_networkModel.areThereIPv6AddressAvailableInNetwork(network.getId())) {
+            throw new InsufficientAddressCapacityException(
+                    String.format("There is no IPv6 address available in the network [name=%s, network id=%s]", network.getName(), network.getId()), DataCenter.class,
+                    network.getDataCenterId());
+        }
+
+        checkIfCanAllocateIpv6Address(network, requestedIpv6);
+
+        IpAddresses requestedIpPair = new IpAddresses(null, requestedIpv6);
+        _networkModel.checkRequestedIpAddresses(network.getId(), requestedIpPair);
+
+        IPAddressVO ip = ipAddressDao.findByIpAndSourceNetworkId(network.getId(), requestedIpv6);
+        if (ip != null) {
+            State ipState = ip.getState();
+            if (ipState != State.Free) {
+                throw new InsufficientAddressCapacityException(String.format("Requested ip address [%s] is not free [ip state=%]", requestedIpv6, ipState), DataCenter.class,
+                        network.getDataCenterId());
+            }
+        }
+        return requestedIpv6;
+    }
+
+    /**
+     * Allocates a public IPv6 address for the guest NIC. It will throw exceptions in the following cases:
+     * <ul>
+     *    <li>the the requested IPv6 address is already in use in the network;</li>
+     *    <li>IPv6 address is equals to the Gateway;</li>
+     *    <li>the network offering is empty;</li>
+     *    <li>the IPv6 address is not in the network.</li>
+     * </ul>
+     */
+    @Override
+    public String allocatePublicIp6ForGuestNic(Network network, Long podId, Account owner, String requestedIpv6) throws InsufficientAddressCapacityException {
+        checkIfCanAllocateIpv6Address(network, requestedIpv6);
+
+        return requestedIpv6;
+    }
+
+    /**
+     * Performs some checks on the given IPv6 address. It will throw exceptions in the following cases:
+     * <ul>
+     *    <li>the the requested IPv6 address is already in use in the network;</li>
+     *    <li>IPv6 address is equals to the Gateway;</li>
+     *    <li>the network offering is empty;</li>
+     *    <li>the IPv6 address is not in the network.</li>
+     * </ul>
+     */
+    protected void checkIfCanAllocateIpv6Address(Network network, String ipv6) throws InsufficientAddressCapacityException {
+        if (isIp6Taken(network, ipv6)) {
+            throw new InsufficientAddressCapacityException(
+                    String.format("The IPv6 address [%s] is already in use in the network [id=%s, name=%s]", ipv6, network.getId(), network.getName()), Network.class,
+                    network.getId());
+        }
+
+        if (ipAddressManager.isIpEqualsGatewayOrNetworkOfferingsEmpty(network, ipv6)) {
+            throw new InvalidParameterValueException(
+                    String.format("The network [id=%s] offering is empty or the requested IP address [%s] is equals to the Gateway", network.getId(), ipv6));
+        }
+
+        String networkIp6Cidr = network.getIp6Cidr();
+        if (!NetUtils.isIp6InNetwork(ipv6, networkIp6Cidr)) {
+            throw new InvalidParameterValueException(
+                    String.format("The IPv6 address [%s] is not in the network [id=%s, name=%s, ipv6cidr=%s]", ipv6, network.getId(), network.getName(), network.getIp6Cidr()));
+        }
+    }
+
+    /**
+     * Returns false if the requested ipv6 address is taken by some VM, checking on the 'user_ipv6_address' table or 'nic_secondary_ips' table.
+     */
+    protected boolean isIp6Taken(Network network, String requestedIpv6) {
+        UserIpv6AddressVO ip6Vo = _ipv6Dao.findByNetworkIdAndIp(network.getId(), requestedIpv6);
+        NicSecondaryIpVO nicSecondaryIpVO = nicSecondaryIpDao.findByIp6AddressAndNetworkId(requestedIpv6, network.getId());
+        return ip6Vo != null || nicSecondaryIpVO != null;
+    }
+
 }
diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
index bb1a181..c23de72 100644
--- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
@@ -592,7 +592,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
                 return false;
             }
             if (network.getIp6Gateway() != null) {
-                hasFreeIps = isIP6AddressAvailableInNetwork(network.getId());
+                hasFreeIps = areThereIPv6AddressAvailableInNetwork(network.getId());
             }
         } else {
             if (network.getCidr() == null) {
@@ -606,7 +606,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
     }
 
     @Override
-    public boolean isIP6AddressAvailableInNetwork(long networkId) {
+    public boolean areThereIPv6AddressAvailableInNetwork(long networkId) {
         Network network = _networksDao.findById(networkId);
         if (network == null) {
             return false;
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index f1397a1..a8932a8 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -34,11 +34,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
+
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import org.apache.log4j.Logger;
-
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.ApiConstants;
@@ -58,6 +57,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.framework.messagebus.MessageBus;
 import org.apache.cloudstack.framework.messagebus.PublishScope;
 import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
+import org.apache.log4j.Logger;
 
 import com.cloud.api.ApiDBUtils;
 import com.cloud.configuration.Config;
@@ -91,6 +91,7 @@ import com.cloud.host.dao.HostDao;
 import com.cloud.network.IpAddress.State;
 import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.GuestType;
+import com.cloud.network.Network.IpAddresses;
 import com.cloud.network.Network.Provider;
 import com.cloud.network.Network.Service;
 import com.cloud.network.Networks.BroadcastDomainType;
@@ -293,6 +294,8 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     @Inject
     IpAddressManager _ipAddrMgr;
     @Inject
+    Ipv6AddressManager ipv6AddrMgr;
+    @Inject
     EntityManager _entityMgr;
     @Inject
     public SecurityGroupService _securityGroupService;
@@ -642,13 +645,16 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
     }
 
     @Override
-    @ActionEvent(eventType = EventTypes.EVENT_NIC_SECONDARY_IP_CONFIGURE, eventDescription = "Configuring secondary ip " +
-            "rules",  async = true)
+    @ActionEvent(eventType = EventTypes.EVENT_NIC_SECONDARY_IP_CONFIGURE, eventDescription = "Configuring secondary ip " + "rules", async = true)
     public boolean configureNicSecondaryIp(NicSecondaryIp secIp, boolean isZoneSgEnabled) {
         boolean success = false;
+        String secondaryIp = secIp.getIp4Address();
+        if (secIp.getIp4Address() == null) {
+            secondaryIp = secIp.getIp6Address();
+        }
 
         if (isZoneSgEnabled) {
-            success = _securityGroupService.securityGroupRulesForVmSecIp(secIp.getNicId(), secIp.getIp4Address(), true);
+            success = _securityGroupService.securityGroupRulesForVmSecIp(secIp.getNicId(), secondaryIp, true);
             s_logger.info("Associated ip address to NIC : " + secIp.getIp4Address());
         } else {
             success = true;
@@ -656,11 +662,16 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
         return success;
     }
 
+    /**
+     * It allocates a secondary IP alias on the NIC. It can be either an Ipv4 or an Ipv6 or even both, according to the the given IpAddresses object.
+     */
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_NIC_SECONDARY_IP_ASSIGN, eventDescription = "assigning secondary ip to nic", create = true)
-    public NicSecondaryIp allocateSecondaryGuestIP(final long nicId, String requestedIp) throws InsufficientAddressCapacityException {
+    public NicSecondaryIp allocateSecondaryGuestIP(final long nicId, IpAddresses requestedIpPair) throws InsufficientAddressCapacityException {
 
         Account caller = CallContext.current().getCallingAccount();
+        String ipv4Address = requestedIpPair.getIp4Address();
+        String ipv6Address = requestedIpPair.getIp6Address();
 
         //check whether the nic belongs to user vm.
         final NicVO nicVO = _nicDao.findById(nicId);
@@ -690,18 +701,23 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
 
         int maxAllowedIpsPerNic = NumbersUtil.parseInt(_configDao.getValue(Config.MaxNumberOfSecondaryIPsPerNIC.key()), 10);
         Long nicWiseIpCount = _nicSecondaryIpDao.countByNicId(nicId);
-        if(nicWiseIpCount.intValue() >= maxAllowedIpsPerNic) {
-            s_logger.error("Maximum Number of Ips \"vm.network.nic.max.secondary.ipaddresses = \"" + maxAllowedIpsPerNic + " per Nic has been crossed for the nic " +  nicId + ".");
+        if (nicWiseIpCount.intValue() >= maxAllowedIpsPerNic) {
+            s_logger.error("Maximum Number of Ips \"vm.network.nic.max.secondary.ipaddresses = \"" + maxAllowedIpsPerNic + " per Nic has been crossed for the nic " + nicId + ".");
             throw new InsufficientAddressCapacityException("Maximum Number of Ips per Nic has been crossed.", Nic.class, nicId);
         }
 
-
         s_logger.debug("Calling the ip allocation ...");
         String ipaddr = null;
+        String ip6addr = null;
         //Isolated network can exist in Basic zone only, so no need to verify the zone type
         if (network.getGuestType() == Network.GuestType.Isolated) {
             try {
-                ipaddr = _ipAddrMgr.allocateGuestIP(network, requestedIp);
+                if (ipv4Address != null) {
+                    ipaddr = _ipAddrMgr.allocateGuestIP(network, ipv4Address);
+                }
+                if (ipv6Address != null) {
+                    ip6addr = ipv6AddrMgr.allocateGuestIpv6(network, ipv6Address);
+                }
             } catch (InsufficientAddressCapacityException e) {
                 throw new InvalidParameterValueException("Allocating guest ip for nic failed");
             }
@@ -711,16 +727,21 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
             DataCenter dc = _dcDao.findById(network.getDataCenterId());
 
             if (dc.getNetworkType() == NetworkType.Basic) {
-            VMInstanceVO vmi = (VMInstanceVO)vm;
+                VMInstanceVO vmi = (VMInstanceVO)vm;
                 podId = vmi.getPodIdToDeployIn();
-            if (podId == null) {
+                if (podId == null) {
                     throw new InvalidParameterValueException("vm pod id is null in Basic zone; can't decide the range for ip allocation");
-            }
+                }
             }
 
             try {
-                ipaddr = _ipAddrMgr.allocatePublicIpForGuestNic(network, podId, ipOwner, requestedIp);
-                if (ipaddr == null) {
+                if (ipv4Address != null) {
+                    ipaddr = _ipAddrMgr.allocatePublicIpForGuestNic(network, podId, ipOwner, ipv4Address);
+                }
+                if (ipv6Address != null) {
+                    ip6addr = ipv6AddrMgr.allocatePublicIp6ForGuestNic(network, podId, ipOwner, ipv6Address);
+                }
+                if (ipaddr == null && ipv6Address == null) {
                     throw new InvalidParameterValueException("Allocating ip to guest nic " + nicId + " failed");
                 }
             } catch (InsufficientAddressCapacityException e) {
@@ -732,29 +753,30 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
             return null;
         }
 
-        if (ipaddr != null) {
+        if (ipaddr != null || ip6addr != null) {
             // we got the ip addr so up the nics table and secodary ip
-            final String addrFinal = ipaddr;
+            final String ip4AddrFinal = ipaddr;
+            final String ip6AddrFinal = ip6addr;
             long id = Transaction.execute(new TransactionCallback<Long>() {
                 @Override
                 public Long doInTransaction(TransactionStatus status) {
-            boolean nicSecondaryIpSet = nicVO.getSecondaryIp();
-            if (!nicSecondaryIpSet) {
-                nicVO.setSecondaryIp(true);
-                // commit when previously set ??
-                s_logger.debug("Setting nics table ...");
-                _nicDao.update(nicId, nicVO);
-            }
+                    boolean nicSecondaryIpSet = nicVO.getSecondaryIp();
+                    if (!nicSecondaryIpSet) {
+                        nicVO.setSecondaryIp(true);
+                        // commit when previously set ??
+                        s_logger.debug("Setting nics table ...");
+                        _nicDao.update(nicId, nicVO);
+                    }
 
-            s_logger.debug("Setting nic_secondary_ip table ...");
+                    s_logger.debug("Setting nic_secondary_ip table ...");
                     Long vmId = nicVO.getInstanceId();
-                    NicSecondaryIpVO secondaryIpVO = new NicSecondaryIpVO(nicId, addrFinal, vmId, ipOwner.getId(), ipOwner.getDomainId(), networkId);
-            _nicSecondaryIpDao.persist(secondaryIpVO);
+                    NicSecondaryIpVO secondaryIpVO = new NicSecondaryIpVO(nicId, ip4AddrFinal, ip6AddrFinal, vmId, ipOwner.getId(), ipOwner.getDomainId(), networkId);
+                    _nicSecondaryIpDao.persist(secondaryIpVO);
                     return secondaryIpVO.getId();
                 }
             });
 
-           return getNicSecondaryIp(id);
+            return getNicSecondaryIp(id);
         } else {
             return null;
         }
diff --git a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java
index 3edc8d2..5150ad7 100644
--- a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java
+++ b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java
@@ -45,6 +45,7 @@ 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.NetworkService;
 import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.Networks.Mode;
 import com.cloud.network.Networks.TrafficType;
@@ -65,6 +66,7 @@ import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.exception.ExceptionUtil;
+import com.cloud.utils.net.NetUtils;
 import com.cloud.vm.Nic;
 import com.cloud.vm.Nic.ReservationStrategy;
 import com.cloud.vm.NicProfile;
@@ -74,6 +76,7 @@ import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineProfile;
 import com.cloud.vm.dao.NicDao;
 import com.cloud.vm.dao.NicSecondaryIpDao;
+import com.cloud.vm.dao.NicSecondaryIpVO;
 
 
 public class DirectNetworkGuru extends AdapterBase implements NetworkGuru {
@@ -105,6 +108,10 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru {
     NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao;
     @Inject
     PhysicalNetworkDao _physicalNetworkDao;
+    @Inject
+    private NetworkService networkService;
+    @Inject
+    private NicSecondaryIpDao nicSecondaryIpDao;
 
     private static final TrafficType[] TrafficTypes = {TrafficType.Guest};
     protected IsolationMethod[] _isolationMethods;
@@ -338,9 +345,16 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru {
                         List<String> nicSecIps = null;
                         nicSecIps = _nicSecondaryIpDao.getSecondaryIpAddressesForNic(nic.getId());
                         for (String secIp : nicSecIps) {
-                            IPAddressVO pubIp = _ipAddressDao.findByIpAndSourceNetworkId(nic.getNetworkId(), secIp);
-                            _ipAddrMgr.markIpAsUnavailable(pubIp.getId());
-                            _ipAddressDao.unassignIpAddress(pubIp.getId());
+                            if (NetUtils.isValidIp4(secIp)) {
+                                IPAddressVO pubIp = _ipAddressDao.findByIpAndSourceNetworkId(nic.getNetworkId(), secIp);
+                                _ipAddrMgr.markIpAsUnavailable(pubIp.getId());
+                                _ipAddressDao.unassignIpAddress(pubIp.getId());
+                            } else {
+                                NicSecondaryIpVO nicSecIp = nicSecondaryIpDao.findByIp6AddressAndNetworkId(secIp, nic.getNetworkId());
+                                if (nicSecIp != null) {
+                                    networkService.releaseSecondaryIpFromNic(nicSecIp.getId());
+                                }
+                            }
                         }
                     }
                 });
diff --git a/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java b/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java
index eda7ca4..2809005 100644
--- a/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java
+++ b/server/src/test/java/com/cloud/api/ApiResponseHelperTest.java
@@ -19,6 +19,9 @@ package com.cloud.api;
 import com.cloud.domain.DomainVO;
 import com.cloud.usage.UsageVO;
 import com.cloud.user.AccountVO;
+import com.cloud.vm.NicSecondaryIp;
+
+import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
 import org.apache.cloudstack.api.response.UsageRecordResponse;
 import org.apache.cloudstack.usage.UsageService;
 import org.junit.Before;
@@ -37,6 +40,7 @@ import java.util.Date;
 import java.util.TimeZone;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Mockito.when;
 
@@ -109,4 +113,32 @@ public class ApiResponseHelperTest {
         UsageRecordResponse MockResponse = helper.createUsageResponse(usage);
         assertEquals("DomainName",MockResponse.getDomainName());
     }
+
+    @Test
+    public void setResponseIpAddressTestIpv4() {
+        NicSecondaryIp result = Mockito.mock(NicSecondaryIp.class);
+        NicSecondaryIpResponse response = new NicSecondaryIpResponse();
+        setResult(result, "ipv4", "ipv6");
+
+        ApiResponseHelper.setResponseIpAddress(result, response);
+
+        assertTrue(response.getIpAddr().equals("ipv4"));
+    }
+
+    private void setResult(NicSecondaryIp result, String ipv4, String ipv6) {
+        when(result.getIp4Address()).thenReturn(ipv4);
+        when(result.getIp6Address()).thenReturn(ipv6);
+    }
+
+    @Test
+    public void setResponseIpAddressTestIpv6() {
+        NicSecondaryIp result = Mockito.mock(NicSecondaryIp.class);
+        NicSecondaryIpResponse response = new NicSecondaryIpResponse();
+        setResult(result, null, "ipv6");
+
+        ApiResponseHelper.setResponseIpAddress(result, response);
+
+        assertTrue(response.getIpAddr().equals("ipv6"));
+    }
+
 }
diff --git a/server/src/test/java/com/cloud/network/IpAddressManagerTest.java b/server/src/test/java/com/cloud/network/IpAddressManagerTest.java
index 0bf92ee..2bf989c 100644
--- a/server/src/test/java/com/cloud/network/IpAddressManagerTest.java
+++ b/server/src/test/java/com/cloud/network/IpAddressManagerTest.java
@@ -17,27 +17,29 @@
 
 package com.cloud.network;
 
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import com.cloud.network.Network.Service;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.rules.StaticNat;
 import com.cloud.network.rules.StaticNatImpl;
 import com.cloud.utils.net.Ip;
 
-import static org.mockito.Mockito.when;
-
-import java.util.Collections;
-import java.util.List;
-
-import static org.mockito.Mockito.anyLong;
-import static org.mockito.Mockito.mock;
-
 public class IpAddressManagerTest {
 
     @Mock
@@ -46,6 +48,9 @@ public class IpAddressManagerTest {
     @InjectMocks
     IpAddressManagerImpl _ipManager;
 
+    @InjectMocks
+    NetworkModelImpl networkModel = Mockito.spy(new NetworkModelImpl());
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -68,4 +73,68 @@ public class IpAddressManagerTest {
         IPAddressVO returnedVO = ips.get(0);
         Assert.assertEquals(vo, returnedVO);
     }
-}
+
+    @Test
+    public void isIpEqualsGatewayOrNetworkOfferingsEmptyTestRequestedIpEqualsIp6Gateway() {
+        Network network = setTestIsIpEqualsGatewayOrNetworkOfferingsEmpty(0l, "gateway", "ip6Gateway", null, new ArrayList<Service>());
+
+        boolean result = _ipManager.isIpEqualsGatewayOrNetworkOfferingsEmpty(network, "ip6Gateway");
+
+        Mockito.verify(networkModel, Mockito.times(0)).listNetworkOfferingServices(Mockito.anyLong());
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void isIpEqualsGatewayOrNetworkOfferingsEmptyTestRequestedIpEqualsGateway() {
+        Network network = setTestIsIpEqualsGatewayOrNetworkOfferingsEmpty(0l, "gateway", "ip6Gateway", null, new ArrayList<Service>());
+
+        boolean result = _ipManager.isIpEqualsGatewayOrNetworkOfferingsEmpty(network, "gateway");
+
+        Mockito.verify(networkModel, Mockito.times(0)).listNetworkOfferingServices(Mockito.anyLong());
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void isIpEqualsGatewayOrNetworkOfferingsEmptyTestExpectFalseServicesNotEmpty() {
+        List<Service> services = new ArrayList<Service>();
+        Service serviceGateway = new Service("Gateway");
+        services.add(serviceGateway);
+        Network network = setTestIsIpEqualsGatewayOrNetworkOfferingsEmpty(0l, "gateway", "ip6Gateway", null, services);
+
+        boolean result = _ipManager.isIpEqualsGatewayOrNetworkOfferingsEmpty(network, "requestedIp");
+
+        Mockito.verify(networkModel).listNetworkOfferingServices(Mockito.anyLong());
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void isIpEqualsGatewayOrNetworkOfferingsEmptyTestExpectFalseServicesCidrNotNull() {
+        Network network = setTestIsIpEqualsGatewayOrNetworkOfferingsEmpty(0l, "gateway", "ip6Gateway", "cidr", new ArrayList<Service>());
+
+        boolean result = _ipManager.isIpEqualsGatewayOrNetworkOfferingsEmpty(network, "requestedIp");
+
+        Mockito.verify(networkModel).listNetworkOfferingServices(Mockito.anyLong());
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void isIpEqualsGatewayOrNetworkOfferingsEmptyTestNetworkOfferingsEmptyAndCidrNull() {
+        Network network = setTestIsIpEqualsGatewayOrNetworkOfferingsEmpty(0l, "gateway", "ip6Gateway", null, new ArrayList<Service>());
+
+        boolean result = _ipManager.isIpEqualsGatewayOrNetworkOfferingsEmpty(network, "requestedIp");
+
+        Mockito.verify(networkModel).listNetworkOfferingServices(Mockito.anyLong());
+        Assert.assertTrue(result);
+    }
+
+    private Network setTestIsIpEqualsGatewayOrNetworkOfferingsEmpty(long networkOfferingId, String gateway, String ip6Gateway, String cidr, List<Service> services) {
+        Network network = mock(Network.class);
+        Mockito.when(network.getNetworkOfferingId()).thenReturn(networkOfferingId);
+        Mockito.when(network.getGateway()).thenReturn(gateway);
+        Mockito.when(network.getIp6Gateway()).thenReturn(ip6Gateway);
+        Mockito.when(network.getCidr()).thenReturn(cidr);
+        Mockito.doReturn(services).when(networkModel).listNetworkOfferingServices(Mockito.anyLong());
+        return network;
+    }
+
+}
\ No newline at end of file
diff --git a/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java b/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java
new file mode 100644
index 0000000..26ca8f4
--- /dev/null
+++ b/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java
@@ -0,0 +1,229 @@
+// 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 static org.mockito.Mockito.mock;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.network.IpAddress.State;
+import com.cloud.network.Network.IpAddresses;
+import com.cloud.network.dao.IPAddressDaoImpl;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.network.dao.UserIpv6AddressDaoImpl;
+import com.cloud.user.Account;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.dao.NicSecondaryIpDaoImpl;
+import com.cloud.vm.dao.NicSecondaryIpVO;
+
+public class Ipv6AddressManagerTest {
+
+    @InjectMocks
+    Ipv6AddressManagerImpl ip6Manager = Mockito.spy(new Ipv6AddressManagerImpl());
+
+    @InjectMocks
+    NicSecondaryIpDaoImpl nicSecondaryIpDao = Mockito.spy(new NicSecondaryIpDaoImpl());
+
+    @InjectMocks
+    UserIpv6AddressDaoImpl ipv6Dao = Mockito.spy(new UserIpv6AddressDaoImpl());
+
+    @InjectMocks
+    IpAddressManagerImpl ipAddressManager = Mockito.spy(new IpAddressManagerImpl());
+
+    @InjectMocks
+    NetworkModelImpl networkModel = Mockito.mock(NetworkModelImpl.class);// = Mockito.spy(new NetworkModelImpl());
+
+    @InjectMocks
+    IPAddressDaoImpl ipAddressDao = Mockito.spy(new IPAddressDaoImpl());
+
+    private Network network = mockNetwork();
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void isIp6TakenTestNoNull() {
+        setIsIp6TakenTest(new UserIpv6AddressVO(), new NicSecondaryIpVO(0l, "ipaddr", 0l, 0l, 0l, 0l));
+        boolean result = ip6Manager.isIp6Taken(network, "requestedIpv6");
+        assertAndVerifyIsIp6Taken(true, result);
+    }
+
+    @Test
+    public void isIp6TakenTestSecIpNull() {
+        setIsIp6TakenTest(new UserIpv6AddressVO(), null);
+        boolean result = ip6Manager.isIp6Taken(network, "requestedIpv6");
+        assertAndVerifyIsIp6Taken(true, result);
+    }
+
+    @Test
+    public void isIp6TakenTestUserIpv6AddressNull() {
+        setIsIp6TakenTest(null, new NicSecondaryIpVO(0l, "ipaddr", 0l, 0l, 0l, 0l));
+        boolean result = ip6Manager.isIp6Taken(network, "requestedIpv6");
+        assertAndVerifyIsIp6Taken(true, result);
+    }
+
+    @Test
+    public void isIp6TakenTestAllNull() {
+        setIsIp6TakenTest(null, null);
+        boolean result = ip6Manager.isIp6Taken(network, "requestedIpv6");
+        assertAndVerifyIsIp6Taken(false, result);
+    }
+
+    private void assertAndVerifyIsIp6Taken(boolean expected, boolean result) {
+        Assert.assertEquals(expected, result);
+        Mockito.verify(ipv6Dao).findByNetworkIdAndIp(Mockito.anyLong(), Mockito.anyString());
+        Mockito.verify(nicSecondaryIpDao).findByIp6AddressAndNetworkId(Mockito.anyString(), Mockito.anyLong());
+    }
+
+    private void setIsIp6TakenTest(UserIpv6AddressVO userIpv6, NicSecondaryIpVO nicSecondaryIp) {
+        Mockito.doReturn(userIpv6).when(ipv6Dao).findByNetworkIdAndIp(Mockito.anyLong(), Mockito.anyString());
+        Mockito.doReturn(nicSecondaryIp).when(nicSecondaryIpDao).findByIp6AddressAndNetworkId(Mockito.anyString(), Mockito.anyLong());
+    }
+
+    private Network mockNetwork() {
+        Network network = mock(Network.class);
+        Mockito.when(network.getId()).thenReturn(0l);
+        Mockito.when(network.getIp6Cidr()).thenReturn("2001:db8::/32");
+        return network;
+    }
+
+    @Test
+    public void allocatePublicIp6ForGuestNicTestNoException() throws InsufficientAddressCapacityException {
+        Account owner = Mockito.mock(Account.class);
+        String requestedIpv6 = setCheckIfCanAllocateIpv6AddresscTest("2001:db8::10", false, false);
+
+        String returnedIp = ip6Manager.allocatePublicIp6ForGuestNic(network, 0l, owner, requestedIpv6);
+
+        Mockito.verify(ip6Manager).checkIfCanAllocateIpv6Address(network, requestedIpv6);
+        Assert.assertEquals(requestedIpv6, returnedIp);
+    }
+
+    @Test(expected = InsufficientAddressCapacityException.class)
+    public void checkIfCanAllocateIpv6AddressTestIp6IsTaken() throws InsufficientAddressCapacityException {
+        String requestedIpv6 = setCheckIfCanAllocateIpv6AddresscTest("2001:db8::10", true, false);
+
+        ip6Manager.checkIfCanAllocateIpv6Address(network, requestedIpv6);
+
+        verifyCheckIfCanAllocateIpv6AddressTest(network, requestedIpv6, 1, 0);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void checkIfCanAllocateIpv6AddressTestIpIsIpEqualsGatewayOrNetworkOfferingsEmpty() throws InsufficientAddressCapacityException {
+        String requestedIpv6 = setCheckIfCanAllocateIpv6AddresscTest("2001:db8::10", false, true);
+
+        ip6Manager.checkIfCanAllocateIpv6Address(network, requestedIpv6);
+
+        verifyCheckIfCanAllocateIpv6AddressTest(network, requestedIpv6, 1, 1);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void checkIfCanAllocateIpv6AddressTestIpINotInTheNetwork() throws InsufficientAddressCapacityException {
+        String requestedIpv6 = "2002:db8::10";
+        setCheckIfCanAllocateIpv6AddresscTest(requestedIpv6, false, false);
+
+        ip6Manager.checkIfCanAllocateIpv6Address(network, requestedIpv6);
+
+        verifyCheckIfCanAllocateIpv6AddressTest(network, requestedIpv6, 1, 1);
+    }
+
+    private void verifyCheckIfCanAllocateIpv6AddressTest(Network network, String requestedIpv6, int isIp6TakenTimes, int isIpEqualsGatewayTimes) {
+        Mockito.verify(ip6Manager, Mockito.times(isIp6TakenTimes)).isIp6Taken(network, requestedIpv6);
+        Mockito.verify(ipAddressManager, Mockito.times(isIpEqualsGatewayTimes)).isIpEqualsGatewayOrNetworkOfferingsEmpty(network, requestedIpv6);
+    }
+
+    private String setCheckIfCanAllocateIpv6AddresscTest(String requestedIpv6, boolean isIp6Taken, boolean isIpEqualsGatewayOrNetworkOfferingsEmpty) {
+        Mockito.doReturn(isIp6Taken).when(ip6Manager).isIp6Taken(Mockito.eq(network), Mockito.anyString());
+        Mockito.doReturn(isIpEqualsGatewayOrNetworkOfferingsEmpty).when(ipAddressManager).isIpEqualsGatewayOrNetworkOfferingsEmpty(network, requestedIpv6);
+        NetUtils.isIp6InNetwork(requestedIpv6, network.getIp6Cidr());
+        return requestedIpv6;
+    }
+
+    @Test
+    public void acquireGuestIpv6AddressTest() throws InsufficientAddressCapacityException {
+        setAcquireGuestIpv6AddressTest(true, State.Free);
+        String requestedIpv6 = setCheckIfCanAllocateIpv6AddresscTest("2001:db8::10", false, false);
+
+        ip6Manager.acquireGuestIpv6Address(network, requestedIpv6);
+
+        verifyAcquireGuestIpv6AddressTest();
+    }
+
+    private void verifyAcquireGuestIpv6AddressTest() {
+        Mockito.verify(networkModel).areThereIPv6AddressAvailableInNetwork(Mockito.anyLong());
+        Mockito.verify(networkModel).checkRequestedIpAddresses(Mockito.anyLong(), Mockito.any(IpAddresses.class));
+        Mockito.verify(ipAddressDao).findByIpAndSourceNetworkId(Mockito.anyLong(), Mockito.anyString());
+    }
+
+    @Test(expected = InsufficientAddressCapacityException.class)
+    public void acquireGuestIpv6AddressTestUnavailableIp() throws InsufficientAddressCapacityException {
+        setAcquireGuestIpv6AddressTest(false, State.Free);
+        String requestedIpv6 = setCheckIfCanAllocateIpv6AddresscTest("2001:db8::10", false, false);
+
+        ip6Manager.acquireGuestIpv6Address(network, requestedIpv6);
+
+        verifyAcquireGuestIpv6AddressTest();
+    }
+
+    @Test(expected = InsufficientAddressCapacityException.class)
+    public void acquireGuestIpv6AddressTestStateAllocating() throws InsufficientAddressCapacityException {
+        setAcquireGuestIpv6AddressTest(false, State.Allocating);
+        String requestedIpv6 = setCheckIfCanAllocateIpv6AddresscTest("2001:db8::10", false, false);
+
+        ip6Manager.acquireGuestIpv6Address(network, requestedIpv6);
+
+        verifyAcquireGuestIpv6AddressTest();
+    }
+
+    @Test(expected = InsufficientAddressCapacityException.class)
+    public void acquireGuestIpv6AddressTestStateAllocated() throws InsufficientAddressCapacityException {
+        setAcquireGuestIpv6AddressTest(false, State.Allocated);
+        String requestedIpv6 = setCheckIfCanAllocateIpv6AddresscTest("2001:db8::10", false, false);
+
+        ip6Manager.acquireGuestIpv6Address(network, requestedIpv6);
+
+        verifyAcquireGuestIpv6AddressTest();
+    }
+
+    @Test(expected = InsufficientAddressCapacityException.class)
+    public void acquireGuestIpv6AddressTestStateReleasing() throws InsufficientAddressCapacityException {
+        setAcquireGuestIpv6AddressTest(false, State.Releasing);
+        String requestedIpv6 = setCheckIfCanAllocateIpv6AddresscTest("2001:db8::10", false, false);
+
+        ip6Manager.acquireGuestIpv6Address(network, requestedIpv6);
+
+        verifyAcquireGuestIpv6AddressTest();
+    }
+
+    private void setAcquireGuestIpv6AddressTest(boolean isIPAvailable, State state) {
+        mockNetwork();
+        IPAddressVO ipVo = Mockito.mock(IPAddressVO.class);
+        Mockito.doReturn(isIPAvailable).when(networkModel).areThereIPv6AddressAvailableInNetwork(Mockito.anyLong());
+        Mockito.doReturn(ipVo).when(ipAddressDao).findByIpAndSourceNetworkId(Mockito.anyLong(), Mockito.anyString());
+        Mockito.when(ipVo.getState()).thenReturn(state);
+    }
+
+}
diff --git a/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java b/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
index d142554..a35cec5 100644
--- a/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
+++ b/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
@@ -813,7 +813,7 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel {
     }
 
     @Override
-    public boolean isIP6AddressAvailableInNetwork(long networkId) {
+    public boolean areThereIPv6AddressAvailableInNetwork(long networkId) {
         // TODO Auto-generated method stub
         return false;
     }
diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
index 8cbf30c..57ecbd1 100644
--- a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -51,6 +51,7 @@ import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.network.GuestVlan;
 import com.cloud.network.IpAddress;
 import com.cloud.network.Network;
+import com.cloud.network.Network.IpAddresses;
 import com.cloud.network.Network.Provider;
 import com.cloud.network.Network.Service;
 import com.cloud.network.NetworkProfile;
@@ -827,7 +828,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
     }
 
     @Override
-    public NicSecondaryIp allocateSecondaryGuestIP(long nicId, String ipaddress) {
+    public NicSecondaryIp allocateSecondaryGuestIP(long nicId, IpAddresses requestedIpPair) {
         // TODO Auto-generated method stub
         return null;
     }
diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java b/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java
index 33192a7..56670d2 100644
--- a/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java
+++ b/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java
@@ -829,7 +829,7 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel {
     }
 
     @Override
-    public boolean isIP6AddressAvailableInNetwork(long networkId) {
+    public boolean areThereIPv6AddressAvailableInNetwork(long networkId) {
         // TODO Auto-generated method stub
         return false;
     }
diff --git a/ui/lib/jquery.validate.additional-methods.js b/ui/lib/jquery.validate.additional-methods.js
index 811b4f7..2de65d3 100644
--- a/ui/lib/jquery.validate.additional-methods.js
+++ b/ui/lib/jquery.validate.additional-methods.js
@@ -503,6 +503,16 @@ $.validator.addMethod("ipv6", function(value, element) {
 	return this.optional(element) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|( [...]
 }, "Please enter a valid IP v6 address.");
 
+$.validator.addMethod("ipv46address", function(value, element) {
+    if (this.optional(element) && value.length == 0)
+        return true;
+
+    if ($.validator.methods.ipv4.call(this, value, element) || $.validator.methods.ipv6.call(this, value, element))
+        return true;
+
+    return false;
+}, "Please enter a valid IPv4/IPv6 address.");
+
 $.validator.addMethod("lettersonly", function(value, element) {
 	return this.optional(element) || /^[a-z]+$/i.test(value);
 }, "Letters only please");
diff --git a/ui/scripts/network.js b/ui/scripts/network.js
index 22ddb10..1cbacb6 100644
--- a/ui/scripts/network.js
+++ b/ui/scripts/network.js
@@ -1782,7 +1782,7 @@
                                         label: 'label.ip.address',
                                         validation: {
                                             required: false,
-                                            ipv4: true
+                                            ipv46address: true
                                         }
                                     }
                                 }
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 1bd08a3..9a88249 100644
--- a/utils/src/main/java/com/cloud/utils/net/NetUtils.java
+++ b/utils/src/main/java/com/cloud/utils/net/NetUtils.java
@@ -23,9 +23,9 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.math.BigInteger;
-import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
+import java.net.InetAddress;
 import java.net.InterfaceAddress;
 import java.net.NetworkInterface;
 import java.net.SocketException;
@@ -1547,4 +1547,20 @@ public class NetUtils {
         return EUI64Address(IPv6Network.LINK_LOCAL_NETWORK, macAddress);
     }
 
+    /**
+     * Returns true if the given IP address is IPv4 or false if it is an IPv6. If it is an invalid IP address it throws an exception.
+     */
+    public static boolean isIpv4(String ipAddr) {
+        boolean isIpv4 = true;
+        if (ipAddr != null) {
+            if (!NetUtils.isValidIp4(ipAddr)) {
+                isIpv4 = false;
+            }
+            if (!NetUtils.isValidIp6(ipAddr) && !isIpv4) {
+                throw new IllegalArgumentException("Invalid ip address " + ipAddr);
+            }
+        }
+        return isIpv4;
+    }
+
 }
diff --git a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
index bec2209..4abb87a 100644
--- a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
+++ b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
@@ -678,4 +678,20 @@ public class NetUtilsTest {
         assertFalse(NetUtils.isValidPort(-1));
         assertFalse(NetUtils.isValidPort(65536));
     }
+
+    @Test
+    public void testIsIpv4() {
+        assertTrue(NetUtils.isIpv4("192.168.1.1"));
+        assertFalse(NetUtils.isIpv4("2a01:4f8:130:2192::2"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testIsIpv4ExpectException() {
+        NetUtils.isIpv4("test");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testIsIpv4ExpectException2() {
+        NetUtils.isIpv4("2001:db8:300::/64");
+    }
 }