You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by sh...@apache.org on 2022/09/10 07:35:49 UTC

[cloudstack] branch main updated: api,server: custom dns for guest network (#6425)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 78b68fd7e6 api,server: custom dns for guest network (#6425)
78b68fd7e6 is described below

commit 78b68fd7e6ec9eefd6c5275fab05ec7697f8dd2f
Author: Abhishek Kumar <ab...@gmail.com>
AuthorDate: Sat Sep 10 13:05:40 2022 +0530

    api,server: custom dns for guest network (#6425)
    
    Adds option to provide custom DNS servers for isolated network, shared network and VPC tier.
    New API parameters added in createNetwork API along with the corresponding response parameters.
    
    Doc PR: apache/cloudstack-documentation#276
---
 .../java/com/cloud/agent/api/to/NetworkTO.java     |  10 +
 api/src/main/java/com/cloud/network/Network.java   |   8 +
 .../main/java/com/cloud/network/NetworkModel.java  |  16 +-
 .../java/com/cloud/network/NetworkProfile.java     |  22 +
 api/src/main/java/com/cloud/network/vpc/Vpc.java   |  12 +-
 .../java/com/cloud/network/vpc/VpcService.java     |   5 +-
 .../api/command/user/network/CreateNetworkCmd.java |  28 +
 .../api/command/user/network/UpdateNetworkCmd.java |  29 +
 .../api/command/user/vpc/CreateVPCCmd.java         |  30 +-
 .../cloudstack/api/response/NetworkResponse.java   |  20 +-
 .../cloudstack/api/response/VpcResponse.java       |  32 +
 .../service/NetworkOrchestrationService.java       |   3 +-
 .../java/com/cloud/network/vpc/VpcManager.java     |   3 +-
 .../engine/orchestration/NetworkOrchestrator.java  |  64 +-
 .../orchestration/NetworkOrchestratorTest.java     | 156 ++++-
 .../src/main/java/com/cloud/dc/DataCenterVO.java   |  10 +-
 .../main/java/com/cloud/network/dao/NetworkVO.java |  45 +-
 .../src/main/java/com/cloud/network/vpc/VpcVO.java |  41 +-
 .../network/vpc/dao/VpcOfferingServiceMapDao.java  |   2 +-
 .../vpc/dao/VpcOfferingServiceMapDaoImpl.java      |   4 +-
 .../resources/META-INF/db/schema-41710to41800.sql  |  12 +-
 .../networkservice/BaremetaNetworkGuru.java        |  14 +-
 .../cluster/KubernetesClusterManagerImpl.java      | 106 +--
 .../main/java/com/cloud/api/ApiResponseHelper.java |   6 +
 .../com/cloud/hypervisor/HypervisorGuruBase.java   |   2 +
 .../com/cloud/network/IpAddressManagerImpl.java    |  13 +-
 .../com/cloud/network/Ipv6AddressManagerImpl.java  |   6 +-
 .../java/com/cloud/network/Ipv6ServiceImpl.java    |   5 +-
 .../cloud/network/NetworkMigrationManagerImpl.java |   5 +-
 .../java/com/cloud/network/NetworkModelImpl.java   |  46 ++
 .../java/com/cloud/network/NetworkServiceImpl.java |  90 ++-
 .../com/cloud/network/guru/DirectNetworkGuru.java  |  40 +-
 .../network/guru/DirectPodBasedNetworkGuru.java    |  11 +-
 .../network/guru/ExternalGuestNetworkGuru.java     |   6 +-
 .../com/cloud/network/guru/GuestNetworkGuru.java   |  36 +-
 .../com/cloud/network/guru/PrivateNetworkGuru.java |  26 +-
 .../com/cloud/network/guru/PublicNetworkGuru.java  |  26 +-
 .../cloud/network/router/CommandSetupHelper.java   |  22 +-
 .../router/VirtualNetworkApplianceManagerImpl.java |   4 +-
 .../VpcVirtualNetworkApplianceManagerImpl.java     |  10 +
 .../java/com/cloud/network/vpc/VpcManagerImpl.java |  47 +-
 .../main/java/com/cloud/vm/UserVmManagerImpl.java  |   4 +-
 .../cloud/network/CreatePrivateNetworkTest.java    |   2 +-
 .../com/cloud/network/Ipv6AddressManagerTest.java  |   8 +-
 .../com/cloud/network/Ipv6ServiceImplTest.java     |   5 +-
 .../com/cloud/network/MockNetworkModelImpl.java    |  17 +
 .../com/cloud/network/NetworkModelImplTest.java    | 144 ++++
 .../com/cloud/network/NetworkServiceImplTest.java  | 300 ++++++++-
 .../cloud/network/guru/DirectNetworkGuruTest.java  |  84 ++-
 .../network/guru/ExternalGuestNetworkGuruTest.java | 123 ++++
 .../com/cloud/network/vpc/VpcManagerImplTest.java  | 101 ++-
 .../java/com/cloud/vpc/MockNetworkManagerImpl.java |   4 +-
 .../java/com/cloud/vpc/MockNetworkModelImpl.java   |  17 +
 .../test/java/com/cloud/vpc/VpcApiUnitTest.java    |   2 +-
 .../java/com/cloud/vpc/dao/MockVpcDaoImpl.java     |   4 +-
 .../vpc/dao/MockVpcOfferingServiceMapDaoImpl.java  |   2 +-
 systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh   |  12 +
 .../component/test_network_vpc_custom_dns.py       | 732 +++++++++++++++++++++
 tools/marvin/marvin/lib/base.py                    |   8 +
 ui/src/config/section/network.js                   |   4 +-
 ui/src/views/network/CreateIsolatedNetworkForm.vue | 100 ++-
 ui/src/views/network/CreateSharedNetworkForm.vue   | 296 +++++----
 ui/src/views/network/CreateVpc.vue                 |  73 +-
 ui/src/views/network/UpdateNetwork.vue             |  64 +-
 64 files changed, 2828 insertions(+), 351 deletions(-)

diff --git a/api/src/main/java/com/cloud/agent/api/to/NetworkTO.java b/api/src/main/java/com/cloud/agent/api/to/NetworkTO.java
index b106418f06..bd08ce8110 100644
--- a/api/src/main/java/com/cloud/agent/api/to/NetworkTO.java
+++ b/api/src/main/java/com/cloud/agent/api/to/NetworkTO.java
@@ -41,6 +41,8 @@ public class NetworkTO {
     protected String ip6address;
     protected String ip6gateway;
     protected String ip6cidr;
+    protected String ip6Dns1;
+    protected String ip6Dns2;
 
     public NetworkTO() {
     }
@@ -221,4 +223,12 @@ public class NetworkTO {
     public boolean isSecurityGroupEnabled() {
         return this.isSecurityGroupEnabled;
     }
+
+    public void setIp6Dns1(String ip6Dns1) {
+        this.ip6Dns1 = ip6Dns1;
+    }
+
+    public void setIp6Dns2(String ip6Dns2) {
+        this.ip6Dns2 = ip6Dns2;
+    }
 }
diff --git a/api/src/main/java/com/cloud/network/Network.java b/api/src/main/java/com/cloud/network/Network.java
index 49408b9110..0fee5c04d2 100644
--- a/api/src/main/java/com/cloud/network/Network.java
+++ b/api/src/main/java/com/cloud/network/Network.java
@@ -483,5 +483,13 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
 
     String getRouterIpv6();
 
+    String getDns1();
+
+    String getDns2();
+
+    String getIp6Dns1();
+
+    String getIp6Dns2();
+
     Date getCreated();
 }
diff --git a/api/src/main/java/com/cloud/network/NetworkModel.java b/api/src/main/java/com/cloud/network/NetworkModel.java
index 971bb308b1..c27290f902 100644
--- a/api/src/main/java/com/cloud/network/NetworkModel.java
+++ b/api/src/main/java/com/cloud/network/NetworkModel.java
@@ -17,13 +17,14 @@
 
 package com.cloud.network;
 
-import com.google.common.collect.ImmutableMap;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.cloudstack.framework.config.ConfigKey;
+
+import com.cloud.dc.DataCenter;
 import com.cloud.dc.Vlan;
 import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
@@ -39,10 +40,11 @@ import com.cloud.network.router.VirtualRouter;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offering.NetworkOffering.Detail;
 import com.cloud.user.Account;
+import com.cloud.utils.Pair;
 import com.cloud.vm.Nic;
 import com.cloud.vm.NicProfile;
 import com.cloud.vm.VirtualMachine;
-import org.apache.cloudstack.framework.config.ConfigKey;
+import com.google.common.collect.ImmutableMap;
 
 /**
  * The NetworkModel presents a read-only view into the Network data such as L2 networks,
@@ -323,4 +325,12 @@ public interface NetworkModel {
 
     String getValidNetworkCidr(Network guestNetwork);
 
+    Pair<String, String> getNetworkIp4Dns(final Network network, final DataCenter zone);
+
+    Pair<String, String> getNetworkIp6Dns(final Network network, final DataCenter zone);
+
+    void verifyIp4DnsPair(final String ip4Dns1, final String ip4Dns2);
+
+    void verifyIp6DnsPair(final String ip6Dns1, final String ip6Dns2);
+
 }
diff --git a/api/src/main/java/com/cloud/network/NetworkProfile.java b/api/src/main/java/com/cloud/network/NetworkProfile.java
index f3c178767e..5289bda629 100644
--- a/api/src/main/java/com/cloud/network/NetworkProfile.java
+++ b/api/src/main/java/com/cloud/network/NetworkProfile.java
@@ -31,6 +31,8 @@ public class NetworkProfile implements Network {
     private final long domainId;
     private String dns1;
     private String dns2;
+    private String ip6Dns1;
+    private String ip6Dns2;
     private URI broadcastUri;
     private final State state;
     private boolean isRedundant;
@@ -98,10 +100,12 @@ public class NetworkProfile implements Network {
         externalId = network.getExternalId();
     }
 
+    @Override
     public String getDns1() {
         return dns1;
     }
 
+    @Override
     public String getDns2() {
         return dns2;
     }
@@ -114,6 +118,24 @@ public class NetworkProfile implements Network {
         this.dns2 = dns2;
     }
 
+    @Override
+    public String getIp6Dns1() {
+        return ip6Dns1;
+    }
+
+    @Override
+    public String getIp6Dns2() {
+        return ip6Dns2;
+    }
+
+    public void setIp6Dns1(String ip6Dns1) {
+        this.ip6Dns1 = ip6Dns1;
+    }
+
+    public void setIp6Dns2(String ip6Dns2) {
+        this.ip6Dns2 = ip6Dns2;
+    }
+
     @Override
     public String getGuruName() {
         return guruName;
diff --git a/api/src/main/java/com/cloud/network/vpc/Vpc.java b/api/src/main/java/com/cloud/network/vpc/Vpc.java
index 432c8839ad..664b6eb7e9 100644
--- a/api/src/main/java/com/cloud/network/vpc/Vpc.java
+++ b/api/src/main/java/com/cloud/network/vpc/Vpc.java
@@ -16,12 +16,12 @@
 // under the License.
 package com.cloud.network.vpc;
 
+import java.util.Date;
+
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.api.Identity;
 import org.apache.cloudstack.api.InternalIdentity;
 
-import java.util.Date;
-
 public interface Vpc extends ControlledEntity, Identity, InternalIdentity {
 
     public enum State {
@@ -95,4 +95,12 @@ public interface Vpc extends ControlledEntity, Identity, InternalIdentity {
     void setRollingRestart(boolean rollingRestart);
 
     Date getCreated();
+
+    String getIp4Dns1();
+
+    String getIp4Dns2();
+
+    String getIp6Dns1();
+
+    String getIp6Dns2();
 }
diff --git a/api/src/main/java/com/cloud/network/vpc/VpcService.java b/api/src/main/java/com/cloud/network/vpc/VpcService.java
index 088239708f..3829e5dbd7 100644
--- a/api/src/main/java/com/cloud/network/vpc/VpcService.java
+++ b/api/src/main/java/com/cloud/network/vpc/VpcService.java
@@ -20,6 +20,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.cloudstack.api.command.user.vpc.CreatePrivateGatewayCmd;
+import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd;
 import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd;
 import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd;
 import org.apache.cloudstack.api.command.user.vpc.RestartVPCCmd;
@@ -36,6 +37,7 @@ import com.cloud.utils.Pair;
 
 public interface VpcService {
 
+    public Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException;
     /**
      * Persists VPC record in the database
      *
@@ -50,7 +52,8 @@ public interface VpcService {
      * @return
      * @throws ResourceAllocationException TODO
      */
-    public Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain, Boolean displayVpc)
+    public Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain,
+                         String dns1, String dns2, String ip6Dns1, String ip6Dns2, Boolean displayVpc)
             throws ResourceAllocationException;
 
     /**
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
index 903793b6e9..9973af2db9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
@@ -157,6 +157,18 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd {
             description = "The network this network is associated to. only available if create a Shared network")
     private Long associatedNetworkId;
 
+    @Parameter(name = ApiConstants.DNS1, type = CommandType.STRING, description = "the first IPv4 DNS for the network", since = "4.18.0")
+    private String ip4Dns1;
+
+    @Parameter(name = ApiConstants.DNS2, type = CommandType.STRING, description = "the second IPv4 DNS for the network", since = "4.18.0")
+    private String ip4Dns2;
+
+    @Parameter(name = ApiConstants.IP6_DNS1, type = CommandType.STRING, description = "the first IPv6 DNS for the network", since = "4.18.0")
+    private String ip6Dns1;
+
+    @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the network", since = "4.18.0")
+    private String ip6Dns2;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -326,6 +338,22 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd {
         return aclId;
     }
 
+    public String getIp4Dns1() {
+        return ip4Dns1;
+    }
+
+    public String getIp4Dns2() {
+        return ip4Dns2;
+    }
+
+    public String getIp6Dns1() {
+        return ip6Dns1;
+    }
+
+    public String getIp6Dns2() {
+        return ip6Dns2;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
index bb27579992..49a23a145f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
@@ -84,6 +84,18 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd implements UserCmd {
     @Parameter(name= ApiConstants.FORCED, type = CommandType.BOOLEAN, description = "Setting this to true will cause a forced network update,", authorized = {RoleType.Admin})
     private Boolean forced;
 
+    @Parameter(name = ApiConstants.DNS1, type = CommandType.STRING, description = "the first IPv4 DNS for the network. Empty string will update the first IPv4 DNS with the value from the zone", since = "4.18.0")
+    private String ip4Dns1;
+
+    @Parameter(name = ApiConstants.DNS2, type = CommandType.STRING, description = "the second IPv4 DNS for the network. Empty string will update the second IPv4 DNS with the value from the zone", since = "4.18.0")
+    private String ip4Dns2;
+
+    @Parameter(name = ApiConstants.IP6_DNS1, type = CommandType.STRING, description = "the first IPv6 DNS for the network. Empty string will update the first IPv6 DNS with the value from the zone", since = "4.18.0")
+    private String ip6Dns1;
+
+    @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the network. Empty string will update the second IPv6 DNS with the value from the zone", since = "4.18.0")
+    private String ip6Dns2;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -136,6 +148,23 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd implements UserCmd {
         }
         return forced;
     }
+
+    public String getIp4Dns1() {
+        return ip4Dns1;
+    }
+
+    public String getIp4Dns2() {
+        return ip4Dns2;
+    }
+
+    public String getIp6Dns1() {
+        return ip6Dns1;
+    }
+
+    public String getIp6Dns2() {
+        return ip6Dns2;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
index 8f6568fbe5..4df741f1d2 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
@@ -95,6 +95,18 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd implements UserCmd {
     @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the vpc to the end user or not", since = "4.4", authorized = {RoleType.Admin})
     private Boolean display;
 
+    @Parameter(name = ApiConstants.DNS1, type = CommandType.STRING, description = "the first IPv4 DNS for the VPC", since = "4.18.0")
+    private String ip4Dns1;
+
+    @Parameter(name = ApiConstants.DNS2, type = CommandType.STRING, description = "the second IPv4 DNS for the VPC", since = "4.18.0")
+    private String ip4Dns2;
+
+    @Parameter(name = ApiConstants.IP6_DNS1, type = CommandType.STRING, description = "the first IPv6 DNS for the VPC", since = "4.18.0")
+    private String ip6Dns1;
+
+    @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the VPC", since = "4.18.0")
+    private String ip6Dns2;
+
     // ///////////////////////////////////////////////////
     // ///////////////// Accessors ///////////////////////
     // ///////////////////////////////////////////////////
@@ -131,6 +143,22 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd implements UserCmd {
         return networkDomain;
     }
 
+    public String getIp4Dns1() {
+        return ip4Dns1;
+    }
+
+    public String getIp4Dns2() {
+        return ip4Dns2;
+    }
+
+    public String getIp6Dns1() {
+        return ip6Dns1;
+    }
+
+    public String getIp6Dns2() {
+        return ip6Dns2;
+    }
+
     public boolean isStart() {
         if (start != null) {
             return start;
@@ -144,7 +172,7 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd implements UserCmd {
 
     @Override
     public void create() throws ResourceAllocationException {
-        Vpc vpc = _vpcService.createVpc(getZoneId(), getVpcOffering(), getEntityOwnerId(), getVpcName(), getDisplayText(), getCidr(), getNetworkDomain(), getDisplayVpc());
+        Vpc vpc = _vpcService.createVpc(this);
         if (vpc != null) {
             setEntityId(vpc.getId());
             setEntityUuid(vpc.getUuid());
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java
index 7bed68f99b..19edc1b394 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java
@@ -120,11 +120,11 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement
     private String broadcastUri;
 
     @SerializedName(ApiConstants.DNS1)
-    @Param(description = "the first DNS for the network")
+    @Param(description = "the first IPv4 DNS for the network")
     private String dns1;
 
     @SerializedName(ApiConstants.DNS2)
-    @Param(description = "the second DNS for the network")
+    @Param(description = "the second IPv4 DNS for the network")
     private String dns2;
 
     @SerializedName(ApiConstants.TYPE)
@@ -287,6 +287,14 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement
     @Param(description = "The routes for the network to ease adding route in upstream router", since = "4.17.0")
     private Set<Ipv6RouteResponse> ipv6Routes;
 
+    @SerializedName(ApiConstants.IP6_DNS1)
+    @Param(description = "the first IPv6 DNS for the network", since = "4.18.0")
+    private String ipv6Dns1;
+
+    @SerializedName(ApiConstants.IP6_DNS2)
+    @Param(description = "the second IPv6 DNS for the network", since = "4.18.0")
+    private String ipv6Dns2;
+
     public NetworkResponse() {}
 
     public Boolean getDisplayNetwork() {
@@ -586,4 +594,12 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement
     public void addIpv6Route(Ipv6RouteResponse ipv6Route) {
         this.ipv6Routes.add(ipv6Route);
     }
+
+    public void setIpv6Dns1(String ipv6Dns1) {
+        this.ipv6Dns1 = ipv6Dns1;
+    }
+
+    public void setIpv6Dns2(String ipv6Dns2) {
+        this.ipv6Dns2 = ipv6Dns2;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VpcResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VpcResponse.java
index 3b5661f8a8..4ca594870a 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/VpcResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/VpcResponse.java
@@ -136,6 +136,22 @@ public class VpcResponse extends BaseResponseWithAnnotations implements Controll
     @Param(description = "The routes for the network to ease adding route in upstream router", since = "4.17.0")
     private Set<Ipv6RouteResponse> ipv6Routes;
 
+    @SerializedName(ApiConstants.DNS1)
+    @Param(description = "the first IPv4 DNS for the VPC")
+    private String dns1;
+
+    @SerializedName(ApiConstants.DNS2)
+    @Param(description = "the second IPv4 DNS for the VPC")
+    private String dns2;
+
+    @SerializedName(ApiConstants.IP6_DNS1)
+    @Param(description = "the first IPv6 DNS for the VPC", since = "4.18.0")
+    private String ipv6Dns1;
+
+    @SerializedName(ApiConstants.IP6_DNS2)
+    @Param(description = "the second IPv6 DNS for the VPC", since = "4.18.0")
+    private String ipv6Dns2;
+
     public void setId(final String id) {
         this.id = id;
     }
@@ -257,4 +273,20 @@ public class VpcResponse extends BaseResponseWithAnnotations implements Controll
     public Set<Ipv6RouteResponse> getIpv6Routes() {
         return ipv6Routes;
     }
+
+    public void setDns1(String dns1) {
+        this.dns1 = dns1;
+    }
+
+    public void setDns2(String dns2) {
+        this.dns2 = dns2;
+    }
+
+    public void setIpv6Dns1(String ipv6Dns1) {
+        this.ipv6Dns1 = ipv6Dns1;
+    }
+
+    public void setIpv6Dns2(String ipv6Dns2) {
+        this.ipv6Dns2 = ipv6Dns2;
+    }
 }
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
index b79cce5f60..cde00df026 100644
--- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java
@@ -187,7 +187,8 @@ public interface NetworkOrchestrationService {
 
     Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain, Account owner,
                                Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr,
-                               Boolean displayNetworkEnabled, String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String routerIp, String routerIpv6) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
+                               Boolean displayNetworkEnabled, String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String routerIp, String routerIpv6,
+                               String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
 
     UserDataServiceProvider getPasswordResetProvider(Network network);
 
diff --git a/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java b/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java
index 56e70ca56f..4974345d4e 100644
--- a/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java
+++ b/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java
@@ -109,8 +109,7 @@ public interface VpcManager {
     Network
         createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner,
             Long domainId, PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Long aclId, Account caller,
-            Boolean displayNetworkEnabled, String externalId, String ip6Gateway, String ip6Cidr)
-
+            Boolean displayNetworkEnabled, String externalId, String ip6Gateway, String ip6Cidr, String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2)
             throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
 
     /**
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index 3284511e01..a8464f39c3 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -38,7 +38,6 @@ import java.util.stream.Collectors;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import com.cloud.server.ManagementServer;
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.annotation.AnnotationService;
 import org.apache.cloudstack.annotation.dao.AnnotationDao;
@@ -55,6 +54,7 @@ import org.apache.cloudstack.framework.messagebus.MessageBus;
 import org.apache.cloudstack.framework.messagebus.PublishScope;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.network.dao.NetworkPermissionDao;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
@@ -197,6 +197,7 @@ import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
 import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import com.cloud.resource.ResourceManager;
+import com.cloud.server.ManagementServer;
 import com.cloud.user.Account;
 import com.cloud.user.ResourceLimitService;
 import com.cloud.user.User;
@@ -422,6 +423,38 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
 
     HashMap<Long, Long> _lastNetworkIdsToFree = new HashMap<Long, Long>();
 
+    private void updateRouterDefaultDns(final VirtualMachineProfile vmProfile, final NicProfile nicProfile) {
+        if (!Type.DomainRouter.equals(vmProfile.getType()) || !nicProfile.isDefaultNic()) {
+            return;
+        }
+        DomainRouterVO router = routerDao.findById(vmProfile.getId());
+        if (router != null && router.getVpcId() != null) {
+            final Vpc vpc = _vpcMgr.getActiveVpc(router.getVpcId());
+            if (StringUtils.isNotBlank(vpc.getIp4Dns1())) {
+                nicProfile.setIPv4Dns1(vpc.getIp4Dns1());
+                nicProfile.setIPv4Dns2(vpc.getIp4Dns2());
+            }
+            if (StringUtils.isNotBlank(vpc.getIp6Dns1())) {
+                nicProfile.setIPv6Dns1(vpc.getIp6Dns1());
+                nicProfile.setIPv6Dns2(vpc.getIp6Dns2());
+            }
+            return;
+        }
+        List<Long> networkIds = routerNetworkDao.getRouterNetworks(vmProfile.getId());
+        if (CollectionUtils.isEmpty(networkIds) || networkIds.size() > 1) {
+            return;
+        }
+        final NetworkVO routerNetwork = _networksDao.findById(networkIds.get(0));
+        if (StringUtils.isNotBlank(routerNetwork.getDns1())) {
+            nicProfile.setIPv4Dns1(routerNetwork.getDns1());
+            nicProfile.setIPv4Dns2(routerNetwork.getDns2());
+        }
+        if (StringUtils.isNotBlank(routerNetwork.getIp6Dns1())) {
+            nicProfile.setIPv6Dns1(routerNetwork.getIp6Dns1());
+            nicProfile.setIPv6Dns2(routerNetwork.getIp6Dns2());
+        }
+    }
+
     @Override
     @DB
     public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
@@ -1951,7 +1984,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
 
         profile.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(network));
         guru.updateNicProfile(profile, network);
-
+        updateRouterDefaultDns(vmProfile, profile);
         configureExtraDhcpOptions(network, nicId);
         return profile;
     }
@@ -2430,7 +2463,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
         // create network for private gateway
         return createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId,
                 bypassVlanOverlapCheck, null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null,
-                vpcId, null, null, true, null, null, null, true, null, null);
+                vpcId, null, null, true, null, null, null, true, null, null,
+                null, null, null, null);
     }
 
     @Override
@@ -2438,18 +2472,21 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
     public Network createGuestNetwork(final long networkOfferingId, final String name, final String displayText, final String gateway, final String cidr, String vlanId,
                                       boolean bypassVlanOverlapCheck, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk,
                                       final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr,
-                                      final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String routerIp, String routerIpv6) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
+                                      final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId,
+                                      String routerIp, String routerIpv6, String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
         // create Isolated/Shared/L2 network
         return createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, bypassVlanOverlapCheck,
                 networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr,
-                isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, externalId, false, routerIp, routerIpv6);
+                isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, externalId, false, routerIp, routerIpv6, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
     }
 
     @DB
     private Network createGuestNetwork(final long networkOfferingId, final String name, final String displayText, final String gateway, final String cidr, String vlanId,
                                        boolean bypassVlanOverlapCheck, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk,
                                        final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr,
-                                       final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, final Boolean isPrivateNetwork, String routerIp, String routerIpv6) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
+                                       final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId,
+                                       final Boolean isPrivateNetwork, String routerIp, String routerIpv6, final String ip4Dns1, final String ip4Dns2,
+                                       final String ip6Dns1, final String ip6Dns2) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
 
         final NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
         final DataCenterVO zone = _dcDao.findById(zoneId);
@@ -2724,6 +2761,21 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
                     userNetwork.setRouterIpv6(routerIpv6);
                 }
 
+                if (!GuestType.L2.equals(userNetwork.getGuestType())) {
+                    if (StringUtils.isNotBlank(ip4Dns1)) {
+                        userNetwork.setDns1(ip4Dns1);
+                    }
+                    if (StringUtils.isNotBlank(ip4Dns2)) {
+                        userNetwork.setDns2(ip4Dns2);
+                    }
+                    if (StringUtils.isNotBlank(ip6Dns1)) {
+                        userNetwork.setIp6Dns1(ip6Dns1);
+                    }
+                    if (StringUtils.isNotBlank(ip6Dns2)) {
+                        userNetwork.setIp6Dns2(ip6Dns2);
+                    }
+                }
+
                 if (vlanIdFinal != null) {
                     if (isolatedPvlan == null) {
                         URI uri = null;
diff --git a/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
index ff0a6faae2..f9adc9c643 100644
--- a/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
+++ b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java
@@ -29,8 +29,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import com.cloud.network.dao.PhysicalNetworkVO;
-import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.log4j.Logger;
 import org.junit.Assert;
 import org.junit.Before;
@@ -43,30 +41,44 @@ import org.mockito.Mockito;
 import com.cloud.dc.Vlan;
 import com.cloud.dc.VlanVO;
 import com.cloud.dc.dao.VlanDao;
+import com.cloud.deploy.DeployDestination;
 import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.network.IpAddress.State;
 import com.cloud.network.Network;
 import com.cloud.network.Network.GuestType;
 import com.cloud.network.Network.Service;
 import com.cloud.network.NetworkModel;
-import com.cloud.network.IpAddress.State;
 import com.cloud.network.Networks.TrafficType;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkServiceMapDao;
 import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.PhysicalNetworkVO;
+import com.cloud.network.dao.RouterNetworkDao;
 import com.cloud.network.element.DhcpServiceProvider;
+import com.cloud.network.guru.GuestNetworkGuru;
 import com.cloud.network.guru.NetworkGuru;
+import com.cloud.network.vpc.VpcManager;
+import com.cloud.network.vpc.VpcVO;
 import com.cloud.offerings.NetworkOfferingVO;
+import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.Ip;
+import com.cloud.vm.DomainRouterVO;
 import com.cloud.vm.Nic;
 import com.cloud.vm.NicProfile;
 import com.cloud.vm.NicVO;
+import com.cloud.vm.ReservationContext;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.Type;
 import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.DomainRouterDao;
 import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.NicExtraDhcpOptionDao;
 import com.cloud.vm.dao.NicIpAliasDao;
 import com.cloud.vm.dao.NicSecondaryIpDao;
 
@@ -89,6 +101,11 @@ public class NetworkOrchestratorTest extends TestCase {
 
     private static final long networkOfferingId = 1l;
 
+    final String[] ip4Dns = {"5.5.5.5", "6.6.6.6"};
+    final String[] ip6Dns = {"2001:4860:4860::5555", "2001:4860:4860::6666"};
+    final String[] ip4AltDns = {"7.7.7.7", "8.8.8.8"};
+    final String[] ip6AltDns = {"2001:4860:4860::7777", "2001:4860:4860::8888"};
+
     @Override
     @Before
     public void setUp() {
@@ -101,6 +118,11 @@ public class NetworkOrchestratorTest extends TestCase {
         testOrchastrator._nicIpAliasDao = mock(NicIpAliasDao.class);
         testOrchastrator._ipAddressDao = mock(IPAddressDao.class);
         testOrchastrator._vlanDao = mock(VlanDao.class);
+        testOrchastrator._networkModel = mock(NetworkModel.class);
+        testOrchastrator._nicExtraDhcpOptionDao = mock(NicExtraDhcpOptionDao.class);
+        testOrchastrator.routerDao = mock(DomainRouterDao.class);
+        testOrchastrator.routerNetworkDao = mock(RouterNetworkDao.class);
+        testOrchastrator._vpcMgr = mock(VpcManager.class);
         DhcpServiceProvider provider = mock(DhcpServiceProvider.class);
 
         Map<Network.Capability, String> capabilities = new HashMap<Network.Capability, String>();
@@ -556,4 +578,132 @@ public class NetworkOrchestratorTest extends TestCase {
         Assert.assertEquals(expectedIsolation, resultUri.getScheme());
         Assert.assertEquals(expectedUri, resultUri.toString());
     }
+
+    private NicProfile prepareMocksAndRunPrepareNic(VirtualMachine.Type vmType, boolean isDefaultNic, boolean isVpcRouter, boolean routerResourceHasCustomDns) {
+        Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
+        Long nicId = 1L;
+        Long vmId = 1L;
+        Long networkId = 1L;
+        Integer networkRate = 200;
+        Network network = Mockito.mock(Network.class);
+        Mockito.when(network.getGuruName()).thenReturn(GuestNetworkGuru.class.getSimpleName());
+        Mockito.when(network.getDns1()).thenReturn(ip4Dns[0]);
+        Mockito.when(network.getDns2()).thenReturn(ip4Dns[1]);
+        Mockito.when(network.getIp6Dns1()).thenReturn(ip6Dns[0]);
+        Mockito.when(network.getIp6Dns2()).thenReturn(ip6Dns[1]);
+        Mockito.when(testOrchastrator._networkModel.getNetworkRate(networkId, vmId)).thenReturn(networkRate);
+        NicVO nicVO = Mockito.mock(NicVO.class);
+        Mockito.when(nicVO.isDefaultNic()).thenReturn(isDefaultNic);
+        Mockito.when(testOrchastrator._nicDao.findById(nicId)).thenReturn(nicVO);
+        Mockito.when(testOrchastrator._nicDao.update(nicId, nicVO)).thenReturn(true);
+        Mockito.when(testOrchastrator._networkModel.isSecurityGroupSupportedInNetwork(network)).thenReturn(false);
+        Mockito.when(testOrchastrator._networkModel.getNetworkTag(hypervisorType, network)).thenReturn(null);
+        Mockito.when(testOrchastrator._ntwkSrvcDao.getDistinctProviders(networkId)).thenReturn(new ArrayList<>());
+        testOrchastrator.networkElements = new ArrayList<>();
+        Mockito.when(testOrchastrator._nicExtraDhcpOptionDao.listByNicId(nicId)).thenReturn(new ArrayList<>());
+        Mockito.when(testOrchastrator._ntwkSrvcDao.areServicesSupportedInNetwork(networkId, Service.Dhcp)).thenReturn(false);
+        VirtualMachineProfile virtualMachineProfile = Mockito.mock(VirtualMachineProfile.class);
+        Mockito.when(virtualMachineProfile.getType()).thenReturn(vmType);
+        Mockito.when(virtualMachineProfile.getId()).thenReturn(vmId);
+        DeployDestination deployDestination = Mockito.mock(DeployDestination.class);
+        ReservationContext reservationContext = Mockito.mock(ReservationContext.class);
+        Mockito.doAnswer((org.mockito.stubbing.Answer<Void>) invocation -> {
+            NicProfile nicProfile = (NicProfile) invocation.getArguments()[0];
+            Network ntwk = (Network) invocation.getArguments()[1];
+            nicProfile.setIPv4Dns1(ntwk.getDns1());
+            nicProfile.setIPv4Dns2(ntwk.getDns2());
+            nicProfile.setIPv6Dns1(ntwk.getIp6Dns1());
+            nicProfile.setIPv6Dns2(ntwk.getIp6Dns2());
+            return null;
+        }).when(guru).updateNicProfile(Mockito.any(NicProfile.class), Mockito.any(Network.class));
+        DomainRouterVO routerVO = Mockito.mock(DomainRouterVO.class);
+        if (isVpcRouter) {
+            Long vpcId = 1L;
+            Mockito.when(routerVO.getVpcId()).thenReturn(vpcId);
+            VpcVO vpcVO = Mockito.mock(VpcVO.class);
+            if (routerResourceHasCustomDns) {
+                Mockito.when(vpcVO.getIp4Dns1()).thenReturn(ip4AltDns[0]);
+                Mockito.when(vpcVO.getIp4Dns2()).thenReturn(ip4AltDns[1]);
+                Mockito.when(vpcVO.getIp6Dns1()).thenReturn(ip6AltDns[0]);
+                Mockito.when(vpcVO.getIp6Dns2()).thenReturn(ip6AltDns[1]);
+            } else {
+                Mockito.when(vpcVO.getIp4Dns1()).thenReturn(null);
+                Mockito.when(vpcVO.getIp6Dns1()).thenReturn(null);
+            }
+            Mockito.when(testOrchastrator._vpcMgr.getActiveVpc(vpcId)).thenReturn(vpcVO);
+        } else {
+            Mockito.when(routerVO.getVpcId()).thenReturn(null);
+            Long routerNetworkId = 2L;
+            NetworkVO routerNetworkVO = Mockito.mock(NetworkVO.class);
+            if (routerResourceHasCustomDns) {
+                Mockito.when(routerNetworkVO.getDns1()).thenReturn(ip4AltDns[0]);
+                Mockito.when(routerNetworkVO.getDns2()).thenReturn(ip4AltDns[1]);
+                Mockito.when(routerNetworkVO.getIp6Dns1()).thenReturn(ip6AltDns[0]);
+                Mockito.when(routerNetworkVO.getIp6Dns2()).thenReturn(ip6AltDns[1]);
+            } else {
+                Mockito.when(routerNetworkVO.getDns1()).thenReturn(null);
+                Mockito.when(routerNetworkVO.getIp6Dns1()).thenReturn(null);
+            }
+            Mockito.when(testOrchastrator.routerNetworkDao.getRouterNetworks(vmId)).thenReturn(List.of(routerNetworkId));
+            Mockito.when(testOrchastrator._networksDao.findById(routerNetworkId)).thenReturn(routerNetworkVO);
+        }
+        Mockito.when(testOrchastrator.routerDao.findById(vmId)).thenReturn(routerVO);
+        NicProfile profile = null;
+        try {
+            profile = testOrchastrator.prepareNic(virtualMachineProfile, deployDestination, reservationContext, nicId, network);
+        } catch (InsufficientCapacityException | ResourceUnavailableException e) {
+            Assert.fail(String.format("Failure with exception %s", e.getMessage()));
+        }
+        return profile;
+    }
+
+    @Test
+    public void testPrepareNicUserVm() {
+        NicProfile profile = prepareMocksAndRunPrepareNic(Type.User, false, false, false);
+        Assert.assertNotNull(profile);
+        Assert.assertEquals(ip4Dns[0], profile.getIPv4Dns1());
+        Assert.assertEquals(ip4Dns[1], profile.getIPv4Dns2());
+        Assert.assertEquals(ip6Dns[0], profile.getIPv6Dns1());
+        Assert.assertEquals(ip6Dns[1], profile.getIPv6Dns2());
+    }
+
+    @Test
+    public void testPrepareNicVpcRouterVm() {
+        NicProfile profile = prepareMocksAndRunPrepareNic(Type.DomainRouter, true, true, true);
+        Assert.assertNotNull(profile);
+        Assert.assertEquals(ip4AltDns[0], profile.getIPv4Dns1());
+        Assert.assertEquals(ip4AltDns[1], profile.getIPv4Dns2());
+        Assert.assertEquals(ip6AltDns[0], profile.getIPv6Dns1());
+        Assert.assertEquals(ip6AltDns[1], profile.getIPv6Dns2());
+    }
+
+    @Test
+    public void testPrepareNicVpcRouterNoDnsVm() {
+        NicProfile profile = prepareMocksAndRunPrepareNic(Type.DomainRouter, true, true, false);
+        Assert.assertNotNull(profile);
+        Assert.assertEquals(ip4Dns[0], profile.getIPv4Dns1());
+        Assert.assertEquals(ip4Dns[1], profile.getIPv4Dns2());
+        Assert.assertEquals(ip6Dns[0], profile.getIPv6Dns1());
+        Assert.assertEquals(ip6Dns[1], profile.getIPv6Dns2());
+    }
+
+    @Test
+    public void testPrepareNicNetworkRouterVm() {
+        NicProfile profile = prepareMocksAndRunPrepareNic(Type.DomainRouter, true, false, true);
+        Assert.assertNotNull(profile);
+        Assert.assertEquals(ip4AltDns[0], profile.getIPv4Dns1());
+        Assert.assertEquals(ip4AltDns[1], profile.getIPv4Dns2());
+        Assert.assertEquals(ip6AltDns[0], profile.getIPv6Dns1());
+        Assert.assertEquals(ip6AltDns[1], profile.getIPv6Dns2());
+    }
+
+    @Test
+    public void testPrepareNicNetworkRouterNoDnsVm() {
+        NicProfile profile = prepareMocksAndRunPrepareNic(Type.DomainRouter, true, false, false);
+        Assert.assertNotNull(profile);
+        Assert.assertEquals(ip4Dns[0], profile.getIPv4Dns1());
+        Assert.assertEquals(ip4Dns[1], profile.getIPv4Dns2());
+        Assert.assertEquals(ip6Dns[0], profile.getIPv6Dns1());
+        Assert.assertEquals(ip6Dns[1], profile.getIPv6Dns2());
+    }
 }
diff --git a/engine/schema/src/main/java/com/cloud/dc/DataCenterVO.java b/engine/schema/src/main/java/com/cloud/dc/DataCenterVO.java
index d0f3192c60..038daeaa10 100644
--- a/engine/schema/src/main/java/com/cloud/dc/DataCenterVO.java
+++ b/engine/schema/src/main/java/com/cloud/dc/DataCenterVO.java
@@ -183,15 +183,15 @@ public class DataCenterVO implements DataCenter {
         this.firewallProvider = firewallProvider;
     }
 
-    public DataCenterVO(long id, String name, String description, String dns1, String dns2, String dns3, String dns4, String guestCidr, String domain, Long domainId,
+    public DataCenterVO(long id, String name, String description, String dns1, String dns2, String internalDns1, String internalDns2, String guestCidr, String domain, Long domainId,
             NetworkType zoneType, String zoneToken, String domainSuffix) {
-        this(name, description, dns1, dns2, dns3, dns4, guestCidr, domain, domainId, zoneType, zoneToken, domainSuffix, false, false, null, null);
+        this(name, description, dns1, dns2, internalDns1, internalDns2, guestCidr, domain, domainId, zoneType, zoneToken, domainSuffix, false, false, null, null);
         this.id = id;
         this.allocationState = Grouping.AllocationState.Enabled;
         this.uuid = UUID.randomUUID().toString();
     }
 
-    public DataCenterVO(String name, String description, String dns1, String dns2, String dns3, String dns4, String guestCidr, String domain, Long domainId,
+    public DataCenterVO(String name, String description, String dns1, String dns2, String internalDns1, String internalDns2, String guestCidr, String domain, Long domainId,
             NetworkType zoneType, String zoneToken, String domainSuffix, boolean securityGroupEnabled, boolean localStorageEnabled, String ip6Dns1, String ip6Dns2) {
         this.name = name;
         this.description = description;
@@ -199,8 +199,8 @@ public class DataCenterVO implements DataCenter {
         this.dns2 = dns2;
         this.ip6Dns1 = ip6Dns1;
         this.ip6Dns2 = ip6Dns2;
-        this.internalDns1 = dns3;
-        this.internalDns2 = dns4;
+        this.internalDns1 = internalDns1;
+        this.internalDns2 = internalDns2;
         this.guestNetworkCidr = guestCidr;
         this.domain = domain;
         this.domainId = domainId;
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java
index 4dbcda670a..e6869b4b26 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java
@@ -30,6 +30,7 @@ import javax.persistence.TableGenerator;
 import javax.persistence.Transient;
 
 import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.commons.lang3.StringUtils;
 
 import com.cloud.network.Network;
 import com.cloud.network.Networks.BroadcastDomainType;
@@ -106,9 +107,6 @@ public class NetworkVO implements Network {
     @Column(name = "redundant")
     boolean redundant;
 
-    @Column(name = "dns1")
-    String dns1;
-
     @Column(name = "domain_id")
     long domainId;
 
@@ -125,9 +123,18 @@ public class NetworkVO implements Network {
     @Column(name = "guru_data", length = 1024)
     String guruData;
 
+    @Column(name = "dns1")
+    String dns1;
+
     @Column(name = "dns2")
     String dns2;
 
+    @Column(name = "ip6Dns1")
+    String ip6Dns1;
+
+    @Column(name = "ip6Dns2")
+    String ip6Dns2;
+
     @Column(name = "network_domain")
     String networkDomain;
 
@@ -255,6 +262,18 @@ public class NetworkVO implements Network {
         uuid = UUID.randomUUID().toString();
         ip6Gateway = that.getIp6Gateway();
         ip6Cidr = that.getIp6Cidr();
+        if (StringUtils.isNotBlank(that.getDns1())) {
+            this.dns1 = that.getDns1();
+        }
+        if (StringUtils.isNotBlank(that.getDns2())) {
+            this.dns2 = that.getDns2();
+        }
+        if (StringUtils.isNotBlank(that.getIp6Dns1())) {
+            this.ip6Dns1 = that.getIp6Dns1();
+        }
+        if (StringUtils.isNotBlank(that.getIp6Dns2())) {
+            this.ip6Dns2 = that.getIp6Dns2();
+        }
         this.externalId = externalId;
     }
 
@@ -471,6 +490,7 @@ public class NetworkVO implements Network {
         return dataCenterId;
     }
 
+    @Override
     public String getDns1() {
         return dns1;
     }
@@ -479,6 +499,7 @@ public class NetworkVO implements Network {
         dns1 = dns;
     }
 
+    @Override
     public String getDns2() {
         return dns2;
     }
@@ -487,6 +508,24 @@ public class NetworkVO implements Network {
         dns2 = dns;
     }
 
+    @Override
+    public String getIp6Dns1() {
+        return ip6Dns1;
+    }
+
+    public void setIp6Dns1(String ip6Dns1) {
+        this.ip6Dns1 = ip6Dns1;
+    }
+
+    @Override
+    public String getIp6Dns2() {
+        return ip6Dns2;
+    }
+
+    public void setIp6Dns2(String ip6Dns2) {
+        this.ip6Dns2 = ip6Dns2;
+    }
+
     @Override
     public String getName() {
         return name;
diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/VpcVO.java b/engine/schema/src/main/java/com/cloud/network/vpc/VpcVO.java
index 83034b3fdb..c2c57b11fb 100644
--- a/engine/schema/src/main/java/com/cloud/network/vpc/VpcVO.java
+++ b/engine/schema/src/main/java/com/cloud/network/vpc/VpcVO.java
@@ -89,6 +89,18 @@ public class VpcVO implements Vpc {
     @Column(name = "region_level_vpc")
     boolean regionLevelVpc = false;
 
+    @Column(name = "dns1")
+    String ip4Dns1;
+
+    @Column(name = "dns2")
+    String ip4Dns2;
+
+    @Column(name = "ip6Dns1")
+    String ip6Dns1;
+
+    @Column(name = "ip6Dns2")
+    String ip6Dns2;
+
     @Transient
     boolean rollingRestart = false;
 
@@ -97,8 +109,9 @@ public class VpcVO implements Vpc {
     }
 
     public VpcVO(final long zoneId, final String name, final String displayText, final long accountId, final long domainId,
-            final long vpcOffId, final String cidr, final String networkDomain, final boolean useDistributedRouter,
-            final boolean regionLevelVpc, final boolean isRedundant) {
+                 final long vpcOffId, final String cidr, final String networkDomain, final boolean useDistributedRouter,
+                 final boolean regionLevelVpc, final boolean isRedundant, final String ip4Dns1, final String ip4Dns2,
+                 final String ip6Dns1, final String ip6Dns2) {
         this.zoneId = zoneId;
         this.name = name;
         this.displayText = displayText;
@@ -112,6 +125,10 @@ public class VpcVO implements Vpc {
         usesDistributedRouter = useDistributedRouter;
         this.regionLevelVpc = regionLevelVpc;
         redundant = isRedundant;
+        this.ip4Dns1 = ip4Dns1;
+        this.ip4Dns2 = ip4Dns2;
+        this.ip6Dns1 = ip6Dns1;
+        this.ip6Dns2 = ip6Dns2;
     }
 
     @Override
@@ -255,4 +272,24 @@ public class VpcVO implements Vpc {
     public boolean usesDistributedRouter() {
         return usesDistributedRouter;
     }
+
+    @Override
+    public String getIp4Dns1() {
+        return ip4Dns1;
+    }
+
+    @Override
+    public String getIp4Dns2() {
+        return ip4Dns2;
+    }
+
+    @Override
+    public String getIp6Dns1() {
+        return ip6Dns1;
+    }
+
+    @Override
+    public String getIp6Dns2() {
+        return ip6Dns2;
+    }
 }
diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java
index 56de31819d..06cfd25e67 100644
--- a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java
+++ b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java
@@ -31,7 +31,7 @@ public interface VpcOfferingServiceMapDao extends GenericDao<VpcOfferingServiceM
      * @param services
      * @return
      */
-    boolean areServicesSupportedByNetworkOffering(long networkOfferingId, Service[] services);
+    boolean areServicesSupportedByVpcOffering(long vpcOfferingId, Service[] services);
 
     List<String> listServicesForVpcOffering(long vpcOfferingId);
 
diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java
index 9e14bb5348..c7400f6edf 100644
--- a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java
@@ -65,9 +65,9 @@ public class VpcOfferingServiceMapDaoImpl extends GenericDaoBase<VpcOfferingServ
     }
 
     @Override
-    public boolean areServicesSupportedByNetworkOffering(long networkOfferingId, Service... services) {
+    public boolean areServicesSupportedByVpcOffering(long vpcOfferingId, Service... services) {
         SearchCriteria<VpcOfferingServiceMapVO> sc = MultipleServicesSearch.create();
-        sc.setParameters("vpcOffId", networkOfferingId);
+        sc.setParameters("vpcOffId", vpcOfferingId);
 
         if (services != null) {
             String[] servicesStr = new String[services.length];
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql b/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql
index 4ec812cc1c..f57b75c737 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql
@@ -18,7 +18,6 @@
 --;
 -- Schema upgrade from 4.17.1.0 to 4.18.0.0
 --;
-
 -- Enable CPU cap for default system offerings;
 UPDATE `cloud`.`service_offering` so
 SET so.limit_cpu_use = 1
@@ -27,3 +26,14 @@ WHERE so.default_use = 1 AND so.vm_type IN ('domainrouter', 'secondarystoragevm'
 -- Add cidr_list column to load_balancing_rules
 ALTER TABLE `cloud`.`load_balancing_rules`
 ADD cidr_list VARCHAR(4096);
+
+-- Alter networks table to add ip6dns1 and ip6dns2
+ALTER TABLE `cloud`.`networks`
+    ADD COLUMN `ip6dns1` varchar(255) DEFAULT NULL COMMENT 'first IPv6 DNS for the network' AFTER `dns2`,
+    ADD COLUMN `ip6dns2` varchar(255) DEFAULT NULL COMMENT 'second IPv6 DNS for the network' AFTER `ip6dns1`;
+-- Alter vpc table to add dns1, dns2, ip6dns1 and ip6dns2
+ALTER TABLE `cloud`.`vpc`
+    ADD COLUMN `dns1` varchar(255) DEFAULT NULL COMMENT 'first IPv4 DNS for the vpc' AFTER `network_domain`,
+    ADD COLUMN `dns2` varchar(255) DEFAULT NULL COMMENT 'second IPv4 DNS for the vpc' AFTER `dns1`,
+    ADD COLUMN `ip6dns1` varchar(255) DEFAULT NULL COMMENT 'first IPv6 DNS for the vpc' AFTER `dns2`,
+    ADD COLUMN `ip6dns2` varchar(255) DEFAULT NULL COMMENT 'second IPv6 DNS for the vpc' AFTER `ip6dns1`;
diff --git a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java
index 68acee88ab..bf6932f05d 100644
--- a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java
+++ b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java
@@ -41,6 +41,7 @@ import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.IpAddressManager;
 import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
 import com.cloud.network.Networks.AddressFormat;
 import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.Networks.IsolationType;
@@ -49,6 +50,7 @@ import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.guru.DirectPodBasedNetworkGuru;
 import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.utils.Pair;
 import com.cloud.utils.db.Transaction;
 import com.cloud.utils.db.TransactionCallbackNoReturn;
 import com.cloud.utils.db.TransactionStatus;
@@ -74,6 +76,8 @@ public class BaremetaNetworkGuru extends DirectPodBasedNetworkGuru {
     PodVlanMapDao _podVlanDao;
     @Inject
     IpAddressManager _ipAddrMgr;
+    @Inject
+    NetworkModel networkModel;
 
     @Override
     public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context)
@@ -125,8 +129,9 @@ public class BaremetaNetworkGuru extends DirectPodBasedNetworkGuru {
         }
 
         DataCenter dc = _dcDao.findById(network.getDataCenterId());
-        nic.setIPv4Dns1(dc.getDns1());
-        nic.setIPv4Dns2(dc.getDns2());
+        Pair<String, String> dns = networkModel.getNetworkIp4Dns(network, dc);
+        nic.setIPv4Dns1(dns.first());
+        nic.setIPv4Dns2(dns.second());
 
         /*
          * Pod pod = dest.getPod(); Pair<String, Long> ip =
@@ -167,7 +172,8 @@ public class BaremetaNetworkGuru extends DirectPodBasedNetworkGuru {
             nic.setReservationId(String.valueOf(ip.getVlanTag()));
             nic.setMacAddress(ip.getMacAddress());
         }
-        nic.setIPv4Dns1(dc.getDns1());
-        nic.setIPv4Dns2(dc.getDns2());
+        Pair<String, String> dns = networkModel.getNetworkIp4Dns(network, dc);
+        nic.setIPv4Dns1(dns.first());
+        nic.setIPv4Dns2(dns.second());
     }
 }
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
index fa96e8b24b..e1c205e29c 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
@@ -16,6 +16,58 @@
 // under the License.
 package com.cloud.kubernetes.cluster;
 
+import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
+
+import java.math.BigInteger;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+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.acl.ControlledEntity;
+import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.annotation.AnnotationService;
+import org.apache.cloudstack.annotation.dao.AnnotationDao;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiConstants.VMDetails;
+import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.CreateKubernetesClusterCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.DeleteKubernetesClusterCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.GetKubernetesClusterConfigCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.ListKubernetesClustersCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.ScaleKubernetesClusterCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.StartKubernetesClusterCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.StopKubernetesClusterCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.UpgradeKubernetesClusterCmd;
+import org.apache.cloudstack.api.response.KubernetesClusterConfigResponse;
+import org.apache.cloudstack.api.response.KubernetesClusterResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.config.ApiServiceConfiguration;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.managed.context.ManagedContextRunnable;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+
 import com.cloud.api.ApiDBUtils;
 import com.cloud.api.query.dao.NetworkOfferingJoinDao;
 import com.cloud.api.query.dao.TemplateJoinDao;
@@ -117,56 +169,6 @@ import com.cloud.utils.net.NetUtils;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.dao.VMInstanceDao;
-import org.apache.cloudstack.acl.ControlledEntity;
-import org.apache.cloudstack.acl.SecurityChecker;
-import org.apache.cloudstack.annotation.AnnotationService;
-import org.apache.cloudstack.annotation.dao.AnnotationDao;
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.ApiConstants.VMDetails;
-import org.apache.cloudstack.api.ResponseObject.ResponseView;
-import org.apache.cloudstack.api.command.user.kubernetes.cluster.CreateKubernetesClusterCmd;
-import org.apache.cloudstack.api.command.user.kubernetes.cluster.DeleteKubernetesClusterCmd;
-import org.apache.cloudstack.api.command.user.kubernetes.cluster.GetKubernetesClusterConfigCmd;
-import org.apache.cloudstack.api.command.user.kubernetes.cluster.ListKubernetesClustersCmd;
-import org.apache.cloudstack.api.command.user.kubernetes.cluster.ScaleKubernetesClusterCmd;
-import org.apache.cloudstack.api.command.user.kubernetes.cluster.StartKubernetesClusterCmd;
-import org.apache.cloudstack.api.command.user.kubernetes.cluster.StopKubernetesClusterCmd;
-import org.apache.cloudstack.api.command.user.kubernetes.cluster.UpgradeKubernetesClusterCmd;
-import org.apache.cloudstack.api.response.KubernetesClusterConfigResponse;
-import org.apache.cloudstack.api.response.KubernetesClusterResponse;
-import org.apache.cloudstack.api.response.ListResponse;
-import org.apache.cloudstack.api.response.UserVmResponse;
-import org.apache.cloudstack.config.ApiServiceConfiguration;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
-import org.apache.cloudstack.framework.config.ConfigKey;
-import org.apache.cloudstack.managed.context.ManagedContextRunnable;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-
-import javax.inject.Inject;
-import javax.naming.ConfigurationException;
-import java.math.BigInteger;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
 
 public class KubernetesClusterManagerImpl extends ManagerBase implements KubernetesClusterService {
 
@@ -761,7 +763,9 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
 
             try {
                 network = networkMgr.createGuestNetwork(networkOffering.getId(), clusterName + "-network", owner.getAccountName() + "-network",
-                        null, null, null, false, null, owner, null, physicalNetwork, zone.getId(), ControlledEntity.ACLType.Account, null, null, null, null, true, null, null, null, null, null);
+                        null, null, null, false, null, owner, null, physicalNetwork, zone.getId(),
+                        ControlledEntity.ACLType.Account, null, null, null, null, true, null,
+                        null, null, null, null, null, null, null, null);
             } catch (ConcurrentOperationException | InsufficientCapacityException | ResourceAllocationException e) {
                 logAndThrow(Level.ERROR, String.format("Unable to create network for the Kubernetes cluster: %s", clusterName));
             }
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index 411d0e1c0a..52502f39cf 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -2374,6 +2374,8 @@ public class ApiResponseHelper implements ResponseGenerator {
 
         response.setDns1(profile.getDns1());
         response.setDns2(profile.getDns2());
+        response.setIpv6Dns1(profile.getIp6Dns1());
+        response.setIpv6Dns2(profile.getIp6Dns2());
         // populate capability
         Map<Service, Map<Capability, String>> serviceCapabilitiesMap = ApiDBUtils.getNetworkCapabilities(network.getId(), network.getDataCenterId());
         Map<Service, Set<Provider>> serviceProviderMap = ApiDBUtils.listNetworkOfferingServices(network.getNetworkOfferingId());
@@ -3235,6 +3237,10 @@ public class ApiResponseHelper implements ResponseGenerator {
         response.setHasAnnotation(annotationDao.hasAnnotations(vpc.getUuid(), AnnotationService.EntityType.VPC.name(),
                 _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())));
         ipv6Service.updateIpv6RoutesForVpcResponse(vpc, response);
+        response.setDns1(vpc.getIp4Dns1());
+        response.setDns2(vpc.getIp4Dns2());
+        response.setIpv6Dns1(vpc.getIp6Dns1());
+        response.setIpv6Dns2(vpc.getIp6Dns2());
         response.setObjectName("vpc");
         return response;
     }
diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
index 20b7a2b67d..3c8b6c58d9 100644
--- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
+++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
@@ -143,6 +143,8 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
         to.setIp6Address(profile.getIPv6Address());
         to.setIp6Gateway(profile.getIPv6Gateway());
         to.setIp6Cidr(profile.getIPv6Cidr());
+        to.setIp6Dns1(profile.getIPv6Dns1());
+        to.setIp6Dns2(profile.getIPv6Dns2());
 
         NetworkVO network = networkDao.findById(profile.getNetworkId());
         to.setNetworkUuid(network.getUuid());
diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
index 7ec4d0fd37..010925b700 100644
--- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
@@ -1802,7 +1802,8 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
                             s_logger.debug("Creating network for account " + owner + " from the network offering id=" + requiredOfferings.get(0).getId()
                                     + " as a part of createVlanIpRange process");
                             guestNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName()
-                                    + "-network", null, null, null, false, null, owner, null, physicalNetwork, zoneId, ACLType.Account, null, null, null, null, true, null, null, null, null, null);
+                                    + "-network", null, null, null, false, null, owner, null, physicalNetwork, zoneId, ACLType.Account, null, null, null, null, true, null, null, null, null, null,
+                                    null, null, null, null);
                             if (guestNetwork == null) {
                                 s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId);
                                 throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT "
@@ -2210,8 +2211,9 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
                             nic.setMacAddress(ip.getMacAddress());
                         }
                     }
-                    nic.setIPv4Dns1(dc.getDns1());
-                    nic.setIPv4Dns2(dc.getDns2());
+                    Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
+                    nic.setIPv4Dns1(dns.first());
+                    nic.setIPv4Dns2(dns.second());
                 }
 
                 _ipv6Mgr.setNicIp6Address(nic, dc, network);
@@ -2260,8 +2262,9 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
                             nic.setMacAddress(_networkModel.getNextAvailableMacAddressInNetwork(network.getId()));
                         }
                     }
-                    nic.setIPv4Dns1(dc.getDns1());
-                    nic.setIPv4Dns2(dc.getDns2());
+                    Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
+                    nic.setIPv4Dns1(dns.first());
+                    nic.setIPv4Dns2(dns.second());
                 }
 
                 _ipv6Mgr.setNicIp6Address(nic, dc, network);
diff --git a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java
index 2a53708fc5..0d683292cf 100644
--- a/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/Ipv6AddressManagerImpl.java
@@ -42,6 +42,7 @@ import com.cloud.network.dao.NetworkDetailsDao;
 import com.cloud.network.dao.UserIpv6AddressDao;
 import com.cloud.user.Account;
 import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.Pair;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.net.NetUtils;
@@ -226,8 +227,9 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa
                             IPv6Address.class.getName(), null);
                 }
             }
-            nic.setIPv6Dns1(dc.getIp6Dns1());
-            nic.setIPv6Dns2(dc.getIp6Dns2());
+            Pair<String, String> dns = _networkModel.getNetworkIp6Dns(network, dc);
+            nic.setIPv6Dns1(dns.first());
+            nic.setIPv6Dns2(dns.second());
         }
     }
 
diff --git a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java
index dd0f6c49e3..47537a69d1 100644
--- a/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java
@@ -447,8 +447,9 @@ public class Ipv6ServiceImpl extends ComponentLifecycleBase implements Ipv6Servi
             } else {
                 nic.setFormat(Networks.AddressFormat.Ip6);
             }
-            nic.setIPv6Dns1(dc.getIp6Dns1());
-            nic.setIPv6Dns2(dc.getIp6Dns2());
+            Pair<String, String> dns = networkModel.getNetworkIp6Dns(network, dc);
+            nic.setIPv6Dns1(dns.first());
+            nic.setIPv6Dns2(dns.second());
         }
     }
 
diff --git a/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java b/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java
index 748ea5c68a..1df42a54ac 100644
--- a/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java
@@ -297,8 +297,9 @@ public class NetworkMigrationManagerImpl implements NetworkMigrationManager {
         Vpc copyOfVpc;
         long copyOfVpcId;
         try {
-            copyOfVpc = _vpcService.createVpc(vpc.getZoneId(), vpcOfferingId, vpc.getAccountId(), vpc.getName(), vpc.getDisplayText(), vpc.getCidr(),
-                                              vpc.getNetworkDomain(), vpc.isDisplay());
+            copyOfVpc = _vpcService.createVpc(vpc.getZoneId(), vpcOfferingId, vpc.getAccountId(), vpc.getName(),
+                    vpc.getDisplayText(), vpc.getCidr(), vpc.getNetworkDomain(), vpc.getIp4Dns1(), vpc.getIp4Dns2(),
+                    vpc.getIp6Dns1(), vpc.getIp6Dns2(), vpc.isDisplay());
             copyOfVpcId = copyOfVpc.getId();
             //on resume of migration the uuid will be swapped already. So the copy will have the value of the original vpcid.
             _resourceTagDao.persist(new ResourceTagVO(MIGRATION, Long.toString(vpcId), vpc.getAccountId(), vpc.getDomainId(), copyOfVpcId, ResourceTag.ResourceObjectType.Vpc, null, vpc.getUuid()));
diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
index c601c13e6a..d183ba0dd9 100644
--- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
@@ -79,6 +79,7 @@ import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.NetworkAccountDao;
 import com.cloud.network.dao.NetworkAccountVO;
 import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkDetailsDao;
 import com.cloud.network.dao.NetworkDomainDao;
 import com.cloud.network.dao.NetworkDomainVO;
 import com.cloud.network.dao.NetworkServiceMapDao;
@@ -119,6 +120,7 @@ import com.cloud.user.AccountVO;
 import com.cloud.user.DomainManager;
 import com.cloud.user.User;
 import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.Pair;
 import com.cloud.utils.StringUtils;
 import com.cloud.utils.component.AdapterBase;
 import com.cloud.utils.component.ManagerBase;
@@ -166,6 +168,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
     @Inject
     NetworkDao _networksDao = null;
     @Inject
+    NetworkDetailsDao networkDetailsDao;
+    @Inject
     NicDao _nicDao = null;
     @Inject
     PodVlanMapDao _podVlanMapDao;
@@ -2637,4 +2641,46 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
         String networkCidr = guestNetwork.getNetworkCidr();
         return networkCidr == null ? guestNetwork.getCidr() : networkCidr;
     }
+
+    @Override
+    public Pair<String, String> getNetworkIp4Dns(final Network network, final DataCenter zone) {
+        if (org.apache.commons.lang3.StringUtils.isNotBlank(network.getDns1())) {
+            return new Pair<>(network.getDns1(), network.getDns2());
+        }
+        return new Pair<>(zone.getDns1(), zone.getDns2());
+    }
+
+    @Override
+    public Pair<String, String> getNetworkIp6Dns(final Network network, final DataCenter zone) {
+        if (org.apache.commons.lang3.StringUtils.isNotBlank(network.getIp6Dns1())) {
+            return new Pair<>(network.getIp6Dns1(), network.getIp6Dns2());
+        }
+        return new Pair<>(zone.getIp6Dns1(), zone.getIp6Dns2());
+    }
+
+    @Override
+    public void verifyIp4DnsPair(String ip4Dns1, String ip4Dns2) {
+        if (org.apache.commons.lang3.StringUtils.isEmpty(ip4Dns1) && org.apache.commons.lang3.StringUtils.isNotEmpty(ip4Dns2)) {
+            throw new InvalidParameterValueException("Second IPv4 DNS can be specified only with the first IPv4 DNS");
+        }
+        if (org.apache.commons.lang3.StringUtils.isNotEmpty(ip4Dns1) && !NetUtils.isValidIp4(ip4Dns1)) {
+            throw new InvalidParameterValueException("Invalid IPv4 for DNS1");
+        }
+        if (org.apache.commons.lang3.StringUtils.isNotEmpty(ip4Dns2) && !NetUtils.isValidIp4(ip4Dns2)) {
+            throw new InvalidParameterValueException("Invalid IPv4 for DNS2");
+        }
+    }
+
+    @Override
+    public void verifyIp6DnsPair(String ip6Dns1, String ip6Dns2) {
+        if (org.apache.commons.lang3.StringUtils.isEmpty(ip6Dns1) && org.apache.commons.lang3.StringUtils.isNotEmpty(ip6Dns2)) {
+            throw new InvalidParameterValueException("Second IPv6 DNS can be specified only with the first IPv6 DNS");
+        }
+        if (org.apache.commons.lang3.StringUtils.isNotEmpty(ip6Dns1) && !NetUtils.isValidIp6(ip6Dns1)) {
+            throw new InvalidParameterValueException("Invalid IPv6 for IPv6 DNS1");
+        }
+        if (org.apache.commons.lang3.StringUtils.isNotEmpty(ip6Dns2) && !NetUtils.isValidIp6(ip6Dns2)) {
+            throw new InvalidParameterValueException("Invalid IPv6 for IPv6 DNS2");
+        }
+    }
 }
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index 4ad5b4a6b3..fefe6c98cc 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -74,6 +74,7 @@ import org.apache.cloudstack.network.dao.NetworkPermissionDao;
 import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.EnumUtils;
+import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
@@ -571,6 +572,70 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
         return result;
     }
 
+    private void checkNetworkDns(boolean isIpv6, NetworkOffering networkOffering, Long vpcId,
+        String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2) {
+        if (ObjectUtils.anyNotNull(ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2)) {
+            if (GuestType.L2.equals(networkOffering.getGuestType())) {
+                throw new InvalidParameterValueException(String.format("DNS can not be specified %s networks", GuestType.L2));
+            }
+            if (vpcId != null) {
+                throw new InvalidParameterValueException("DNS can not be specified for a VPC tier");
+            }
+            if (!areServicesSupportedByNetworkOffering(networkOffering.getId(), Service.Dns)) {
+                throw new InvalidParameterValueException("DNS can not be specified for networks with network offering that do not support DNS service");
+            }
+        }
+        if (!isIpv6 && !StringUtils.isAllEmpty(ip6Dns1, ip6Dns2)) {
+            throw new InvalidParameterValueException("IPv6 DNS cannot be specified for IPv4 only network");
+        }
+        _networkModel.verifyIp4DnsPair(ip4Dns1, ip4Dns2);
+        _networkModel.verifyIp6DnsPair(ip6Dns1, ip6Dns2);
+    }
+
+    protected boolean checkAndUpdateNetworkDns(NetworkVO network, NetworkOffering networkOffering, String newIp4Dns1,
+        String newIp4Dns2, String newIp6Dns1, String newIp6Dns2) {
+        String ip4Dns1 = network.getDns1();
+        String ip4Dns2 = network.getDns2();
+        String ip6Dns1 = network.getIp6Dns1();
+        String ip6Dns2 = network.getIp6Dns2();
+        if (ObjectUtils.allNull(newIp4Dns1, newIp4Dns2, newIp6Dns1, newIp6Dns2)) {
+            if (ObjectUtils.anyNotNull(ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2) &&
+                    !areServicesSupportedByNetworkOffering(networkOffering.getId(), Service.Dns)) {
+                network.setDns1(null);
+                network.setDns2(null);
+                network.setIp6Dns1(null);
+                network.setIp6Dns2(null);
+                return true;
+            }
+            return false;
+        }
+        if (StringUtils.equals(ip4Dns1, StringUtils.trimToNull(newIp4Dns1)) && StringUtils.equals(ip4Dns2, StringUtils.trimToNull(newIp4Dns2)) &&
+                StringUtils.equals(ip6Dns1, StringUtils.trimToNull(newIp6Dns1)) && StringUtils.equals(ip6Dns2, StringUtils.trimToNull(newIp6Dns2))) {
+            return false;
+        }
+        boolean isIpv6 = (GuestType.Shared.equals(network.getGuestType()) &&
+                StringUtils.isNotEmpty(network.getIp6Cidr())) ||
+                _networkOfferingDao.isIpv6Supported(networkOffering.getId());
+        if (newIp4Dns1 != null) {
+            ip4Dns1 = StringUtils.trimToNull(newIp4Dns1);
+        }
+        if (newIp4Dns2 != null) {
+            ip4Dns2 = StringUtils.trimToNull(newIp4Dns2);
+        }
+        if (newIp6Dns1 != null) {
+            ip6Dns1 = StringUtils.trimToNull(newIp6Dns1);
+        }
+        if (newIp6Dns2 != null) {
+            ip6Dns2 = StringUtils.trimToNull(newIp6Dns2);
+        }
+        checkNetworkDns(isIpv6, networkOffering, network.getVpcId(), ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
+        network.setDns1(ip4Dns1);
+        network.setDns2(ip4Dns2);
+        network.setIp6Dns1(ip6Dns1);
+        network.setIp6Dns2(ip6Dns2);
+        return true;
+    }
+
     @Override
     public List<? extends Network> getIsolatedNetworksOwnedByAccountInZone(long zoneId, Account owner) {
 
@@ -1273,6 +1338,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
         String externalId = cmd.getExternalId();
         String isolatedPvlanType = cmd.getIsolatedPvlanType();
         Long associatedNetworkId = cmd.getAssociatedNetworkId();
+        String ip4Dns1 = cmd.getIp4Dns1();
+        String ip4Dns2 = cmd.getIp4Dns2();
+        String ip6Dns1 = cmd.getIp6Dns1();
+        String ip6Dns2 = cmd.getIp6Dns2();
 
         // Validate network offering
         NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
@@ -1486,7 +1555,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
                 throw new InvalidParameterValueException("Can only support create IPv6 network with advance shared network!");
             }
 
-            if(StringUtils.isAllBlank(zone.getIp6Dns1(), zone.getIp6Dns2())) {
+            if(StringUtils.isAllBlank(ip6Dns1, ip6Dns2, zone.getIp6Dns1(), zone.getIp6Dns2())) {
                 throw new InvalidParameterValueException("Can only create IPv6 network if the zone has IPv6 DNS! Please configure the zone IPv6 DNS1 and/or IPv6 DNS2.");
             }
 
@@ -1609,9 +1678,11 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
                     cidr, startIP, endIP);
         }
 
+        checkNetworkDns(ipv6, ntwkOff, vpcId, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
+
         Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zoneId,
                 domainId, isDomainSpecific, subdomainAccess, vpcId, startIPv6, endIPv6, ip6Gateway, ip6Cidr, displayNetwork, aclId, secondaryVlanId, privateVlanType, ntwkOff, pNtwk, aclType, owner, cidr, createVlan,
-                externalId, routerIp, routerIpv6, associatedNetwork);
+                externalId, routerIp, routerIpv6, associatedNetwork, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
 
         if (hideIpAddressUsage) {
             _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.hideIpAddressUsage, String.valueOf(hideIpAddressUsage), false));
@@ -1753,7 +1824,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
                                   final boolean isDomainSpecific, final Boolean subdomainAccessFinal, final Long vpcId, final String startIPv6, final String endIPv6, final String ip6Gateway, final String ip6Cidr,
                                   final Boolean displayNetwork, final Long aclId, final String isolatedPvlan, final PVlanType isolatedPvlanType, final NetworkOfferingVO ntwkOff, final PhysicalNetwork pNtwk, final ACLType aclType, final Account ownerFinal,
                                   final String cidr, final boolean createVlan, final String externalId, String routerIp, String routerIpv6,
-                                  final Network associatedNetwork) throws InsufficientCapacityException, ResourceAllocationException {
+                                  final Network associatedNetwork, final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2) throws InsufficientCapacityException, ResourceAllocationException {
         try {
             Network network = Transaction.execute(new TransactionCallbackWithException<Network, Exception>() {
                 @Override
@@ -1812,7 +1883,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
                             }
                         }
                         network = _vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType,
-                                subdomainAccess, vpcId, aclId, caller, displayNetwork, externalId, ip6Gateway, ip6Cidr);
+                                subdomainAccess, vpcId, aclId, caller, displayNetwork, externalId, ip6Gateway, ip6Cidr, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
                     } else {
                         if (_configMgr.isOfferingForVpc(ntwkOff)) {
                             throw new InvalidParameterValueException("Network offering can be used for VPC networks only");
@@ -1822,7 +1893,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
                         }
 
                         network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, bypassVlanOverlapCheck, networkDomain, owner, sharedDomainId, pNtwk,
-                                zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr, displayNetwork, isolatedPvlan, isolatedPvlanType, externalId, routerIp, routerIpv6);
+                                zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr, displayNetwork, isolatedPvlan, isolatedPvlanType, externalId, routerIp, routerIpv6, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
                     }
 
                     if (createVlan && network != null) {
@@ -2587,6 +2658,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
         String customId = cmd.getCustomId();
         boolean updateInSequence = cmd.getUpdateInSequence();
         boolean forced = cmd.getForced();
+        String ip4Dns1 = cmd.getIp4Dns1();
+        String ip4Dns2 = cmd.getIp4Dns2();
+        String ip6Dns1 = cmd.getIp6Dns1();
+        String ip6Dns2 = cmd.getIp6Dns2();
 
         boolean restartNetwork = false;
 
@@ -2715,6 +2790,11 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
             }
         }
 
+        if (checkAndUpdateNetworkDns(network, networkOfferingChanged ? networkOffering : oldNtwkOff, ip4Dns1, ip4Dns2,
+                ip6Dns1, ip6Dns2)) {
+            restartNetwork = true;
+        }
+
         final Map<String, String> newSvcProviders = networkOfferingChanged
                 ? _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), network.getPhysicalNetworkId())
                         : new HashMap<String, String>();
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 5629eb2d1c..7d7fb1564e 100644
--- a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java
+++ b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java
@@ -20,9 +20,9 @@ import java.util.List;
 
 import javax.inject.Inject;
 
-import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.dc.DataCenter;
@@ -36,8 +36,6 @@ import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.network.dao.PhysicalNetworkDao;
-import com.cloud.network.dao.PhysicalNetworkVO;
 import com.cloud.network.IpAddressManager;
 import com.cloud.network.Network;
 import com.cloud.network.Network.GuestType;
@@ -54,8 +52,12 @@ import com.cloud.network.PhysicalNetwork.IsolationMethod;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkVO;
 import com.cloud.offering.NetworkOffering;
+import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import com.cloud.user.Account;
+import com.cloud.utils.Pair;
 import com.cloud.utils.component.AdapterBase;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Transaction;
@@ -217,6 +219,19 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru {
             if (userSpecified.getRouterIpv6() != null) {
                 config.setRouterIpv6(userSpecified.getRouterIpv6());
             }
+
+            if (StringUtils.isNotBlank(userSpecified.getDns1())) {
+                config.setDns1(userSpecified.getDns1());
+            }
+            if (StringUtils.isNotBlank(userSpecified.getDns2())) {
+                config.setDns2(userSpecified.getDns2());
+            }
+            if (StringUtils.isNotBlank(userSpecified.getIp6Dns1())) {
+                config.setIp6Dns1(userSpecified.getIp6Dns1());
+            }
+            if (StringUtils.isNotBlank(userSpecified.getIp6Dns2())) {
+                config.setIp6Dns2(userSpecified.getIp6Dns2());
+            }
         }
 
         boolean isSecurityGroupEnabled = _networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Service.SecurityGroup);
@@ -240,11 +255,13 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru {
     @Override
     public void updateNicProfile(NicProfile profile, Network network) {
         DataCenter dc = _dcDao.findById(network.getDataCenterId());
+        Pair<String, String> ip4Dns = _networkModel.getNetworkIp4Dns(network, dc);
+        Pair<String, String> ip6Dns = _networkModel.getNetworkIp6Dns(network, dc);
         if (profile != null) {
-            profile.setIPv4Dns1(dc.getDns1());
-            profile.setIPv4Dns2(dc.getDns2());
-            profile.setIPv6Dns1(dc.getIp6Dns1());
-            profile.setIPv6Dns2(dc.getIp6Dns2());
+            profile.setIPv4Dns1(ip4Dns.first());
+            profile.setIPv4Dns2(ip4Dns.second());
+            profile.setIPv6Dns1(ip6Dns.first());
+            profile.setIPv6Dns2(ip6Dns.second());
         }
     }
 
@@ -413,7 +430,12 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru {
     @Override
     public void updateNetworkProfile(NetworkProfile networkProfile) {
         DataCenter dc = _dcDao.findById(networkProfile.getDataCenterId());
-        networkProfile.setDns1(dc.getDns1());
-        networkProfile.setDns2(dc.getDns2());
+        Network network = _networkModel.getNetwork(networkProfile.getId());
+        Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
+        networkProfile.setDns1(dns.first());
+        networkProfile.setDns2(dns.second());
+        dns = _networkModel.getNetworkIp6Dns(network, dc);
+        networkProfile.setIp6Dns1(dns.first());
+        networkProfile.setIp6Dns2(dns.second());
     }
 }
diff --git a/server/src/main/java/com/cloud/network/guru/DirectPodBasedNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
index 01b33893b5..f0ddc128b9 100644
--- a/server/src/main/java/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
+++ b/server/src/main/java/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
@@ -50,6 +50,7 @@ import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.utils.Pair;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Transaction;
 import com.cloud.utils.db.TransactionCallbackNoReturn;
@@ -157,8 +158,9 @@ public class DirectPodBasedNetworkGuru extends DirectNetworkGuru {
         }
 
         DataCenter dc = _dcDao.findById(network.getDataCenterId());
-        nic.setIPv4Dns1(dc.getDns1());
-        nic.setIPv4Dns2(dc.getDns2());
+        Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
+        nic.setIPv4Dns1(dns.first());
+        nic.setIPv4Dns2(dns.second());
     }
 
     @DB
@@ -240,8 +242,9 @@ public class DirectPodBasedNetworkGuru extends DirectNetworkGuru {
             }
         });
 
-        nic.setIPv4Dns1(dc.getDns1());
-        nic.setIPv4Dns2(dc.getDns2());
+        Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
+        nic.setIPv4Dns1(dns.first());
+        nic.setIPv4Dns2(dns.second());
     }
 
 }
diff --git a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java
index 6524abe1e4..2f7051154c 100644
--- a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java
+++ b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java
@@ -59,6 +59,7 @@ import com.cloud.network.rules.PortForwardingRuleVO;
 import com.cloud.network.rules.dao.PortForwardingRulesDao;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.user.Account;
+import com.cloud.utils.Pair;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.Ip;
@@ -321,8 +322,9 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru {
         if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId())) {
             nic.setBroadcastUri(config.getBroadcastUri());
             nic.setIsolationUri(config.getBroadcastUri());
-            nic.setIPv4Dns1(dc.getDns1());
-            nic.setIPv4Dns2(dc.getDns2());
+            Pair<String, String> dns = _networkModel.getNetworkIp4Dns(config, dc);
+            nic.setIPv4Dns1(dns.first());
+            nic.setIPv4Dns2(dns.second());
             nic.setIPv4Netmask(NetUtils.cidr2Netmask(config.getCidr()));
             long cidrAddress = NetUtils.ip2Long(config.getCidr().split("/")[0]);
             int cidrSize = getGloballyConfiguredCidrSize();
diff --git a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java
index be3d57eb48..47d90aa881 100644
--- a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java
+++ b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java
@@ -28,6 +28,7 @@ import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationSe
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.configuration.Config;
@@ -258,6 +259,19 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur
                     network.setPvlanType(userSpecified.getPvlanType());
                 }
             }
+
+            if (StringUtils.isNotBlank(userSpecified.getDns1())) {
+                network.setDns1(userSpecified.getDns1());
+            }
+            if (StringUtils.isNotBlank(userSpecified.getDns2())) {
+                network.setDns2(userSpecified.getDns2());
+            }
+            if (StringUtils.isNotBlank(userSpecified.getIp6Dns1())) {
+                network.setIp6Dns1(userSpecified.getIp6Dns1());
+            }
+            if (StringUtils.isNotBlank(userSpecified.getIp6Dns2())) {
+                network.setIp6Dns2(userSpecified.getIp6Dns2());
+            }
         } else {
             final String guestNetworkCidr = dc.getGuestNetworkCidr();
             if (guestNetworkCidr == null && dc.getNetworkType() == NetworkType.Advanced) {
@@ -437,8 +451,9 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur
                     nic.setIPv4Netmask(NetUtils.cidr2Netmask(_networkModel.getValidNetworkCidr(network)));
                 }
 
-                nic.setIPv4Dns1(dc.getDns1());
-                nic.setIPv4Dns2(dc.getDns2());
+                Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
+                nic.setIPv4Dns1(dns.first());
+                nic.setIPv4Dns2(dns.second());
                 nic.setFormat(AddressFormat.Ip4);
             }
         }
@@ -458,9 +473,13 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur
     @Override
     public void updateNicProfile(final NicProfile profile, final Network network) {
         final DataCenter dc = _dcDao.findById(network.getDataCenterId());
+        Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
+        Pair<String, String> ip6Dns = _networkModel.getNetworkIp6Dns(network, dc);
         if (profile != null) {
-            profile.setIPv4Dns1(dc.getDns1());
-            profile.setIPv4Dns2(dc.getDns2());
+            profile.setIPv4Dns1(dns.first());
+            profile.setIPv4Dns2(dns.second());
+            profile.setIPv6Dns1(ip6Dns.first());
+            profile.setIPv6Dns2(ip6Dns.second());
         }
     }
 
@@ -506,8 +525,13 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur
     @Override
     public void updateNetworkProfile(final NetworkProfile networkProfile) {
         final DataCenter dc = _dcDao.findById(networkProfile.getDataCenterId());
-        networkProfile.setDns1(dc.getDns1());
-        networkProfile.setDns2(dc.getDns2());
+        Network network = _networkModel.getNetwork(networkProfile.getId());
+        Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
+        networkProfile.setDns1(dns.first());
+        networkProfile.setDns2(dns.second());
+        dns = _networkModel.getNetworkIp6Dns(network, dc);
+        networkProfile.setIp6Dns1(dns.first());
+        networkProfile.setIp6Dns2(dns.second());
     }
 
     @Override
diff --git a/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java
index 6e2f1db5f2..a5eac9aac1 100644
--- a/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java
+++ b/server/src/main/java/com/cloud/network/guru/PrivateNetworkGuru.java
@@ -44,6 +44,7 @@ import com.cloud.network.vpc.PrivateIpVO;
 import com.cloud.network.vpc.dao.PrivateIpDao;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.user.Account;
+import com.cloud.utils.Pair;
 import com.cloud.utils.component.AdapterBase;
 import com.cloud.utils.db.EntityManager;
 import com.cloud.utils.exception.CloudRuntimeException;
@@ -60,7 +61,7 @@ public class PrivateNetworkGuru extends AdapterBase implements NetworkGuru {
     @Inject
     protected PrivateIpDao _privateIpDao;
     @Inject
-    protected NetworkModel _networkMgr;
+    protected NetworkModel networkModel;
     @Inject
     EntityManager _entityMgr;
 
@@ -199,16 +200,22 @@ public class PrivateNetworkGuru extends AdapterBase implements NetworkGuru {
             nic.setMacAddress(ip.getMacAddress());
         }
 
-        nic.setIPv4Dns1(dc.getDns1());
-        nic.setIPv4Dns2(dc.getDns2());
+
+        Pair<String, String> dns = networkModel.getNetworkIp4Dns(network, dc);
+        nic.setIPv4Dns1(dns.first());
+        nic.setIPv4Dns2(dns.second());
     }
 
     @Override
     public void updateNicProfile(NicProfile profile, Network network) {
         DataCenter dc = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
+        Pair<String, String> dns = networkModel.getNetworkIp4Dns(network, dc);
+        Pair<String, String> ip6Dns = networkModel.getNetworkIp6Dns(network, dc);
         if (profile != null) {
-            profile.setIPv4Dns1(dc.getDns1());
-            profile.setIPv4Dns2(dc.getDns2());
+            profile.setIPv4Dns1(dns.first());
+            profile.setIPv4Dns2(dns.second());
+            profile.setIPv6Dns1(ip6Dns.first());
+            profile.setIPv6Dns2(ip6Dns.second());
         }
     }
 
@@ -239,7 +246,12 @@ public class PrivateNetworkGuru extends AdapterBase implements NetworkGuru {
     @Override
     public void updateNetworkProfile(NetworkProfile networkProfile) {
         DataCenter dc = _entityMgr.findById(DataCenter.class, networkProfile.getDataCenterId());
-        networkProfile.setDns1(dc.getDns1());
-        networkProfile.setDns2(dc.getDns2());
+        Network network = networkModel.getNetwork(networkProfile.getId());
+        Pair<String, String> dns = networkModel.getNetworkIp4Dns(network, dc);
+        networkProfile.setDns1(dns.first());
+        networkProfile.setDns2(dns.second());
+        dns = networkModel.getNetworkIp6Dns(network, dc);
+        networkProfile.setIp6Dns1(dns.first());
+        networkProfile.setIp6Dns2(dns.second());
     }
 }
diff --git a/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java
index c3f7ee3d94..e8374b39f5 100644
--- a/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java
+++ b/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java
@@ -34,6 +34,7 @@ import com.cloud.network.IpAddressManager;
 import com.cloud.network.Ipv6Service;
 import com.cloud.network.Network;
 import com.cloud.network.Network.State;
+import com.cloud.network.NetworkModel;
 import com.cloud.network.NetworkProfile;
 import com.cloud.network.Networks.AddressFormat;
 import com.cloud.network.Networks.BroadcastDomainType;
@@ -46,6 +47,7 @@ import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.user.Account;
+import com.cloud.utils.Pair;
 import com.cloud.utils.component.AdapterBase;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Transaction;
@@ -73,6 +75,8 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru {
     IpAddressManager _ipAddrMgr;
     @Inject
     Ipv6Service ipv6Service;
+    @Inject
+    NetworkModel networkModel;
 
     private static final TrafficType[] TrafficTypes = {TrafficType.Public};
 
@@ -140,8 +144,9 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru {
             nic.setMacAddress(ip.getMacAddress());
         }
 
-        nic.setIPv4Dns1(dc.getDns1());
-        nic.setIPv4Dns2(dc.getDns2());
+        Pair<String, String> dns = networkModel.getNetworkIp4Dns(network, dc);
+        nic.setIPv4Dns1(dns.first());
+        nic.setIPv4Dns2(dns.second());
 
         ipv6Service.updateNicIpv6(nic, dc, network);
     }
@@ -149,9 +154,13 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru {
     @Override
     public void updateNicProfile(NicProfile profile, Network network) {
         DataCenter dc = _dcDao.findById(network.getDataCenterId());
+        Pair<String, String> dns = networkModel.getNetworkIp4Dns(network, dc);
+        Pair<String, String> ip6Dns = networkModel.getNetworkIp6Dns(network, dc);
         if (profile != null) {
-            profile.setIPv4Dns1(dc.getDns1());
-            profile.setIPv4Dns2(dc.getDns2());
+            profile.setIPv4Dns1(dns.first());
+            profile.setIPv4Dns2(dns.second());
+            profile.setIPv6Dns1(ip6Dns.first());
+            profile.setIPv6Dns2(ip6Dns.second());
         }
     }
 
@@ -237,8 +246,13 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru {
     @Override
     public void updateNetworkProfile(NetworkProfile networkProfile) {
         DataCenter dc = _dcDao.findById(networkProfile.getDataCenterId());
-        networkProfile.setDns1(dc.getDns1());
-        networkProfile.setDns2(dc.getDns2());
+        Network network = networkModel.getNetwork(networkProfile.getId());
+        Pair<String, String> dns = networkModel.getNetworkIp4Dns(network, dc);
+        networkProfile.setDns1(dns.first());
+        networkProfile.setDns2(dns.second());
+        dns = networkModel.getNetworkIp6Dns(network, dc);
+        networkProfile.setIp6Dns1(dns.first());
+        networkProfile.setIp6Dns2(dns.second());
     }
 
 }
diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java
index 6839a6ae13..517b65b83e 100644
--- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java
+++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java
@@ -1116,18 +1116,20 @@ public class CommandSetupHelper {
 
         if (setupDns) {
             final DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId());
-            if (guestNic.getIPv4Dns1() != null) {
-                defaultDns1 = guestNic.getIPv4Dns1();
-            } else {
-                defaultDns1 = dcVo.getDns1();
+            defaultDns1 = guestNic.getIPv4Dns1();
+            defaultDns2 = guestNic.getIPv4Dns2();
+            if (org.apache.commons.lang3.StringUtils.isAllBlank(guestNic.getIPv4Dns1(), guestNic.getIPv4Dns2())) {
+                Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dcVo);
+                defaultDns1 = dns.first();
+                defaultDns2 = dns.second();
             }
-            if (guestNic.getIPv4Dns2() != null) {
-                defaultDns2 = guestNic.getIPv4Dns2();
-            } else {
-                defaultDns2 = dcVo.getDns2();
+            defaultIp6Dns1 = guestNic.getIPv6Dns1();
+            defaultIp6Dns2 = guestNic.getIPv6Dns2();
+            if (org.apache.commons.lang3.StringUtils.isAllBlank(guestNic.getIPv6Dns1(), guestNic.getIPv6Dns2())) {
+                Pair<String, String> dns = _networkModel.getNetworkIp6Dns(network, dcVo);
+                defaultIp6Dns1 = dns.first();
+                defaultIp6Dns2 = dns.second();
             }
-            defaultIp6Dns1 = dcVo.getIp6Dns1();
-            defaultIp6Dns2 = dcVo.getIp6Dns2();
         }
 
         final Nic nic = _nicDao.findByNtwkIdAndInstanceId(network.getId(), router.getId());
diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
index 5ce4362908..c8daff60ba 100644
--- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
@@ -1984,8 +1984,8 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
                     buf.append(" gateway=").append(nic.getIPv4Gateway());
                 }
                 if (ipv6) {
-                    defaultIp6Dns1 = nic.getIPv6Dns1() != null? nic.getIPv6Dns1() : dc.getIp6Dns1();
-                    defaultIp6Dns2 = nic.getIPv6Dns2() != null? nic.getIPv6Dns2() : dc.getIp6Dns2();
+                    defaultIp6Dns1 = nic.getIPv6Dns1();
+                    defaultIp6Dns2 = nic.getIPv6Dns2();
                     buf.append(" ip6gateway=").append(nic.getIPv6Gateway());
                 }
                 defaultDns1 = nic.getIPv4Dns1();
diff --git a/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
index 1d1b9494d7..ad20fb9a3a 100644
--- a/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
@@ -252,6 +252,8 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
             if (domainRouterVO.getState() == State.Starting || domainRouterVO.getState() == State.Running) {
                 String defaultDns1 = null;
                 String defaultDns2 = null;
+                String defaultIp6Dns1 = null;
+                String defaultIp6Dns2 = null;
                 // remove public and guest nics as we will plug them later
                 final Iterator<NicProfile> it = profile.getNics().iterator();
                 while (it.hasNext()) {
@@ -261,6 +263,8 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
                         if (nic.getTrafficType() == TrafficType.Public) {
                             defaultDns1 = nic.getIPv4Dns1();
                             defaultDns2 = nic.getIPv4Dns2();
+                            defaultIp6Dns1 = nic.getIPv6Dns1();
+                            defaultIp6Dns2 = nic.getIPv6Dns2();
                         }
                         s_logger.debug("Removing nic " + nic + " of type " + nic.getTrafficType() + " from the nics passed on vm start. " + "The nic will be plugged later");
                         it.remove();
@@ -276,6 +280,12 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
                 if (defaultDns2 != null) {
                     buf.append(" dns2=").append(defaultDns2);
                 }
+                if (defaultIp6Dns1 != null) {
+                    buf.append(" ip6dns1=").append(defaultIp6Dns1);
+                }
+                if (defaultIp6Dns2 != null) {
+                    buf.append(" ip6dns2=").append(defaultIp6Dns2);
+                }
             }
         }
 
diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
index 781ee38c8a..1c4911d9d3 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -47,6 +47,7 @@ import org.apache.cloudstack.api.command.admin.vpc.CreatePrivateGatewayByAdminCm
 import org.apache.cloudstack.api.command.admin.vpc.CreateVPCOfferingCmd;
 import org.apache.cloudstack.api.command.admin.vpc.UpdateVPCOfferingCmd;
 import org.apache.cloudstack.api.command.user.vpc.CreatePrivateGatewayCmd;
+import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd;
 import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd;
 import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd;
 import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd;
@@ -57,6 +58,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.query.QueryService;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.ObjectUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.api.query.dao.VpcOfferingJoinDao;
@@ -261,6 +263,17 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
         hTypes.add(HypervisorType.Ovm3);
     }
 
+    private void checkVpcDns(VpcOffering vpcOffering, String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2) {
+        if (ObjectUtils.anyNotNull(ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2) && !areServicesSupportedByVpcOffering(vpcOffering.getId(), Service.Dns)) {
+            throw new InvalidParameterValueException("DNS can not be specified for VPCs with offering that do not support DNS service");
+        }
+        if (!_vpcOffDao.isIpv6Supported(vpcOffering.getId()) && !org.apache.commons.lang3.StringUtils.isAllBlank(ip6Dns1, ip6Dns2)) {
+            throw new InvalidParameterValueException("IPv6 DNS can be specified for IPv6 enabled VPC");
+        }
+        _ntwkModel.verifyIp4DnsPair(ip4Dns1, ip4Dns2);
+        _ntwkModel.verifyIp6DnsPair(ip6Dns1, ip6Dns2);
+    }
+
     @Override
     @DB
     public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
@@ -788,7 +801,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
     }
 
     protected boolean areServicesSupportedByVpcOffering(final long vpcOffId, final Service... services) {
-        return _vpcOffSvcMapDao.areServicesSupportedByNetworkOffering(vpcOffId, services);
+        return _vpcOffSvcMapDao.areServicesSupportedByVpcOffering(vpcOffId, services);
     }
 
     @Override
@@ -969,7 +982,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true)
     public Vpc createVpc(final long zoneId, final long vpcOffId, final long vpcOwnerId, final String vpcName, final String displayText, final String cidr, String networkDomain,
-            final Boolean displayVpc) throws ResourceAllocationException {
+            final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, final Boolean displayVpc) throws ResourceAllocationException {
         final Account caller = CallContext.current().getCallingAccount();
         final Account owner = _accountMgr.getAccount(vpcOwnerId);
 
@@ -979,9 +992,15 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
         // check resource limit
         _resourceLimitMgr.checkResourceLimit(owner, ResourceType.vpc);
 
+        // Validate zone
+        final DataCenter zone = _dcDao.findById(zoneId);
+        if (zone == null) {
+            throw new InvalidParameterValueException("Can't find zone by id specified");
+        }
+
         // Validate vpc offering
         final VpcOfferingVO vpcOff = _vpcOffDao.findById(vpcOffId);
-        _accountMgr.checkAccess(owner, vpcOff, _dcDao.findById(zoneId));
+        _accountMgr.checkAccess(owner, vpcOff, zone);
         if (vpcOff == null || vpcOff.getState() != State.Enabled) {
             final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find vpc offering in " + State.Enabled + " state by specified id");
             if (vpcOff == null) {
@@ -997,12 +1016,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
             throw new InvalidParameterValueException("Network domain must be specified for region level VPC");
         }
 
-        // Validate zone
-        final DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId);
-        if (zone == null) {
-            throw new InvalidParameterValueException("Can't find zone by id specified");
-        }
-
         if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) {
             // See DataCenterVO.java
             final PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled");
@@ -1021,13 +1034,23 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
             }
         }
 
+        checkVpcDns(vpcOff, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
+
         final boolean useDistributedRouter = vpcOff.isSupportsDistributedRouter();
         final VpcVO vpc = new VpcVO(zoneId, vpcName, displayText, owner.getId(), owner.getDomainId(), vpcOffId, cidr, networkDomain, useDistributedRouter, isRegionLevelVpcOff,
-                vpcOff.isRedundantRouter());
+                vpcOff.isRedundantRouter(), ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
 
         return createVpc(displayVpc, vpc);
     }
 
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true)
+    public Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException {
+        return createVpc(cmd.getZoneId(), cmd.getVpcOffering(), cmd.getEntityOwnerId(), cmd.getVpcName(), cmd.getDisplayText(),
+            cmd.getCidr(), cmd.getNetworkDomain(), cmd.getIp4Dns1(), cmd.getIp4Dns2(), cmd.getIp6Dns1(),
+            cmd.getIp6Dns2(), cmd.isDisplay());
+    }
+
     @DB
     protected Vpc createVpc(final Boolean displayVpc, final VpcVO vpc) {
         final String cidr = vpc.getCidr();
@@ -2687,7 +2710,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
     @Override
     public Network createVpcGuestNetwork(final long ntwkOffId, final String name, final String displayText, final String gateway, final String cidr, final String vlanId,
             String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk, final long zoneId, final ACLType aclType, final Boolean subdomainAccess,
-            final long vpcId, final Long aclId, final Account caller, final Boolean isDisplayNetworkEnabled, String externalId, String ip6Gateway, String ip6Cidr) throws ConcurrentOperationException, InsufficientCapacityException,
+            final long vpcId, final Long aclId, final Account caller, final Boolean isDisplayNetworkEnabled, String externalId, String ip6Gateway, String ip6Cidr, final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2) throws ConcurrentOperationException, InsufficientCapacityException,
             ResourceAllocationException {
 
         final Vpc vpc = getActiveVpc(vpcId);
@@ -2712,7 +2735,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
 
         // 2) Create network
         final Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId, false, networkDomain, owner, domainId, pNtwk, zoneId, aclType,
-                                                                 subdomainAccess, vpcId, ip6Gateway, ip6Cidr, isDisplayNetworkEnabled, null, null, externalId, null, null);
+                                                                 subdomainAccess, vpcId, ip6Gateway, ip6Cidr, isDisplayNetworkEnabled, null, null, externalId, null, null, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
 
         if (guestNetwork != null) {
             guestNetwork.setNetworkACLId(aclId);
diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index 11741a4e49..608448c8e4 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -3752,7 +3752,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
         s_logger.debug("Creating network for account " + owner + " from the network offering id=" + requiredOfferings.get(0).getId() + " as a part of deployVM process");
         Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName() + "-network",
                 null, null, null, false, null, owner, null, physicalNetwork, zone.getId(), ACLType.Account, null, null, null, null, true, null, null,
-                null, null, null);
+                null, null, null, null, null, null, null);
         if (newNetwork != null) {
             defaultNetwork = _networkDao.findById(newNetwork.getId());
         }
@@ -7277,7 +7277,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
                             Network newNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), newAccount.getAccountName() + "-network",
                                     newAccount.getAccountName() + "-network", null, null, null, false, null, newAccount,
                                     null, physicalNetwork, zone.getId(), ACLType.Account, null, null,
-                                    null, null, true, null, null, null, null, null);
+                                    null, null, true, null, null, null, null, null, null, null, null, null);
                             // if the network offering has persistent set to true, implement the network
                             if (requiredOfferings.get(0).isPersistent()) {
                                 DeployDestination dest = new DeployDestination(zone, null, null, null);
diff --git a/server/src/test/java/com/cloud/network/CreatePrivateNetworkTest.java b/server/src/test/java/com/cloud/network/CreatePrivateNetworkTest.java
index 7a0ea2e972..93a1d30d17 100644
--- a/server/src/test/java/com/cloud/network/CreatePrivateNetworkTest.java
+++ b/server/src/test/java/com/cloud/network/CreatePrivateNetworkTest.java
@@ -129,7 +129,7 @@ public class CreatePrivateNetworkTest {
                 ACLType.Account, false, 1L, false);
         when(networkService._networkMgr.createGuestNetwork(eq(ntwkOff.getId()), eq("bla"), eq("fake"), eq("10.1.1.1"), eq("10.1.1.0/24"), nullable(String.class), nullable(Boolean.class), nullable(String.class),
                         eq(account), nullable(Long.class), eq(physicalNetwork), eq(physicalNetwork.getDataCenterId()), eq(ACLType.Account), nullable(Boolean.class), eq(1L), nullable(String.class), nullable(String.class),
-                        nullable(Boolean.class), nullable(String.class), nullable(Network.PVlanType.class), nullable(String.class), nullable(String.class), nullable(String.class))).thenReturn(net);
+                        nullable(Boolean.class), nullable(String.class), nullable(Network.PVlanType.class), nullable(String.class), nullable(String.class), nullable(String.class), nullable(String.class), nullable(String.class), nullable(String.class), nullable(String.class))).thenReturn(net);
         when(
             networkService._networkMgr.createPrivateNetwork(eq(ntwkOff.getId()), eq("bla"), eq("fake"), eq("10.1.1.1"), eq("10.1.1.0/24"), anyString(), anyBoolean(), eq(account), eq(physicalNetwork), eq(1L))).thenReturn(net);
 
diff --git a/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java b/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java
index bd1484d588..17676956a8 100644
--- a/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java
+++ b/server/src/test/java/com/cloud/network/Ipv6AddressManagerTest.java
@@ -19,8 +19,6 @@ package com.cloud.network;
 
 import static org.mockito.Mockito.mock;
 
-import com.cloud.dc.DataCenter;
-import com.cloud.vm.NicProfile;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -28,6 +26,7 @@ import org.mockito.InjectMocks;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import com.cloud.dc.DataCenter;
 import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.network.IpAddress.State;
@@ -36,7 +35,9 @@ 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.Pair;
 import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.NicProfile;
 import com.cloud.vm.dao.NicSecondaryIpDaoImpl;
 import com.cloud.vm.dao.NicSecondaryIpVO;
 
@@ -239,8 +240,7 @@ public class Ipv6AddressManagerTest {
         Mockito.when(network.getIp6Cidr()).thenReturn("2001:db8:100::/64");
         Mockito.when(network.getIp6Gateway()).thenReturn("2001:db8:100::1");
 
-        Mockito.when(dc.getIp6Dns1()).thenReturn("2001:db8::53:1");
-        Mockito.when(dc.getIp6Dns1()).thenReturn("2001:db8::53:2");
+        Mockito.when(networkModel.getNetworkIp6Dns(network, dc)).thenReturn(new Pair<>("2001:db8::53:1", "2001:db8::53:2"));
 
         String expected = "2001:db8:100:0:1c00:b1ff:fe00:af6";
 
diff --git a/server/src/test/java/com/cloud/network/Ipv6ServiceImplTest.java b/server/src/test/java/com/cloud/network/Ipv6ServiceImplTest.java
index 1b0592abcb..3b55717d20 100644
--- a/server/src/test/java/com/cloud/network/Ipv6ServiceImplTest.java
+++ b/server/src/test/java/com/cloud/network/Ipv6ServiceImplTest.java
@@ -120,13 +120,11 @@ public class Ipv6ServiceImplTest {
     DomainRouterDao domainRouterDao;
     @Mock
     AccountManager accountManager;
-    @Mock
     NetworkModel networkModel = Mockito.mock(NetworkModelImpl.class);
     @Mock
     IPAddressDao ipAddressDao;
     @Mock
     NetworkOrchestrationService networkOrchestrationService;
-
     FirewallManager firewallManager = Mockito.mock(FirewallManager.class);
 
     @InjectMocks
@@ -145,6 +143,7 @@ public class Ipv6ServiceImplTest {
     final String gateway = "fd17:5:8a43:e2a5::1";
     final String macAddress = "1e:00:4c:00:00:03";
     final String ipv6Address = "fd17:5:8a43:e2a5:1c00:4cff:fe00:3"; // Resulting  IPv6 address using SLAAC
+    final Pair<String, String> ipv6DnsPair = new Pair<>("2001:db8::53:1", "2001:db8::53:2");
     public static final long ACCOUNT_ID = 1;
 
     private AccountVO account;
@@ -485,6 +484,7 @@ public class Ipv6ServiceImplTest {
     @Test
     public void testIpv6NetworkUpdateNicIpv6() {
         Mockito.when(networkOfferingDao.isIpv6Supported(Mockito.anyLong())).thenReturn(true);
+        Mockito.when(networkModel.getNetworkIp6Dns(Mockito.any(Network.class), Mockito.any(DataCenter.class))).thenReturn(ipv6DnsPair);
         NicProfile nicProfile = new NicProfile();
         nicProfile.setBroadcastUri(URI.create(vlan));
         nicProfile.setMacAddress(macAddress);
@@ -502,6 +502,7 @@ public class Ipv6ServiceImplTest {
     @Test
     public void testIpv6NetworkFromPlaceholderUpdateNicIpv6() {
         Mockito.when(networkOfferingDao.isIpv6Supported(Mockito.anyLong())).thenReturn(true);
+        Mockito.when(networkModel.getNetworkIp6Dns(Mockito.any(Network.class), Mockito.any(DataCenter.class))).thenReturn(ipv6DnsPair);
         NicProfile nicProfile = new NicProfile();
         nicProfile.setBroadcastUri(URI.create(vlan));
         nicProfile.setMacAddress(macAddress);
diff --git a/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java b/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
index e9c9db3cba..6f437b8be5 100644
--- a/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
+++ b/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java
@@ -24,6 +24,7 @@ import java.util.Set;
 
 import javax.naming.ConfigurationException;
 
+import com.cloud.dc.DataCenter;
 import com.cloud.dc.Vlan;
 import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
@@ -44,6 +45,7 @@ import com.cloud.offering.NetworkOffering;
 import com.cloud.offering.NetworkOffering.Detail;
 import com.cloud.offerings.NetworkOfferingVO;
 import com.cloud.user.Account;
+import com.cloud.utils.Pair;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.vm.Nic;
 import com.cloud.vm.NicProfile;
@@ -918,4 +920,19 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel {
         return null;
     }
 
+    @Override
+    public Pair<String, String> getNetworkIp4Dns(Network network, DataCenter zone) {
+        return new Pair<>(null, null);
+    }
+
+    @Override
+    public Pair<String, String> getNetworkIp6Dns(Network network, DataCenter zone) {
+        return new Pair<>(null, null);
+    }
+
+    @Override
+    public void verifyIp4DnsPair(String ip4Dns1, String ip4Dns2) {}
+
+    @Override
+    public void verifyIp6DnsPair(String ip4Dns1, String ip4Dns2) {}
 }
diff --git a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java
new file mode 100644
index 0000000000..76d049b886
--- /dev/null
+++ b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java
@@ -0,0 +1,144 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.utils.Pair;
+
+public class NetworkModelImplTest {
+    final String[] ip4Dns1 = {"5.5.5.5", "6.6.6.6"};
+    final String[] ip4Dns2 = {"7.7.7.7", "8.8.8.8"};
+    final String[] ip6Dns1 = {"2001:4860:4860::5555", "2001:4860:4860::6666"};
+    final String[] ip6Dns2 = {"2001:4860:4860::7777", "2001:4860:4860::8888"};
+
+    @InjectMocks
+    private NetworkModelImpl networkModel = new NetworkModelImpl();
+
+    private void prepareMocks(boolean isIp6, Network network, DataCenter zone,
+                              String dns1, String dns2, String dns3, String dns4) {
+        if (isIp6) {
+            Mockito.when(network.getIp6Dns1()).thenReturn(dns1);
+            Mockito.when(zone.getIp6Dns1()).thenReturn(dns2);
+            Mockito.when(network.getIp6Dns2()).thenReturn(dns3);
+            Mockito.when(zone.getIp6Dns2()).thenReturn(dns4);
+        } else {
+            Mockito.when(network.getDns1()).thenReturn(dns1);
+            Mockito.when(zone.getDns1()).thenReturn(dns2);
+            Mockito.when(network.getDns2()).thenReturn(dns3);
+            Mockito.when(zone.getDns2()).thenReturn(dns4);
+        }
+    }
+
+    private void testDnsCases(boolean isIp6) {
+        String[] dns1 = isIp6 ? ip6Dns1 : ip4Dns1;
+        String[] dns2 = isIp6 ? ip6Dns2 : ip4Dns2;
+        Network network = Mockito.mock(Network.class);
+        DataCenter zone = Mockito.mock(DataCenter.class);
+        // Both network and zone have valid dns
+        prepareMocks(isIp6, network, zone, dns1[0], dns1[1], dns2[0], dns1[1]);
+        Pair<String, String> result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) :
+                networkModel.getNetworkIp4Dns(network, zone);
+        Assert.assertEquals(dns1[0], result.first());
+        Assert.assertEquals(dns2[0], result.second());
+        // Network has valid dns and zone don't
+        prepareMocks(isIp6, network, zone, dns1[0], null, dns2[0], null);
+        result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) :
+                networkModel.getNetworkIp4Dns(network, zone);
+        Assert.assertEquals(dns1[0], result.first());
+        Assert.assertEquals(dns2[0], result.second());
+        // Zone has a valid dns and network don't
+        prepareMocks(isIp6, network, zone, null, dns1[1],  null, dns2[1]);
+        result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) :
+                networkModel.getNetworkIp4Dns(network, zone);
+        Assert.assertEquals(dns1[1], result.first());
+        Assert.assertEquals(dns2[1], result.second());
+        // Zone has a valid dns and network has only first dns
+        prepareMocks(isIp6, network, zone, dns1[0], dns1[1],  null, dns2[1]);
+        result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) :
+                networkModel.getNetworkIp4Dns(network, zone);
+        Assert.assertEquals(dns1[0], result.first());
+        Assert.assertNull(result.second());
+        // Both network and zone only have the first dns
+        prepareMocks(isIp6, network, zone, dns1[0], dns1[1],  null, null);
+        result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) :
+                networkModel.getNetworkIp4Dns(network, zone);
+        Assert.assertEquals(dns1[0], result.first());
+        Assert.assertNull(result.second());
+        // Both network and zone dns are null
+        prepareMocks(isIp6, network, zone, null, null,  null, null);
+        result = isIp6 ? networkModel.getNetworkIp6Dns(network, zone) :
+                networkModel.getNetworkIp4Dns(network, zone);
+        Assert.assertNull(result.first());
+        Assert.assertNull(result.second());
+    }
+
+    @Test
+    public void testGetNetworkIp4Dns() {
+        testDnsCases(false);
+    }
+
+    @Test
+    public void testGetNetworkIp6Dns() {
+        testDnsCases(true);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testVerifyIp4DnsPairDns1NullFailure() {
+        networkModel.verifyIp4DnsPair(null, ip4Dns1[1]);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testVerifyIp4DnsPairInvalidDns1Failure() {
+        networkModel.verifyIp4DnsPair("invalid", ip4Dns1[1]);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testVerifyIp4DnsPairInvalidDns2Failure() {
+        networkModel.verifyIp4DnsPair(ip4Dns1[0], "invalid");
+    }
+
+    @Test
+    public void testVerifyIp4DnsPairValid() {
+        networkModel.verifyIp4DnsPair(ip4Dns1[0], ip4Dns1[1]);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testVerifyIp6DnsPairDns1NullFailure() {
+        networkModel.verifyIp6DnsPair(null, ip6Dns1[1]);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testVerifyIp6DnsPairInvalidDns1Failure() {
+        networkModel.verifyIp6DnsPair("invalid", ip6Dns1[1]);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testVerifyIp6DnsPairInvalidDns2Failure() {
+        networkModel.verifyIp6DnsPair(ip6Dns1[0], "invalid");
+    }
+
+    @Test
+    public void testVerifyIp6DnsPairValid() {
+        networkModel.verifyIp6DnsPair(ip6Dns1[0], ip6Dns1[1]);
+    }
+}
\ No newline at end of file
diff --git a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
index 2520f3902b..30def99f16 100644
--- a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
+++ b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
@@ -16,18 +16,89 @@
 // under the License.
 package com.cloud.network;
 
-import com.cloud.utils.Pair;
-import com.cloud.utils.exception.CloudRuntimeException;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.UUID;
+
+import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.junit.Assert;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkVO;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offerings.NetworkOfferingVO;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.User;
+import com.cloud.user.UserVO;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.ComponentContext;
+import com.cloud.utils.exception.CloudRuntimeException;
 
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(ComponentContext.class)
 public class NetworkServiceImplTest {
+    @Mock
+    AccountManager accountManager;
+    @Mock
+    NetworkOfferingDao networkOfferingDao;
+    @Mock
+    PhysicalNetworkDao physicalNetworkDao;
+    @Mock
+    DataCenterDao dataCenterDao;
+    @Mock
+    NetworkOrchestrationService networkOrchestrationService;
+    @Mock
+    Ipv6Service ipv6Service;
+    @Mock
+    NetworkModel networkModel;
+    @Mock
+    NetworkOfferingServiceMapDao networkOfferingServiceMapDao;
 
+    @InjectMocks
     private NetworkServiceImpl service = new NetworkServiceImpl();
 
     private static final String VLAN_ID_900 = "900";
     private static final String VLAN_ID_901 = "901";
     private static final String VLAN_ID_902 = "902";
+    public static final long ACCOUNT_ID = 1;
+
+    private static final String IP4_GATEWAY = "10.0.16.1";
+    private static final String IP4_NETMASK = "255.255.255.0";
+    private static final String IP6_GATEWAY = "fd17:ac56:1234:2000::1";
+    private static final String IP6_CIDR = "fd17:ac56:1234:2000::/64";
+    final String[] ip4Dns = {"5.5.5.5", "6.6.6.6"};
+    final String[] ip6Dns = {"2001:4860:4860::5555", "2001:4860:4860::6666"};
+
+    private AccountVO account;
+    private UserVO user;
+
+    private void registerCallContext() {
+        account = new AccountVO("testaccount", 1L, "networkdomain", Account.Type.NORMAL, "uuid");
+        account.setId(ACCOUNT_ID);
+        user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone",
+                UUID.randomUUID().toString(), User.Source.UNKNOWN);
+        CallContext.register(user, account);
+    }
 
     @Test
     public void testGetPrivateVlanPairNoVlans() {
@@ -117,4 +188,229 @@ public class NetworkServiceImplTest {
         service.performBasicPrivateVlanChecks(VLAN_ID_900, VLAN_ID_901, Network.PVlanType.Promiscuous);
     }
 
+    private void prepareCreateNetworkDnsMocks(CreateNetworkCmd cmd, Network.GuestType guestType, boolean ipv6, boolean isVpc, boolean dnsServiceSupported) {
+        long networkOfferingId = 1L;
+        Mockito.when(cmd.getNetworkOfferingId()).thenReturn(networkOfferingId);
+        NetworkOfferingVO networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
+        Mockito.when(networkOfferingVO.getId()).thenReturn(networkOfferingId);
+        Mockito.when(networkOfferingVO.getGuestType()).thenReturn(guestType);
+        Mockito.when(networkOfferingVO.getTrafficType()).thenReturn(Networks.TrafficType.Guest);
+        Mockito.when(networkOfferingVO.isSpecifyIpRanges()).thenReturn(true);
+        Mockito.when(networkOfferingDao.findById(networkOfferingId)).thenReturn(networkOfferingVO);
+        Mockito.when(accountManager.finalizeOwner(Mockito.any(), Mockito.any(), Mockito.anyLong(), Mockito.anyLong())).thenReturn(account);
+        if (Network.GuestType.Shared.equals(guestType)) {
+            Mockito.when(networkModel.isProviderForNetworkOffering(Mockito.any(), Mockito.anyLong())).thenReturn(true);
+            Mockito.when(cmd.getGateway()).thenReturn(IP4_GATEWAY);
+            Mockito.when(cmd.getNetmask()).thenReturn(IP4_NETMASK);
+        }
+        Mockito.when(accountManager.isNormalUser(Mockito.anyLong())).thenReturn(true);
+        Mockito.when(physicalNetworkDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(PhysicalNetworkVO.class));
+        DataCenterVO zone = Mockito.mock(DataCenterVO.class);
+        Mockito.when(zone.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
+        Mockito.when(dataCenterDao.findById(Mockito.anyLong())).thenReturn(zone);
+        Mockito.when(networkOrchestrationService.finalizeServicesAndProvidersForNetwork(Mockito.any(), Mockito.anyLong())).thenReturn(new HashMap<>());
+        Mockito.when(networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(networkOfferingId, Network.Service.Dns)).thenReturn(dnsServiceSupported);
+        if(ipv6 && Network.GuestType.Isolated.equals(guestType)) {
+            Mockito.when(networkOfferingDao.isIpv6Supported(networkOfferingId)).thenReturn(true);
+            try {
+                Mockito.when(ipv6Service.preAllocateIpv6SubnetForNetwork(Mockito.anyLong())).thenReturn(new Pair<>(IP6_GATEWAY, IP6_CIDR));
+            } catch (ResourceAllocationException e) {
+                Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+            }
+        }
+        Mockito.when(cmd.getSubdomainAccess()).thenReturn(null);
+        Mockito.when(cmd.getAssociatedNetworkId()).thenReturn(null);
+        if (isVpc) {
+            Mockito.when(cmd.getVpcId()).thenReturn(1L);
+        } else {
+            Mockito.when(cmd.getVpcId()).thenReturn(null);
+        }
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCreateL2NetworkDnsFailure() {
+        registerCallContext();
+        CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class);
+        prepareCreateNetworkDnsMocks(cmd, Network.GuestType.L2, false, false, true);
+        Mockito.when(cmd.getIp4Dns1()).thenReturn(ip4Dns[0]);
+        try {
+            service.createGuestNetwork(cmd);
+        } catch (InsufficientCapacityException | ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        }
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCreateNetworkDnsVpcFailure() {
+        registerCallContext();
+        CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class);
+        prepareCreateNetworkDnsMocks(cmd, Network.GuestType.Isolated, false, true, true);
+        Mockito.when(cmd.getIp4Dns1()).thenReturn(ip4Dns[0]);
+        try {
+            service.createGuestNetwork(cmd);
+        } catch (InsufficientCapacityException | ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        }
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCreateNetworkDnsOfferingServiceFailure() {
+        registerCallContext();
+        CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class);
+        prepareCreateNetworkDnsMocks(cmd, Network.GuestType.Isolated, false, false, false);
+        Mockito.when(cmd.getIp4Dns1()).thenReturn(ip4Dns[0]);
+        try {
+            service.createGuestNetwork(cmd);
+        } catch (InsufficientCapacityException | ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        }
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCreateIp4NetworkIp6DnsFailure() {
+        registerCallContext();
+        CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class);
+        prepareCreateNetworkDnsMocks(cmd, Network.GuestType.Isolated, false, false, true);
+        Mockito.when(cmd.getIp6Dns1()).thenReturn(ip4Dns[0]);
+        try {
+            service.createGuestNetwork(cmd);
+        } catch (InsufficientCapacityException | ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        }
+    }
+
+    @Test
+    public void testCheckAndUpdateNetworkNoUpdate() {
+        Assert.assertFalse(service.checkAndUpdateNetworkDns(Mockito.mock(NetworkVO.class), Mockito.mock(NetworkOffering.class), null, null, null, null));
+        NetworkVO network1 = Mockito.mock(NetworkVO.class);
+        Mockito.when(network1.getDns1()).thenReturn(ip4Dns[0]);
+        Long offeringId = 1L;
+        NetworkOffering offering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(offering.getId()).thenReturn(offeringId);
+        Mockito.when(networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(offeringId, Network.Service.Dns)).thenReturn(true);
+        Assert.assertFalse(service.checkAndUpdateNetworkDns(network1, offering, null, null, null, null));
+        Assert.assertFalse(service.checkAndUpdateNetworkDns(network1, Mockito.mock(NetworkOffering.class), ip4Dns[0], null, null, null));
+        Mockito.when(network1.getIp6Dns1()).thenReturn(ip6Dns[0]);
+        Assert.assertFalse(service.checkAndUpdateNetworkDns(network1, Mockito.mock(NetworkOffering.class), ip4Dns[0], null, ip6Dns[0], null));
+    }
+
+    @Test
+    public void testCheckAndUpdateNetworkOfferingChangeReset() {
+        NetworkVO networkVO = new NetworkVO();
+        networkVO.setDns1(ip4Dns[0]);
+        Long offeringId = 1L;
+        NetworkOffering offering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(offering.getId()).thenReturn(offeringId);
+        Mockito.when(networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(offeringId, Network.Service.Dns)).thenReturn(false);
+        Assert.assertTrue(service.checkAndUpdateNetworkDns(networkVO, offering, null, null, null, null));
+        Assert.assertNull(networkVO.getDns1());
+        Assert.assertNull(networkVO.getDns2());
+        Assert.assertNull(networkVO.getIp6Dns1());
+        Assert.assertNull(networkVO.getIp6Dns2());
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCheckAndUpdateNetworkDnsL2NetworkFailure() {
+        NetworkVO networkVO = Mockito.mock(NetworkVO.class);
+        NetworkOffering offering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(offering.getGuestType()).thenReturn(Network.GuestType.L2);
+        service.checkAndUpdateNetworkDns(networkVO, offering, ip4Dns[0], null, null, null);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCheckAndUpdateNetworkDnsVpcTierFailure() {
+        NetworkVO networkVO = Mockito.mock(NetworkVO.class);
+        Mockito.when(networkVO.getVpcId()).thenReturn(1L);
+        NetworkOffering offering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(offering.getGuestType()).thenReturn(Network.GuestType.Shared);
+        service.checkAndUpdateNetworkDns(networkVO, offering, ip4Dns[0], null, null, null);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCheckAndUpdateNetworkDnsServiceFailure() {
+        NetworkVO networkVO = Mockito.mock(NetworkVO.class);
+        Mockito.when(networkVO.getVpcId()).thenReturn(null);
+        Long offeringId = 1L;
+        NetworkOffering offering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(offering.getId()).thenReturn(offeringId);
+        Mockito.when(offering.getGuestType()).thenReturn(Network.GuestType.Shared);
+        Mockito.when(networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(offeringId, Network.Service.Dns)).thenReturn(false);
+        service.checkAndUpdateNetworkDns(networkVO, offering, ip4Dns[0], null, null, null);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCheckAndUpdateNetworkNotSharedIp6Failure() {
+        NetworkVO networkVO = Mockito.mock(NetworkVO.class);
+        Mockito.when(networkVO.getVpcId()).thenReturn(null);
+        Mockito.when(networkVO.getIp6Cidr()).thenReturn(null);
+        Mockito.when(networkVO.getGuestType()).thenReturn(Network.GuestType.Shared);
+        Long offeringId = 1L;
+        NetworkOffering offering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(offering.getId()).thenReturn(offeringId);
+        Mockito.when(networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(offeringId, Network.Service.Dns)).thenReturn(true);
+        service.checkAndUpdateNetworkDns(networkVO, offering, null, null, ip6Dns[0], null);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCheckAndUpdateNetworkNotIsolatedIp6Failure() {
+        NetworkVO networkVO = Mockito.mock(NetworkVO.class);
+        Mockito.when(networkVO.getVpcId()).thenReturn(null);
+        Mockito.when(networkVO.getGuestType()).thenReturn(Network.GuestType.Isolated);
+        Long offeringId = 1L;
+        NetworkOffering offering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(offering.getId()).thenReturn(offeringId);
+        Mockito.when(networkOfferingDao.isIpv6Supported(offeringId)).thenReturn(false);
+        Mockito.when(networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(offeringId, Network.Service.Dns)).thenReturn(true);
+        service.checkAndUpdateNetworkDns(networkVO, offering, null, null, ip6Dns[0], null);
+    }
+
+    @Test
+    public void testCheckAndUpdateNetworkSuccess() {
+        NetworkVO networkVO = new NetworkVO();
+        networkVO.setVpcId(null);
+        try {
+            Field id = networkVO.getClass().getDeclaredField("guestType");
+            id.setAccessible(true);
+            id.set(networkVO, Network.GuestType.Shared);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            Assert.fail(String.format("Unable to set network guestType, %s", e.getMessage()));
+        }
+        networkVO.setIp6Cidr("cidr");
+        Long offeringId = 1L;
+        NetworkOffering offering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(offering.getId()).thenReturn(offeringId);
+        Mockito.when(networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(offeringId, Network.Service.Dns)).thenReturn(true);
+        boolean updated = service.checkAndUpdateNetworkDns(networkVO, offering, ip4Dns[0], null, ip6Dns[0], null);
+        Assert.assertTrue(updated);
+        Assert.assertEquals(ip4Dns[0], networkVO.getDns1());
+        Assert.assertNull(networkVO.getDns2());
+        Assert.assertEquals(ip6Dns[0], networkVO.getIp6Dns1());
+        Assert.assertNull(networkVO.getIp6Dns2());
+    }
+
+    @Test
+    public void testCheckAndUpdateNetworkResetSuccess() {
+        NetworkVO networkVO = new NetworkVO();
+        networkVO.setVpcId(null);
+        networkVO.setDns1(ip4Dns[0]);
+        networkVO.setIp6Dns1(ip6Dns[0]);
+        try {
+            Field id = networkVO.getClass().getDeclaredField("guestType");
+            id.setAccessible(true);
+            id.set(networkVO, Network.GuestType.Shared);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            Assert.fail(String.format("Unable to set network guestType, %s", e.getMessage()));
+        }
+        networkVO.setIp6Cidr("cidr");
+        Long offeringId = 1L;
+        NetworkOffering offering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(offering.getId()).thenReturn(offeringId);
+        Mockito.when(networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(offeringId, Network.Service.Dns)).thenReturn(true);
+        boolean updated = service.checkAndUpdateNetworkDns(networkVO, offering, "", null, "", null);
+        Assert.assertTrue(updated);
+        Assert.assertNull(networkVO.getDns1());
+        Assert.assertNull(networkVO.getDns2());
+        Assert.assertNull(networkVO.getIp6Dns1());
+        Assert.assertNull(networkVO.getIp6Dns2());
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/guru/DirectNetworkGuruTest.java b/server/src/test/java/com/cloud/network/guru/DirectNetworkGuruTest.java
index 750bee49c8..ce5aabb6c1 100644
--- a/server/src/test/java/com/cloud/network/guru/DirectNetworkGuruTest.java
+++ b/server/src/test/java/com/cloud/network/guru/DirectNetworkGuruTest.java
@@ -16,31 +16,37 @@
 // under the License.
 package com.cloud.network.guru;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
 import com.cloud.dc.DataCenter.NetworkType;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.network.Network;
+import com.cloud.network.Network.GuestType;
 import com.cloud.network.NetworkModel;
+import com.cloud.network.NetworkProfile;
 import com.cloud.network.Networks.TrafficType;
-import com.cloud.network.Network.GuestType;
 import com.cloud.network.PhysicalNetwork.IsolationMethod;
 import com.cloud.network.dao.PhysicalNetworkDao;
 import com.cloud.network.dao.PhysicalNetworkVO;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import com.cloud.user.Account;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.when;
+import com.cloud.utils.Pair;
+import com.cloud.vm.NicProfile;
 
 public class DirectNetworkGuruTest {
 
@@ -76,6 +82,9 @@ public class DirectNetworkGuruTest {
     @Mock
     Account owner;
 
+    final String[] ip4Dns = {"5.5.5.5", "6.6.6.6"};
+    final String[] ip6Dns = {"2001:4860:4860::5555", "2001:4860:4860::6666"};
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -128,4 +137,55 @@ public class DirectNetworkGuruTest {
 
         assertNotNull(guru.design(offering, plan, network, owner));
     }
+
+    @Test
+    public void testDesignDns() {
+        when(dcDao.findById(dc.getId())).thenReturn(dc);
+        when(plan.getDataCenterId()).thenReturn(1l);
+        when(plan.getPhysicalNetworkId()).thenReturn(1l);
+        when(physicalNetworkDao.findById(physicalNetwork.getId())).thenReturn(physicalNetwork);
+        when(offering.isRedundantRouter()).thenReturn(false);
+        when(network.getDns1()).thenReturn(ip4Dns[0]);
+        when(network.getDns2()).thenReturn(ip4Dns[1]);
+        when(network.getIp6Dns1()).thenReturn(ip6Dns[0]);
+        when(network.getIp6Dns2()).thenReturn(ip6Dns[1]);
+
+        when(networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Network.Service.SecurityGroup)).thenReturn(false);
+
+        Network config = guru.design(offering, plan, network, owner);
+        assertNotNull(config);
+        assertEquals(ip4Dns[0], config.getDns1());
+        assertEquals(ip4Dns[1], config.getDns2());
+        assertEquals(ip6Dns[0], config.getIp6Dns1());
+        assertEquals(ip6Dns[1], config.getIp6Dns2());
+    }
+
+    @Test
+    public void testUpdateNicProfile() {
+        NicProfile nicProfile = new NicProfile();
+        when(dcDao.findById(Mockito.anyLong())).thenReturn(dc);
+        when(networkModel.getNetworkIp4Dns(network, dc)).thenReturn(new Pair<>(ip4Dns[0], ip4Dns[1]));
+        when(networkModel.getNetworkIp6Dns(network, dc)).thenReturn(new Pair<>(ip6Dns[0], ip6Dns[1]));
+        guru.updateNicProfile(nicProfile, network);
+        assertNotNull(nicProfile);
+        assertEquals(ip4Dns[0], nicProfile.getIPv4Dns1());
+        assertEquals(ip4Dns[1], nicProfile.getIPv4Dns2());
+        assertEquals(ip6Dns[0], nicProfile.getIPv6Dns1());
+        assertEquals(ip6Dns[1], nicProfile.getIPv6Dns2());
+    }
+
+    @Test
+    public void testUpdateNetworkProfile() {
+        NetworkProfile profile = new NetworkProfile(network);
+        when(dcDao.findById(Mockito.anyLong())).thenReturn(dc);
+        when(networkModel.getNetwork(Mockito.anyLong())).thenReturn(network);
+        when(networkModel.getNetworkIp4Dns(network, dc)).thenReturn(new Pair<>(ip4Dns[0], null));
+        when(networkModel.getNetworkIp6Dns(network, dc)).thenReturn(new Pair<>(ip6Dns[0], null));
+        guru.updateNetworkProfile(profile);
+        assertNotNull(profile);
+        assertEquals(ip4Dns[0], profile.getDns1());
+        assertNull(profile.getDns2());
+        assertEquals(ip6Dns[0], profile.getIp6Dns1());
+        assertNull(profile.getIp6Dns2());
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/guru/ExternalGuestNetworkGuruTest.java b/server/src/test/java/com/cloud/network/guru/ExternalGuestNetworkGuruTest.java
new file mode 100644
index 0000000000..5a3db4819f
--- /dev/null
+++ b/server/src/test/java/com/cloud/network/guru/ExternalGuestNetworkGuruTest.java
@@ -0,0 +1,123 @@
+// 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.guru;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deploy.DeploymentPlan;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.NetworkProfile;
+import com.cloud.network.Networks;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkVO;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.user.Account;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.ComponentContext;
+import com.cloud.vm.NicProfile;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(ComponentContext.class)
+public class ExternalGuestNetworkGuruTest {
+    @Mock
+    NetworkModel networkModel;
+    @Mock
+    DataCenterDao dataCenterDao;
+    @Mock
+    PhysicalNetworkDao physicalNetworkDao;
+
+    @InjectMocks
+    protected ExternalGuestNetworkGuru guru = new ExternalGuestNetworkGuru();
+
+    final String[] ip4Dns = {"5.5.5.5", "6.6.6.6"};
+    final String[] ip6Dns = {"2001:4860:4860::5555", "2001:4860:4860::6666"};
+
+    @Test
+    public void testDesignDns() {
+        Mockito.when(networkModel.areServicesSupportedByNetworkOffering(Mockito.anyLong(), Mockito.any())).thenReturn(false);
+        Mockito.when(networkModel.networkIsConfiguredForExternalNetworking(Mockito.anyLong(), Mockito.anyLong())).thenReturn(true);
+        NetworkOffering networkOffering = Mockito.mock(NetworkOffering.class);
+        Mockito.when(networkOffering.getTrafficType()).thenReturn(Networks.TrafficType.Guest);
+        Mockito.when(networkOffering.getGuestType()).thenReturn(Network.GuestType.Isolated);
+        DataCenterVO zone = Mockito.mock(DataCenterVO.class);
+        Mockito.when(zone.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
+        Mockito.when(dataCenterDao.findById(Mockito.anyLong())).thenReturn(zone);
+        PhysicalNetworkVO physicalNetwork = Mockito.mock(PhysicalNetworkVO.class);
+        Mockito.when(physicalNetwork.getId()).thenReturn(1L);
+        Mockito.when(physicalNetworkDao.findById(Mockito.anyLong())).thenReturn(physicalNetwork);
+        DeploymentPlan plan = Mockito.mock(DeploymentPlan.class);
+        Network network = Mockito.mock(Network.class);
+        Mockito.when(network.getDns1()).thenReturn(ip4Dns[0]);
+        Mockito.when(network.getDns2()).thenReturn(ip4Dns[1]);
+        Mockito.when(network.getIp6Dns1()).thenReturn(ip6Dns[0]);
+        Mockito.when(network.getIp6Dns2()).thenReturn(ip6Dns[1]);
+        Account owner = Mockito.mock(Account.class);
+        Network config = guru.design(networkOffering, plan, network, owner);
+        assertNotNull(config);
+        assertEquals(ip4Dns[0], config.getDns1());
+        assertEquals(ip4Dns[1], config.getDns2());
+        assertEquals(ip6Dns[0], config.getIp6Dns1());
+        assertEquals(ip6Dns[1], config.getIp6Dns2());
+    }
+
+    @Test
+    public void testUpdateNicProfile() {
+        NicProfile nicProfile = new NicProfile();
+        DataCenterVO zone = Mockito.mock(DataCenterVO.class);
+        Network network = Mockito.mock(Network.class);
+        Mockito.when(dataCenterDao.findById(Mockito.anyLong())).thenReturn(zone);
+        Mockito.when(networkModel.getNetworkIp4Dns(network, zone)).thenReturn(new Pair<>(ip4Dns[0], ip4Dns[1]));
+        Mockito.when(networkModel.getNetworkIp6Dns(network, zone)).thenReturn(new Pair<>(ip6Dns[0], ip6Dns[1]));
+        guru.updateNicProfile(nicProfile, network);
+        assertNotNull(nicProfile);
+        assertEquals(ip4Dns[0], nicProfile.getIPv4Dns1());
+        assertEquals(ip4Dns[1], nicProfile.getIPv4Dns2());
+        assertEquals(ip6Dns[0], nicProfile.getIPv6Dns1());
+        assertEquals(ip6Dns[1], nicProfile.getIPv6Dns2());
+    }
+
+    @Test
+    public void testUpdateNetworkProfile() {
+        DataCenterVO zone = Mockito.mock(DataCenterVO.class);
+        Network network = Mockito.mock(Network.class);
+        NetworkProfile profile = new NetworkProfile(network);
+        Mockito.when(dataCenterDao.findById(Mockito.anyLong())).thenReturn(zone);
+        Mockito.when(networkModel.getNetwork(Mockito.anyLong())).thenReturn(network);
+        Mockito.when(networkModel.getNetworkIp4Dns(network, zone)).thenReturn(new Pair<>(ip4Dns[0], null));
+        Mockito.when(networkModel.getNetworkIp6Dns(network, zone)).thenReturn(new Pair<>(ip6Dns[0], null));
+        guru.updateNetworkProfile(profile);
+        assertNotNull(profile);
+        assertEquals(ip4Dns[0], profile.getDns1());
+        assertNull(profile.getDns2());
+        assertEquals(ip6Dns[0], profile.getIp6Dns1());
+        assertNull(profile.getIp6Dns2());
+    }
+}
diff --git a/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java b/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
index 10b59fde8b..9109bed829 100644
--- a/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
@@ -29,8 +29,11 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 
 import org.apache.cloudstack.api.command.admin.vpc.CreateVPCOfferingCmd;
+import org.apache.cloudstack.context.CallContext;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -38,28 +41,79 @@ import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.powermock.reflect.Whitebox;
 
+import com.cloud.configuration.Resource;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
 import com.cloud.network.Network;
 import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.Provider;
 import com.cloud.network.Network.Service;
 import com.cloud.network.NetworkModel;
 import com.cloud.network.element.NetworkElement;
+import com.cloud.network.vpc.dao.VpcOfferingDao;
 import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.ResourceLimitService;
+import com.cloud.user.User;
+import com.cloud.user.UserVO;
 import com.cloud.utils.net.NetUtils;
 
+
 public class VpcManagerImplTest {
 
     @Mock
-    VpcOfferingServiceMapDao vpcOffSvcMapDao;
+    AccountManager accountManager;
+    @Mock
+    ResourceLimitService resourceLimitService;
+    @Mock
+    VpcOfferingDao vpcOfferingDao;
+    @Mock
+    DataCenterDao dataCenterDao;
+    @Mock
+    VpcOfferingServiceMapDao vpcOfferingServiceMapDao;
     VpcManagerImpl manager;
 
+    public static final long ACCOUNT_ID = 1;
+    private AccountVO account;
+    private UserVO user;
+
+    private static final String IP4_GATEWAY = "10.0.16.1";
+    private static final String IP4_NETMASK = "255.255.255.0";
+    private static final String IP6_GATEWAY = "fd17:ac56:1234:2000::1";
+    private static final String IP6_CIDR = "fd17:ac56:1234:2000::/64";
+
+    final String[] ip4Dns = {"5.5.5.5", "6.6.6.6"};
+    final String[] ip6Dns = {"2001:4860:4860::5555", "2001:4860:4860::6666"};
+    final String ip4Cidr = "172.16.0.0/22";
+    final Long zoneId = 1L;
+    final Long vpcOfferingId = 1L;
+    final Long vpcOwnerId = 1L;
+    final String vpcName = "Test-VPC";
+    final String vpcDomain = "domain";
+
+    private void registerCallContext() {
+        account = new AccountVO("testaccount", 1L, "networkdomain", Account.Type.NORMAL, "uuid");
+        account.setId(ACCOUNT_ID);
+        user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone",
+                UUID.randomUUID().toString(), User.Source.UNKNOWN);
+        CallContext.register(user, account);
+    }
+
     @Before
     public void setup()
     {
         MockitoAnnotations.initMocks(this);
         manager = new VpcManagerImpl();
-        manager._vpcOffSvcMapDao = vpcOffSvcMapDao;
+        manager._accountMgr = accountManager;
+        manager._resourceLimitMgr = resourceLimitService;
+        manager._vpcOffDao = vpcOfferingDao;
+        manager._dcDao = dataCenterDao;
+        manager._vpcOffSvcMapDao = vpcOfferingServiceMapDao;
+        registerCallContext();
     }
 
     @Test
@@ -171,4 +225,47 @@ public class VpcManagerImplTest {
         Mockito.when(cmd.getInternetProtocol()).thenReturn(NetUtils.InternetProtocol.DualStack.toString());
         manager.createVpcOffering(cmd);
     }
+
+    private void mockVpcDnsResources(boolean supportDnsService, boolean isIpv6) {
+        Mockito.when(accountManager.getAccount(vpcOwnerId)).thenReturn(account);
+        VpcOfferingVO vpcOfferingVO = Mockito.mock(VpcOfferingVO.class);
+        Mockito.when(vpcOfferingVO.getId()).thenReturn(vpcOfferingId);
+        Mockito.when(vpcOfferingVO.getState()).thenReturn(VpcOffering.State.Enabled);
+        Mockito.when(vpcOfferingDao.findById(vpcOfferingId)).thenReturn(vpcOfferingVO);
+        DataCenterVO dataCenterVO = Mockito.mock(DataCenterVO.class);
+        Mockito.when(dataCenterVO.getId()).thenReturn(zoneId);
+        Mockito.when(dataCenterDao.findById(zoneId)).thenReturn(dataCenterVO);
+        Mockito.doNothing().when(accountManager).checkAccess(account, vpcOfferingVO, dataCenterVO);
+        Mockito.when(vpcOfferingServiceMapDao.areServicesSupportedByVpcOffering(vpcOfferingId, new Service[]{Service.Dns})).thenReturn(supportDnsService);
+        Mockito.when(vpcOfferingDao.isIpv6Supported(vpcOfferingId)).thenReturn(isIpv6);
+        try {
+            Mockito.doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.vpc);
+        } catch (ResourceAllocationException e) {
+            Assert.fail(String.format("checkResourceLimit failure with exception: %s", e.getMessage()));
+        }
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCreateVpcDnsOfferingServiceFailure() {
+        mockVpcDnsResources(false, false);
+        try {
+            Mockito.doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.vpc);
+            manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
+                    ip4Dns[0], null, null, null, true);
+        } catch (ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        }
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCreateVpcDnsIpv6OfferingFailure() {
+        mockVpcDnsResources(true, false);
+        try {
+            Mockito.doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.vpc);
+            manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
+                    ip4Dns[0], ip4Dns[1], ip6Dns[0], null, true);
+        } catch (ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        }
+    }
 }
diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
index 09f00b7925..f473864910 100644
--- a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -663,8 +663,8 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
     @Override
     public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain,
                                       Account owner, Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6,
-                                      String cidrv6, Boolean displayNetworkEnabled, String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String routerIp, String routerIpv6) throws ConcurrentOperationException, InsufficientCapacityException,
-        ResourceAllocationException {
+                                      String cidrv6, Boolean displayNetworkEnabled, String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String routerIp, String routerIpv6,
+                                      String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2) throws ConcurrentOperationException, ResourceAllocationException {
         // 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 83ffa03476..ccb78e3b02 100644
--- a/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java
+++ b/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java
@@ -25,6 +25,7 @@ import java.util.Set;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.dc.DataCenter;
 import com.cloud.dc.Vlan;
 import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
@@ -52,6 +53,7 @@ import com.cloud.offering.NetworkOffering.Detail;
 import com.cloud.offerings.NetworkOfferingVO;
 import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
 import com.cloud.user.Account;
+import com.cloud.utils.Pair;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.vm.Nic;
 import com.cloud.vm.NicProfile;
@@ -933,4 +935,19 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel {
         return null;
     }
 
+    @Override
+    public Pair<String, String> getNetworkIp4Dns(Network network, DataCenter zone) {
+        return new Pair<>(null, null);
+    }
+
+    @Override
+    public Pair<String, String> getNetworkIp6Dns(Network network, DataCenter zone) {
+        return new Pair<>(null, null);
+    }
+
+    @Override
+    public void verifyIp4DnsPair(String ip4Dns1, String ip4Dns2) {}
+
+    @Override
+    public void verifyIp6DnsPair(String ip4Dns1, String ip4Dns2) {}
 }
diff --git a/server/src/test/java/com/cloud/vpc/VpcApiUnitTest.java b/server/src/test/java/com/cloud/vpc/VpcApiUnitTest.java
index 8899a04532..66e6d65834 100644
--- a/server/src/test/java/com/cloud/vpc/VpcApiUnitTest.java
+++ b/server/src/test/java/com/cloud/vpc/VpcApiUnitTest.java
@@ -42,7 +42,7 @@ import junit.framework.TestCase;
 public class VpcApiUnitTest extends TestCase {
     @Inject
     VpcManagerImpl _vpcService = null;
-    VpcVO _vo = new VpcVO(1, "new vpc", "new vpc", 1, 1, 1, "0.0.0.0/0", "vpc domain", false, false, false);
+    VpcVO _vo = new VpcVO(1, "new vpc", "new vpc", 1, 1, 1, "0.0.0.0/0", "vpc domain", false, false, false, null, null, null, null);
 
     @Override
     @Before
diff --git a/server/src/test/java/com/cloud/vpc/dao/MockVpcDaoImpl.java b/server/src/test/java/com/cloud/vpc/dao/MockVpcDaoImpl.java
index f20de036f4..6322a1d169 100644
--- a/server/src/test/java/com/cloud/vpc/dao/MockVpcDaoImpl.java
+++ b/server/src/test/java/com/cloud/vpc/dao/MockVpcDaoImpl.java
@@ -96,9 +96,9 @@ public class MockVpcDaoImpl extends GenericDaoBase<VpcVO, Long> implements VpcDa
     public VpcVO findById(Long id) {
         VpcVO vo = null;
         if (id.longValue() == 1) {
-            vo = new VpcVO(1, "new vpc", "new vpc", 1, 1, 1, "0.0.0.0/0", "vpc domain", false, false, false);
+            vo = new VpcVO(1, "new vpc", "new vpc", 1, 1, 1, "0.0.0.0/0", "vpc domain", false, false, false, null, null, null, null);
         } else if (id.longValue() == 2) {
-            vo = new VpcVO(1, "new vpc", "new vpc", 1, 1, 1, "0.0.0.0/0", "vpc domain", false, false, false);
+            vo = new VpcVO(1, "new vpc", "new vpc", 1, 1, 1, "0.0.0.0/0", "vpc domain", false, false, false, null, null, null, null);
             vo.setState(State.Inactive);
         }
 
diff --git a/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java b/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java
index ba57212e5a..59437bf8cb 100644
--- a/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java
+++ b/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java
@@ -41,7 +41,7 @@ public class MockVpcOfferingServiceMapDaoImpl extends GenericDaoBase<VpcOffering
      * @see com.cloud.network.vpc.Dao.VpcOfferingServiceMapDao#areServicesSupportedByNetworkOffering(long, com.cloud.network.Network.Service[])
      */
     @Override
-    public boolean areServicesSupportedByNetworkOffering(long networkOfferingId, Service[] services) {
+    public boolean areServicesSupportedByVpcOffering(long vpcOfferingId, Service[] services) {
         // TODO Auto-generated method stub
         return false;
     }
diff --git a/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh b/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh
index bfb0621882..4eeb19bae6 100755
--- a/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh
+++ b/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh
@@ -59,6 +59,18 @@ EOF
     echo "nameserver $NS2" >> /etc/dnsmasq-resolv.conf
     echo "nameserver $NS2" >> /etc/resolv.conf
   fi
+
+  if [ -n "$IP6_NS1" ]
+  then
+    echo "nameserver $IP6_NS1" >> /etc/dnsmasq-resolv.conf
+    echo "nameserver $IP6_NS1" >> /etc/resolv.conf
+  fi
+  if [ -n "$IP6_NS2" ]
+  then
+    echo "nameserver $IP6_NS2" >> /etc/dnsmasq-resolv.conf
+    echo "nameserver $IP6_NS2" >> /etc/resolv.conf
+  fi
+
   if [ -n "$MGMTNET"  -a -n "$LOCAL_GW" ]
   then
      if [ "$HYPERVISOR" == "vmware" ] || [ "$HYPERVISOR" == "hyperv" ];
diff --git a/test/integration/component/test_network_vpc_custom_dns.py b/test/integration/component/test_network_vpc_custom_dns.py
new file mode 100644
index 0000000000..bb44d79697
--- /dev/null
+++ b/test/integration/component/test_network_vpc_custom_dns.py
@@ -0,0 +1,732 @@
+# 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.
+""" BVT test for custom DNS for Isolated network and VPC"""
+
+#Import Local Modules
+from marvin.codes import (PASS,
+                          FAIL,
+                          FAILED)
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (createGuestNetworkIpv6Prefix,
+                                  listGuestNetworkIpv6Prefixes,
+                                  deleteGuestNetworkIpv6Prefix)
+from marvin.lib.utils import (get_process_status,
+                              get_host_credentials)
+from marvin.lib.base import (Configurations,
+                             Domain,
+                             NetworkOffering,
+                             VpcOffering,
+                             Account,
+                             PublicIpRange,
+                             Network,
+                             VPC,
+                             Router,
+                             ServiceOffering,
+                             VirtualMachine,
+                             Host,
+                             NetworkACLList,
+                             NetworkACL)
+from marvin.lib.common import (get_domain,
+                               get_zone,
+                               get_test_template)
+from marvin.sshClient import SshClient
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.decoratorGenerators import skipTestIf
+
+from nose.plugins.attrib import attr
+from ipaddress import IPv6Network
+from random import getrandbits
+import time
+import logging
+
+IP6_OFFERING_CONFIG_NAME = "ipv6.offering.enabled"
+
+IP4_DNS1 = "5.5.5.5"
+IP4_DNS2 = "6.6.6.6"
+IP6_DNS1 = "2001:4860:4860::5555"
+IP6_DNS2 = "2001:4860:4860::6666"
+
+VPC_DATA = {
+    "cidr": "10.1.0.0/22",
+    "tier1_gateway": "10.1.1.1",
+    "tier2_gateway": "10.1.2.1",
+    "tier_netmask": "255.255.255.0"
+}
+
+routerDetailsMap = {}
+
+def getRouterProcessStatus(apiclient, hypervisor, config, router, cmd):
+    if router.id not in routerDetailsMap or routerDetailsMap[router.id] is None:
+        connect_ip = apiclient.connection.mgtSvr
+        connect_user = apiclient.connection.user
+        connect_passwd = apiclient.connection.passwd
+        if hypervisor.lower() not in ('vmware', 'hyperv'):
+            hosts = Host.list(
+                apiclient,
+                zoneid=router.zoneid,
+                type='Routing',
+                state='Up',
+                id=router.hostid
+            )
+            if not isinstance(hosts, list):
+                return [FAIL, "list host returns an invalid list"]
+            host = hosts[0]
+            connect_ip = host.ipaddress
+            hypervisor = None
+            try:
+                connect_user, connect_passwd= get_host_credentials(
+                    config, host.ipaddress)
+            except KeyError:
+                return [FAIL, "Marvin configuration has no host credentials to check router services"]
+        details = {}
+        details['connect_ip'] = connect_ip
+        details['connect_user'] = connect_user
+        details['connect_passwd'] = connect_passwd
+        details['hypervisor'] = hypervisor
+        routerDetailsMap[router.id] = details
+    result = get_process_status(
+        routerDetailsMap[router.id]['connect_ip'],
+        22,
+        routerDetailsMap[router.id]['connect_user'],
+        routerDetailsMap[router.id]['connect_passwd'],
+        router.linklocalip,
+        cmd,
+        hypervisor=routerDetailsMap[router.id]['hypervisor']
+    )
+    if type(result) != list or len(result) == 0:
+        return [FAIL, "%s on router %s returned invalid result" % (cmd, router.id)]
+    result = '\n'.join(result)
+    return [PASS, result]
+
+class TestNetworkCustomDns(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestNetworkCustomDns, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        routerDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestNetworkCustomDns')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=IP6_OFFERING_CONFIG_NAME)[0].value
+            Configurations.update(cls.apiclient,
+                IP6_OFFERING_CONFIG_NAME,
+                "true")
+        else:
+            cls.debug("IPv6 is not supported, skipping testing IPv6 details!")
+        cls.domain = get_domain(cls.apiclient)
+        cls.account = Account.create(
+            cls.apiclient,
+            cls.services["account"],
+            admin=True,
+            domainid=cls.domain.id
+        )
+        cls._cleanup.append(cls.account)
+        cls.hypervisor = testClient.getHypervisorInfo()
+        cls.template = get_test_template(
+           cls.apiclient,
+           cls.zone.id,
+           cls.hypervisor)
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                IP6_OFFERING_CONFIG_NAME,
+                cls.initial_ipv6_offering_enabled)
+        super(TestNetworkCustomDns, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        super(TestNetworkCustomDns, self).tearDown()
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createNetworkOffering(self):
+        off_service = self.services["network_offering"]
+        if not self.ipv6NotSupported:
+            off_service["internetprotocol"] = "dualstack"
+        self.network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service
+        )
+        self.cleanup.append(self.network_offering)
+        self.network_offering.update(self.apiclient, state='Enabled')
+
+
+    def deployNetwork(self):
+        network_service = self.services["network"]
+        network_service["networkoffering"] = self.network_offering.id
+        network_service["dns1"] = IP4_DNS1
+        network_service["dns2"] = IP4_DNS2
+        if not self.ipv6NotSupported:
+            network_service["ip6dns1"] = IP6_DNS1
+            network_service["ip6dns2"] = IP6_DNS2
+        self.network = Network.create(
+            self.apiclient,
+            self.services["network"],
+            self.account.name,
+            self.account.domainid,
+            zoneid=self.zone.id
+        )
+        self.cleanup.append(self.network)
+
+    def deployNetworkVm(self):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        self.virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=self.network.id,
+            serviceofferingid=self.service_offering.id
+        )
+        self.cleanup.append(self.virtual_machine)
+
+    def getNetworkRouter(self, network, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            networkid=network.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for network %s" % network.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def checkNetwork(self):
+        self.debug("Listing network: %s" % (self.network.name))
+        network = Network.list(self.apiclient,listall="true",id=self.network.id)
+        self.assertTrue(
+            isinstance(network, list),
+            "Check listNetworks response returns a valid list"
+        )
+        self.assertEqual(
+            len(network),
+            1,
+            "Network not found"
+        )
+        network = network[0]
+        self.assertNotEqual(network,
+                    None,
+                    "User is not able to retrieve network details %s" % self.network.id)
+        self.assertEqual(network.dns1,
+                    IP4_DNS1,
+                    "IPv4 DNS1 is not same, expected=%s, actual=%s" % (IP4_DNS1, network.dns1))
+        self.assertEqual(network.dns2,
+                    IP4_DNS2,
+                    "IPv4 DNS2 is not same, expected=%s, actual=%s" % (IP4_DNS2, network.dns2))
+        if not self.ipv6NotSupported:
+            self.assertEqual(network.ip6dns1,
+                        IP6_DNS1,
+                        "IPv6 DNS1 is not same, expected=%s, actual=%s" % (IP6_DNS1, network.ip6dns1))
+            self.assertEqual(network.ip6dns2,
+                        IP6_DNS2,
+                        "IPv6 DNS2 is not same, expected=%s, actual=%s" % (IP6_DNS2, network.ip6dns2))
+
+    def checkNetworkRouter(self):
+        router = self.getNetworkRouter(self.network)
+        dns_cmd = "cat /etc/resolv.conf"
+        res = getRouterProcessStatus(self.apiclient, self.hypervisor, self.config, router, dns_cmd)
+        if res[0] == FAIL:
+            self.fail("Failed to get router command result. %s" % res[1])
+        res = res[1]
+        ns = "nameserver %s" % IP4_DNS1
+        self.assertTrue(ns in res,
+            "Network router doesn't contain nameserver for DNS1: %s" % IP4_DNS1)
+        ns = "nameserver %s" % IP4_DNS2
+        self.assertTrue(ns in res,
+            "Network router doesn't contain nameserver for DNS2: %s" % IP4_DNS2)
+        if not self.ipv6NotSupported:
+            ns = "nameserver %s" % IP6_DNS1
+            self.assertTrue(ns in res,
+                "Network router doesn't contain nameserver for IPv6 DNS1: %s" % IP6_DNS1)
+            ns = "nameserver %s" % IP6_DNS2
+            self.assertTrue(ns in res,
+                "Network router doesn't contain nameserver for IPv6 DNS2: %s" % IP6_DNS2)
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_01_verify_network_dns(self):
+        """Test to verify custom DNS for network
+
+        # Validate the following:
+        # 1. Create network, deploy VM
+        # 2. Verify network has required DNS details
+        # 3. SSH into VR for the network and verify it has required DNS details as nameserver
+        """
+
+        self.createNetworkOffering()
+        self.createTinyServiceOffering()
+        self.deployNetwork()
+        self.deployNetworkVm()
+        self.checkNetwork()
+        self.checkNetworkRouter()
+
+class TestVpcCustomDns(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestVpcCustomDns, cls).getClsTestClient()
+        cls.services = testClient.getParsedTestDataConfig()
+        cls.apiclient = testClient.getApiClient()
+        cls.dbclient = testClient.getDbConnection()
+        cls.test_ipv6_guestprefix = None
+        cls.initial_ipv6_offering_enabled = None
+        cls._cleanup = []
+        routerDetailsMap = {}
+        cls.vpcAllowAllAclDetailsMap = {}
+
+        cls.logger = logging.getLogger('TestVpcCustomDns')
+
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.ipv6NotSupported = False
+
+        ipv6_guestprefix = cls.getGuestIpv6Prefix()
+        if ipv6_guestprefix == None:
+            cls.ipv6NotSupported = True
+        if cls.ipv6NotSupported == False:
+            ipv6_publiciprange = cls.getPublicIpv6Range()
+            if ipv6_publiciprange == None:
+                cls.ipv6NotSupported = True
+
+        if cls.ipv6NotSupported == False:
+            cls.initial_ipv6_offering_enabled = Configurations.list(
+                cls.apiclient,
+                name=IP6_OFFERING_CONFIG_NAME)[0].value
+            Configurations.update(cls.apiclient,
+                IP6_OFFERING_CONFIG_NAME,
+                "true")
+        else:
+            cls.debug("IPv6 is not supported, skipping testing IPv6 details!")
+        cls.domain = get_domain(cls.apiclient)
+        cls.account = Account.create(
+            cls.apiclient,
+            cls.services["account"],
+            admin=True,
+            domainid=cls.domain.id
+        )
+        cls._cleanup.append(cls.account)
+        cls.hypervisor = testClient.getHypervisorInfo()
+        cls.template = get_test_template(
+           cls.apiclient,
+           cls.zone.id,
+               cls.hypervisor)
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        if cls.initial_ipv6_offering_enabled != None:
+            Configurations.update(cls.apiclient,
+                IP6_OFFERING_CONFIG_NAME,
+                cls.initial_ipv6_offering_enabled)
+        super(TestVpcCustomDns, cls).tearDownClass()
+        if cls.test_ipv6_guestprefix != None:
+            cmd = deleteGuestNetworkIpv6Prefix.deleteGuestNetworkIpv6PrefixCmd()
+            cmd.id = cls.test_ipv6_guestprefix.id
+            cls.apiclient.deleteGuestNetworkIpv6Prefix(cmd)
+
+    @classmethod
+    def getGuestIpv6Prefix(cls):
+        cmd = listGuestNetworkIpv6Prefixes.listGuestNetworkIpv6PrefixesCmd()
+        cmd.zoneid = cls.zone.id
+        ipv6_prefixes_response = cls.apiclient.listGuestNetworkIpv6Prefixes(cmd)
+        if isinstance(ipv6_prefixes_response, list) == True and len(ipv6_prefixes_response) > 0:
+            return ipv6_prefixes_response[0]
+        ipv6_guestprefix_service = cls.services["guestip6prefix"]
+        cmd = createGuestNetworkIpv6Prefix.createGuestNetworkIpv6PrefixCmd()
+        cmd.zoneid = cls.zone.id
+        cmd.prefix = ipv6_guestprefix_service["prefix"]
+        ipv6_guestprefix = cls.apiclient.createGuestNetworkIpv6Prefix(cmd)
+        cls.test_ipv6_guestprefix = ipv6_guestprefix
+        return ipv6_guestprefix
+
+    @classmethod
+    def getPublicIpv6Range(cls):
+        list_public_ip_range_response = PublicIpRange.list(
+            cls.apiclient,
+            zoneid=cls.zone.id
+        )
+        ipv4_range_vlan = None
+        if isinstance(list_public_ip_range_response, list) == True and len(list_public_ip_range_response) > 0:
+            for ip_range in list_public_ip_range_response:
+                if ip_range.ip6cidr != None and ip_range.ip6gateway != None:
+                    return ip_range
+                if ip_range.netmask != None and ip_range.gateway != None:
+                    vlan = ip_range.vlan
+                    if ipv4_range_vlan == None and vlan.startswith("vlan://"):
+                        vlan = vlan.replace("vlan://", "")
+                        if vlan == "untagged":
+                            ipv4_range_vlan = None
+                        else:
+                            ipv4_range_vlan = int(vlan)
+        ipv6_publiciprange_service = cls.services["publicip6range"]
+        ipv6_publiciprange_service["zoneid"] = cls.zone.id
+        ipv6_publiciprange_service["vlan"] = ipv4_range_vlan
+        ipv6_publiciprange = PublicIpRange.create(
+            cls.apiclient,
+            ipv6_publiciprange_service
+        )
+        cls._cleanup.append(ipv6_publiciprange)
+        return ipv6_publiciprange
+
+    def setUp(self):
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        super(TestVpcCustomDns, self).tearDown()
+
+    def createTinyServiceOffering(self):
+        self.service_offering = ServiceOffering.create(
+            self.apiclient,
+            self.services["service_offerings"]["big"],
+        )
+        self.cleanup.append(self.service_offering)
+
+    def createVpcOfferingInternal(self, is_redundant, is_ipv6):
+        off_service = self.services["vpc_offering"]
+        if is_redundant:
+            off_service["serviceCapabilityList"] = {
+                "SourceNat": {
+                    "RedundantRouter": 'true'
+                },
+            }
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        vpc_offering = VpcOffering.create(
+            self.apiclient,
+            off_service
+        )
+        self.cleanup.append(vpc_offering)
+        vpc_offering.update(self.apiclient, state='Enabled')
+        return vpc_offering
+
+    def createVpcOffering(self, is_redundant=False):
+        self.vpc_offering = self.createVpcOfferingInternal(is_redundant, self.ipv6NotSupported == False)
+
+    def deployAllowAllVpcInternal(self, cidr):
+        service = self.services["vpc"]
+        service["cidr"] = cidr
+        ip6Dns1 = None
+        ip6Dns2 = None
+        if not self.ipv6NotSupported:
+            ip6Dns1 = IP6_DNS1
+            ip6Dns2 = IP6_DNS2
+
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            vpcofferingid=self.vpc_offering.id,
+            zoneid=self.zone.id,
+            account=self.account.name,
+            domainid=self.account.domainid,
+            dns1=IP4_DNS1,
+            dns2=IP4_DNS2,
+            ip6dns1=ip6Dns1,
+            ip6dns2=ip6Dns2
+        )
+        self.cleanup.append(vpc)
+        acl = NetworkACLList.create(
+            self.apiclient,
+            services={},
+            name="allowall",
+            description="allowall",
+            vpcid=vpc.id
+        )
+        rule ={
+            "protocol": "all",
+            "traffictype": "ingress",
+        }
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        rule["traffictype"] = "egress"
+        NetworkACL.create(self.apiclient,
+            services=rule,
+            aclid=acl.id
+        )
+        self.vpcAllowAllAclDetailsMap[vpc.id] = acl.id
+        return vpc
+
+    def deployVpc(self):
+        self.vpc = self.deployAllowAllVpcInternal(VPC_DATA["cidr"])
+
+    def createNetworkTierOfferingInternal(self, is_ipv6, remove_lb=True):
+        off_service = self.services["nw_offering_isolated_vpc"]
+        if not remove_lb: # Remove Lb service
+            if "serviceProviderList" in off_service and "Lb" in off_service["serviceProviderList"].keys():
+                providers = off_service["serviceProviderList"]
+                providers.pop("Lb")
+                off_service["serviceProviderList"] = providers
+            if "supportedservices" in off_service and "Lb" in off_service["supportedservices"]:
+                supportedServices = off_service["supportedservices"].split(",")
+                supportedServices.remove("Lb")
+                off_service["supportedservices"] = ",".join(supportedServices)
+        if is_ipv6:
+            off_service["internetprotocol"] = "dualstack"
+        network_offering = NetworkOffering.create(
+            self.apiclient,
+            off_service,
+            conservemode=False
+        )
+        self.cleanup.append(network_offering)
+        network_offering.update(self.apiclient, state='Enabled')
+        return network_offering
+
+    def createNetworkTierOffering(self):
+        self.network_offering = self.createNetworkTierOfferingInternal(self.ipv6NotSupported == False)
+
+    def deployNetworkTierInternal(self, network_offering_id, vpc_id, tier_gateway, tier_netmask, acl_id=None, tier_name=None):
+        if not acl_id and vpc_id in self.vpcAllowAllAclDetailsMap:
+            acl_id = self.vpcAllowAllAclDetailsMap[vpc_id]
+        service = self.services["ntwk"]
+        if tier_name:
+            service["name"] = tier_name
+            service["displaytext"] = "vpc-%s" % tier_name
+        network = Network.create(
+            self.apiclient,
+            service,
+            self.account.name,
+            self.account.domainid,
+            networkofferingid=network_offering_id,
+            vpcid=vpc_id,
+            zoneid=self.zone.id,
+            gateway=tier_gateway,
+            netmask=tier_netmask,
+            aclid=acl_id
+        )
+        self.cleanup.append(network)
+        return network
+
+    def deployNetworkTier(self):
+        self.network = self.deployNetworkTierInternal(
+            self.network_offering.id,
+            self.vpc.id,
+            VPC_DATA["tier1_gateway"],
+            VPC_DATA["tier_netmask"]
+        )
+
+    def deployNetworkTierVmInternal(self, network):
+        if self.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+        self.services["virtual_machine"]["zoneid"] = self.zone.id
+        virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            networkids=network,
+            serviceofferingid=self.service_offering.id
+        )
+        self.cleanup.append(virtual_machine)
+        return virtual_machine
+
+    def deployNetworkTierVm(self):
+        self.virtual_machine = self.deployNetworkTierVmInternal(self.network.id)
+
+    def checkVpcBasic(self):
+        self.debug("Listing VPC: %s" % (self.vpc.name))
+        vpc = VPC.list(self.apiclient,listall="true",id=self.vpc.id)
+        self.assertTrue(
+            isinstance(vpc, list),
+            "Check listVpcs response returns a valid list"
+        )
+        self.assertEqual(
+            len(vpc),
+            1,
+            "Network not found"
+        )
+        vpc = vpc[0]
+        self.assertEqual(vpc.dns1,
+                    IP4_DNS1,
+                    "IPv4 DNS1 is not same, expected=%s, actual=%s" % (IP4_DNS1, vpc.dns1))
+        self.assertEqual(vpc.dns2,
+                    IP4_DNS2,
+                    "IPv4 DNS2 is not same, expected=%s, actual=%s" % (IP4_DNS2, vpc.dns2))
+        if not self.ipv6NotSupported:
+            self.assertEqual(vpc.ip6dns1,
+                        IP6_DNS1,
+                        "IPv6 DNS1 is not same, expected=%s, actual=%s" % (IP6_DNS1, vpc.ip6dns1))
+            self.assertEqual(vpc.ip6dns2,
+                        IP6_DNS2,
+                        "IPv6 DNS2 is not same, expected=%s, actual=%s" % (IP6_DNS2, vpc.ip6dns2))
+
+    def getVpcRouter(self, vpc, red_state="PRIMARY"):
+        routers = Router.list(
+            self.apiclient,
+            vpcid=vpc.id,
+            listall=True
+        )
+        self.assertTrue(
+            isinstance(routers, list) and len(routers) > 0,
+            "No routers found for VPC %s" % vpc.id
+        )
+        if len(routers) == 1:
+            return routers[0]
+        for router in routers:
+            if router.redundantstate == red_state:
+                return router
+
+    def checkVpcRouter(self):
+        router = self.getVpcRouter(self.vpc)
+        dns_cmd = "cat /etc/resolv.conf"
+        res = getRouterProcessStatus(self.apiclient, self.hypervisor, self.config, router, dns_cmd)
+        if res[0] == FAIL:
+            self.fail("Failed to get router command result. %s" % res[1])
+        res = res[1]
+        ns = "nameserver %s" % IP4_DNS1
+        self.assertTrue(ns in res,
+            "Network router doesn't contain nameserver for DNS1: %s" % IP4_DNS1)
+        ns = "nameserver %s" % IP4_DNS2
+        self.assertTrue(ns in res,
+            "Network router doesn't contain nameserver for DNS2: %s" % IP4_DNS2)
+        if not self.ipv6NotSupported:
+            ns = "nameserver %s" % IP6_DNS1
+            self.assertTrue(ns in res,
+                "Network router doesn't contain nameserver for IPv6 DNS1: %s" % IP6_DNS1)
+            ns = "nameserver %s" % IP6_DNS2
+            self.assertTrue(ns in res,
+                "Network router doesn't contain nameserver for IPv6 DNS2: %s" % IP6_DNS2)
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "eip",
+            "sg",
+            "advancedns",
+            "smoke"],
+        required_hardware="false")
+    def test_01_verify_vpc_dns(self):
+        """Test to verify custom DNS for VPC
+        # Validate the following:
+        # 1. Create VPC, deploy network tier and VM in it
+        # 2. Verify VPC details
+        # 3. Verify VPC router details
+        """
+
+        self.createVpcOffering()
+        self.createNetworkTierOffering()
+        self.createTinyServiceOffering()
+        self.deployVpc()
+        self.deployNetworkTier()
+        self.deployNetworkTierVm()
+        self.checkVpcBasic()
+        self.checkVpcRouter()
+
diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py
index 00d212b139..c6a595810b 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -3240,6 +3240,14 @@ class Network:
             cmd.endipv6 = services["endipv6"]
         if "routeripv6" in services:
             cmd.routeripv6 = services["routeripv6"]
+        if "dns1" in services:
+            cmd.dns1 = services["dns1"]
+        if "dns2" in services:
+            cmd.dns2 = services["dns2"]
+        if "ip6dns1" in services:
+            cmd.ip6dns1 = services["ip6dns1"]
+        if "ip6dns2" in services:
+            cmd.ip6dns2 = services["ip6dns2"]
 
         if accountid:
             cmd.account = accountid
diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js
index 94e7ffeabc..b83087396d 100644
--- a/ui/src/config/section/network.js
+++ b/ui/src/config/section/network.js
@@ -39,7 +39,7 @@ export default {
         return fields
       },
       details: () => {
-        var fields = ['name', 'id', 'description', 'type', 'traffictype', 'vpcid', 'vlan', 'broadcasturi', 'cidr', 'ip6cidr', 'netmask', 'gateway', 'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 'redundantrouter', 'networkdomain', 'egressdefaultpolicy', 'zonename', 'account', 'domain', 'associatednetwork', 'associatednetworkid', 'ip6firewall', 'ip6routing', 'ip6routes']
+        var fields = ['name', 'id', 'description', 'type', 'traffictype', 'vpcid', 'vlan', 'broadcasturi', 'cidr', 'ip6cidr', 'netmask', 'gateway', 'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 'redundantrouter', 'networkdomain', 'egressdefaultpolicy', 'zonename', 'account', 'domain', 'associatednetwork', 'associatednetworkid', 'ip6firewall', 'ip6routing', 'ip6routes', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2']
         if (!isAdmin()) {
           fields = fields.filter(function (e) { return e !== 'broadcasturi' })
         }
@@ -166,7 +166,7 @@ export default {
       permission: ['listVPCs'],
       resourceType: 'Vpc',
       columns: ['name', 'state', 'displaytext', 'cidr', 'account', 'zonename'],
-      details: ['name', 'id', 'displaytext', 'cidr', 'networkdomain', 'ip6routes', 'ispersistent', 'redundantvpcrouter', 'restartrequired', 'zonename', 'account', 'domain'],
+      details: ['name', 'id', 'displaytext', 'cidr', 'networkdomain', 'ip6routes', 'ispersistent', 'redundantvpcrouter', 'restartrequired', 'zonename', 'account', 'domain', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2'],
       searchFilters: ['name', 'zoneid', 'domainid', 'account', 'tags'],
       related: [{
         name: 'vm',
diff --git a/ui/src/views/network/CreateIsolatedNetworkForm.vue b/ui/src/views/network/CreateIsolatedNetworkForm.vue
index 7e6e83e9f9..6ea2389880 100644
--- a/ui/src/views/network/CreateIsolatedNetworkForm.vue
+++ b/ui/src/views/network/CreateIsolatedNetworkForm.vue
@@ -105,14 +105,14 @@
             </a-select>
           </a-form-item>
           <a-form-item
-            ref="vlanid"
-            name="vlanid"
+            ref="vlan"
+            name="vlan"
             v-if="!isObjectEmpty(selectedNetworkOffering) && selectedNetworkOffering.specifyvlan">
             <template #label>
               <tooltip-label :title="$t('label.vlan')" :tooltip="apiParams.vlan.description"/>
             </template>
             <a-input
-             v-model:value="form.vlanid"
+             v-model:value="form.vlan"
               :placeholder="apiParams.vlan.description"/>
           </a-form-item>
           <a-form-item
@@ -167,22 +167,68 @@
              v-model:value="form.netmask"
               :placeholder="apiParams.netmask.description"/>
           </a-form-item>
-          <a-form-item v-if="selectedNetworkOffering && selectedNetworkOffering.specifyipranges" name="startipv4" ref="startipv4">
+          <a-form-item v-if="selectedNetworkOffering && selectedNetworkOffering.specifyipranges" name="startip" ref="startip">
             <template #label>
               <tooltip-label :title="$t('label.startipv4')" :tooltip="apiParams.startip.description"/>
             </template>
             <a-input
-              v-model:value="form.startipv4"
+              v-model:value="form.startip"
               :placeholder="apiParams.startip.description"/>
           </a-form-item>
-          <a-form-item v-if="selectedNetworkOffering && selectedNetworkOffering.specifyipranges" name="endipv4" ref="endipv4">
+          <a-form-item v-if="selectedNetworkOffering && selectedNetworkOffering.specifyipranges" name="endip" ref="endip">
             <template #label>
-              <tooltip-label :title="$t('label.endipv4')" :tooltip="apiParams.endip.description"/>
+              <tooltip-label :title="$t('label.endip')" :tooltip="apiParams.endip.description"/>
             </template>
             <a-input
-              v-model:value="form.endipv4"
+              v-model:value="form.endip"
               :placeholder="apiParams.endip.description"/>
           </a-form-item>
+          <div v-if="selectedNetworkOfferingSupportsDns">
+            <a-row :gutter="12">
+              <a-col :md="12" :lg="12">
+                <a-form-item v-if="'dns1' in apiParams" name="dns1" ref="dns1">
+                  <template #label>
+                    <tooltip-label :title="$t('label.dns1')" :tooltip="apiParams.dns1.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.dns1"
+                    :placeholder="apiParams.dns1.description"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="12" :lg="12">
+                <a-form-item v-if="'dns2' in apiParams" name="dns2" ref="dns2">
+                  <template #label>
+                    <tooltip-label :title="$t('label.dns2')" :tooltip="apiParams.dns2.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.dns2"
+                    :placeholder="apiParams.dns2.description"/>
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="12">
+              <a-col :md="12" :lg="12">
+                <a-form-item v-if="selectedNetworkOffering && selectedNetworkOffering.internetprotocol === 'DualStack' && 'ip6dns1' in apiParams" name="ip6dns1" ref="ip6dns1">
+                  <template #label>
+                    <tooltip-label :title="$t('label.ip6dns1')" :tooltip="apiParams.ip6dns1.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.ip6dns1"
+                    :placeholder="apiParams.ip6dns1.description"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="12" :lg="12">
+                <a-form-item v-if="selectedNetworkOffering && selectedNetworkOffering.internetprotocol === 'DualStack' && 'ip6dns2' in apiParams" name="ip6dns2" ref="ip6dns2">
+                  <template #label>
+                    <tooltip-label :title="$t('label.ip6dns2')" :tooltip="apiParams.ip6dns2.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.ip6dns2"
+                    :placeholder="apiParams.ip6dns2.description"/>
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </div>
           <a-form-item
             ref="networkdomain"
             name="networkdomain"
@@ -294,6 +340,16 @@ export default {
     this.initForm()
     this.fetchData()
   },
+  computed: {
+    selectedNetworkOfferingSupportsDns () {
+      if (this.selectedNetworkOffering) {
+        const services = this.selectedNetworkOffering?.service || []
+        const dnsServices = services.filter(service => service.name === 'Dns')
+        return dnsServices && dnsServices.length === 1
+      }
+      return false
+    }
+  },
   methods: {
     initForm () {
       this.formRef = ref()
@@ -457,29 +513,11 @@ export default {
           displayText: values.displaytext,
           networkOfferingId: this.selectedNetworkOffering.id
         }
-        if (this.isValidTextValueForKey(values, 'gateway')) {
-          params.gateway = values.gateway
-        }
-        if (this.isValidTextValueForKey(values, 'netmask')) {
-          params.netmask = values.netmask
-        }
-        if (this.isValidTextValueForKey(values, 'startipv4')) {
-          params.startip = values.startipv4
-        }
-        if (this.isValidTextValueForKey(values, 'endipv4')) {
-          params.endip = values.endipv4
-        }
-        if (this.isValidTextValueForKey(values, 'externalid')) {
-          params.externalid = values.externalid
-        }
-        if (this.isValidTextValueForKey(values, 'vpcid')) {
-          params.vpcid = this.selectedVpc.id
-        }
-        if (this.isValidTextValueForKey(values, 'vlanid')) {
-          params.vlan = values.vlanid
-        }
-        if (this.isValidTextValueForKey(values, 'networkdomain')) {
-          params.networkdomain = values.networkdomain
+        var usefulFields = ['gateway', 'netmask', 'startip', 'endip', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'externalid', 'vpcid', 'vlan', 'networkdomain']
+        for (var field of usefulFields) {
+          if (this.isValidTextValueForKey(values, field)) {
+            params[field] = values[field]
+          }
         }
         if ('domainid' in values && values.domainid > 0) {
           params.domainid = this.selectedDomain.id
diff --git a/ui/src/views/network/CreateSharedNetworkForm.vue b/ui/src/views/network/CreateSharedNetworkForm.vue
index 1b62e473dc..1d26cf1b1e 100644
--- a/ui/src/views/network/CreateSharedNetworkForm.vue
+++ b/ui/src/views/network/CreateSharedNetworkForm.vue
@@ -85,12 +85,12 @@
               </a-select-option>
             </a-select>
           </a-form-item>
-          <a-form-item v-if="!this.isObjectEmpty(this.selectedNetworkOffering) && this.selectedNetworkOffering.specifyvlan && isAdmin()" name="vlanid" ref="vlanid">
+          <a-form-item v-if="!this.isObjectEmpty(this.selectedNetworkOffering) && this.selectedNetworkOffering.specifyvlan && isAdmin()" name="vlan" ref="vlan">
             <template #label>
               <tooltip-label :title="$t('label.vlan')" :tooltip="apiParams.vlan.description"/>
             </template>
             <a-input
-              v-model:value="form.vlanid"
+              v-model:value="form.vlan"
               :placeholder="apiParams.vlan.description"/>
           </a-form-item>
           <a-form-item name="bypassvlanoverlapcheck" ref="bypassvlanoverlapcheck" v-if="isAdmin()">
@@ -265,86 +265,158 @@
               </a-select-option>
             </a-select>
           </a-form-item>
-          <a-form-item name="ip4gateway" ref="ip4gateway">
-            <template #label>
-              <tooltip-label :title="$t('label.ip4gateway')" :tooltip="apiParams.gateway.description"/>
-            </template>
-            <a-input
-              v-model:value="form.ip4gateway"
-              :placeholder="apiParams.gateway.description"/>
-          </a-form-item>
-          <a-form-item name="ip4netmask" ref="ip4netmask">
-            <template #label>
-              <tooltip-label :title="$t('label.ip4netmask')" :tooltip="apiParams.netmask.description"/>
-            </template>
-            <a-input
-              v-model:value="form.ip4netmask"
-              :placeholder="apiParams.netmask.description"/>
-          </a-form-item>
-          <a-form-item name="startipv4" ref="startipv4">
-            <template #label>
-              <tooltip-label :title="$t('label.startipv4')" :tooltip="apiParams.startip.description"/>
-            </template>
-            <a-input
-              v-model:value="form.startipv4"
-              :placeholder="apiParams.startip.description"/>
-          </a-form-item>
-          <a-form-item name="endipv4" ref="endipv4">
-            <template #label>
-              <tooltip-label :title="$t('label.endipv4')" :tooltip="apiParams.endip.description"/>
-            </template>
-            <a-input
-              v-model:value="form.endipv4"
-              :placeholder="apiParams.endip.description"/>
-          </a-form-item>
-          <a-form-item v-if="isVirtualRouterForAtLeastOneService" name="routerip" ref="routerip">
-            <template #label>
-              <tooltip-label :title="$t('label.routerip')" :tooltip="apiParams.routerip.description"/>
-            </template>
-            <a-input
-              v-model:value="form.routerip"
-              :placeholder="apiParams.routerip.description"/>
-          </a-form-item>
-          <a-form-item name="ip6gateway" ref="ip6gateway">
-            <template #label>
-              <tooltip-label :title="$t('label.ip6gateway')" :tooltip="apiParams.ip6gateway.description"/>
-            </template>
-            <a-input
-              v-model:value="form.ip6gateway"
-              :placeholder="apiParams.ip6gateway.description"/>
-          </a-form-item>
-          <a-form-item name="ip6cidr" ref="ip6cidr">
-            <template #label>
-              <tooltip-label :title="$t('label.ip6cidr')" :tooltip="apiParams.ip6cidr.description"/>
-            </template>
-            <a-input
-              v-model:value="form.ip6cidr"
-              :placeholder="apiParams.ip6cidr.description"/>
-          </a-form-item>
-          <a-form-item name="startipv6" ref="startipv6">
-            <template #label>
-              <tooltip-label :title="$t('label.startipv6')" :tooltip="apiParams.startipv6.description"/>
-            </template>
-            <a-input
-              v-model:value="form.startipv6"
-              :placeholder="apiParams.startipv6.description"/>
-          </a-form-item>
-          <a-form-item name="endipv6" ref="endipv6">
-            <template #label>
-              <tooltip-label :title="$t('label.endipv6')" :tooltip="apiParams.endipv6.description"/>
-            </template>
-            <a-input
-              v-model:value="form.endipv6"
-              :placeholder="apiParams.endipv6.description"/>
-          </a-form-item>
-          <a-form-item v-if="isVirtualRouterForAtLeastOneService" name="routeripv6" ref="routeripv6">
-            <template #label>
-              <tooltip-label :title="$t('label.routeripv6')" :tooltip="apiParams.routeripv6.description"/>
-            </template>
-            <a-input
-              v-model:value="form.routeripv6"
-              :placeholder="apiParams.routeripv6.description"/>
-          </a-form-item>
+          <a-card size="small" :title="$t('label.ip.v4')" style="margin-top: 15px">
+            <a-row :gutter="12">
+              <a-col :md="12" :lg="12">
+                <a-form-item name="gateway" ref="gateway">
+                  <template #label>
+                    <tooltip-label :title="$t('label.ip4gateway')" :tooltip="apiParams.gateway.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.gateway"
+                    :placeholder="apiParams.gateway.description"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="12" :lg="12">
+                <a-form-item name="netmask" ref="netmask">
+                  <template #label>
+                    <tooltip-label :title="$t('label.ip4netmask')" :tooltip="apiParams.netmask.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.netmask"
+                    :placeholder="apiParams.netmask.description"/>
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="12">
+              <a-col :md="12" :lg="12">
+                <a-form-item name="startip" ref="startip">
+                  <template #label>
+                    <tooltip-label :title="$t('label.startipv4')" :tooltip="apiParams.startip.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.startip"
+                    :placeholder="apiParams.startip.description"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="12" :lg="12">
+                <a-form-item name="endip" ref="endip">
+                  <template #label>
+                    <tooltip-label :title="$t('label.endipv4')" :tooltip="apiParams.endip.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.endip"
+                    :placeholder="apiParams.endip.description"/>
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-form-item v-if="isVirtualRouterForAtLeastOneService" name="routerip" ref="routerip">
+              <template #label>
+                <tooltip-label :title="$t('label.routerip')" :tooltip="apiParams.routerip.description"/>
+              </template>
+              <a-input
+                v-model:value="form.routerip"
+                :placeholder="apiParams.routerip.description"/>
+            </a-form-item>
+            <a-row :gutter="12" v-if="selectedNetworkOfferingSupportsDns">
+              <a-col :md="12" :lg="12">
+                <a-form-item v-if="'dns1' in apiParams" name="dns1" ref="dns1">
+                  <template #label>
+                    <tooltip-label :title="$t('label.dns1')" :tooltip="apiParams.dns1.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.dns1"
+                    :placeholder="apiParams.dns1.description"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="12" :lg="12">
+                <a-form-item v-if="'dns2' in apiParams" name="dns2" ref="dns2">
+                  <template #label>
+                    <tooltip-label :title="$t('label.dns2')" :tooltip="apiParams.dns2.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.dns2"
+                    :placeholder="apiParams.dns2.description"/>
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </a-card>
+          <a-card size="small" :title="$t('label.ip.v6')" style="margin-top: 15px; margin-bottom: 10px">
+            <a-row :gutter="12">
+              <a-col :md="12" :lg="12">
+                <a-form-item name="ip6gateway" ref="ip6gateway">
+                  <template #label>
+                    <tooltip-label :title="$t('label.ip6gateway')" :tooltip="apiParams.ip6gateway.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.ip6gateway"
+                    :placeholder="apiParams.ip6gateway.description"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="12" :lg="12">
+                <a-form-item name="ip6cidr" ref="ip6cidr">
+                  <template #label>
+                    <tooltip-label :title="$t('label.ip6cidr')" :tooltip="apiParams.ip6cidr.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.ip6cidr"
+                    :placeholder="apiParams.ip6cidr.description"/>
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="12">
+              <a-col :md="12" :lg="12">
+                <a-form-item name="startipv6" ref="startipv6">
+                  <template #label>
+                    <tooltip-label :title="$t('label.startipv6')" :tooltip="apiParams.startipv6.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.startipv6"
+                    :placeholder="apiParams.startipv6.description"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="12" :lg="12">
+                <a-form-item name="endipv6" ref="endipv6">
+                  <template #label>
+                    <tooltip-label :title="$t('label.endipv6')" :tooltip="apiParams.endipv6.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.endipv6"
+                    :placeholder="apiParams.endipv6.description"/>
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-form-item v-if="isVirtualRouterForAtLeastOneService" name="routeripv6" ref="routeripv6">
+              <template #label>
+                <tooltip-label :title="$t('label.routeripv6')" :tooltip="apiParams.routeripv6.description"/>
+              </template>
+              <a-input
+                v-model:value="form.routeripv6"
+                :placeholder="apiParams.routeripv6.description"/>
+            </a-form-item>
+            <a-row :gutter="12" v-if="selectedNetworkOfferingSupportsDns">
+              <a-col :md="12" :lg="12">
+                <a-form-item v-if="'ip6dns1' in apiParams" name="ip6dns1" ref="ip6dns1">
+                  <template #label>
+                    <tooltip-label :title="$t('label.ip6dns1')" :tooltip="apiParams.ip6dns1.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.ip6dns1"
+                    :placeholder="apiParams.ip6dns1.description"/>
+                </a-form-item>
+              </a-col>
+              <a-col :md="12" :lg="12">
+                <a-form-item v-if="'ip6dns2' in apiParams" name="ip6dns2" ref="ip6dns2">
+                  <template #label>
+                    <tooltip-label :title="$t('label.ip6dns2')" :tooltip="apiParams.ip6dns2.description"/>
+                  </template>
+                  <a-input
+                    v-model:value="form.ip6dns2"
+                    :placeholder="apiParams.ip6dns2.description"/>
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </a-card>
           <a-form-item name="networkdomain" ref="networkdomain">
             <template #label>
               <tooltip-label :title="$t('label.networkdomain')" :tooltip="apiParams.networkdomain.description"/>
@@ -453,6 +525,16 @@ export default {
     this.initForm()
     this.fetchData()
   },
+  computed: {
+    selectedNetworkOfferingSupportsDns () {
+      if (this.selectedNetworkOffering) {
+        const services = this.selectedNetworkOffering?.service || []
+        const dnsServices = services.filter(service => service.name === 'Dns')
+        return dnsServices && dnsServices.length === 1
+      }
+      return false
+    }
+  },
   methods: {
     initForm () {
       this.formRef = ref()
@@ -471,7 +553,7 @@ export default {
         name: [{ required: true, message: this.$t('message.error.name') }],
         displaytext: [{ required: true, message: this.$t('message.error.display.text') }],
         zoneid: [{ type: 'number', required: true, message: this.$t('message.error.select') }],
-        vlanid: [{ required: true, message: this.$t('message.please.enter.value') }],
+        vlan: [{ required: true, message: this.$t('message.please.enter.value') }],
         networkofferingid: [{ type: 'number', required: true, message: this.$t('message.error.select') }],
         domainid: [{ type: 'number', required: true, message: this.$t('message.error.select') }],
         account: [{ type: 'number', required: true, message: this.$t('message.error.select') }],
@@ -872,8 +954,8 @@ export default {
         const formRaw = toRaw(this.form)
         const values = this.handleRemoveFields(formRaw)
         if (
-          (!this.isValidTextValueForKey(values, 'ip4gateway') && !this.isValidTextValueForKey(values, 'ip4netmask') &&
-            !this.isValidTextValueForKey(values, 'startipv4') && !this.isValidTextValueForKey(values, 'endipv4') &&
+          (!this.isValidTextValueForKey(values, 'gateway') && !this.isValidTextValueForKey(values, 'netmask') &&
+            !this.isValidTextValueForKey(values, 'startip') && !this.isValidTextValueForKey(values, 'endip') &&
             !this.isValidTextValueForKey(values, 'ip6gateway') && !this.isValidTextValueForKey(values, 'ip6cidr') &&
             !this.isValidTextValueForKey(values, 'startipv6') && !this.isValidTextValueForKey(values, 'endipv6'))
         ) {
@@ -893,8 +975,8 @@ export default {
         if (this.selectedNetworkOffering.guestiptype === 'Shared') {
           params.physicalnetworkid = this.formSelectedPhysicalNetwork.id
         }
-        if (this.isValidTextValueForKey(values, 'vlanid')) {
-          params.vlan = values.vlanid
+        if (this.isValidTextValueForKey(values, 'vlan')) {
+          params.vlan = values.vlan
         }
         if (this.isValidValueForKey(values, 'bypassvlanoverlapcheck')) {
           params.bypassvlanoverlapcheck = values.bypassvlanoverlapcheck
@@ -927,43 +1009,19 @@ export default {
           params.acltype = 'account' // acl type is "account" for regular users
         }
         // IPv4 (begin)
-        if (this.isValidTextValueForKey(values, 'ip4gateway')) {
-          params.gateway = values.ip4gateway
-        }
-        if (this.isValidTextValueForKey(values, 'ip4netmask')) {
-          params.netmask = values.ip4netmask
-        }
-        if (this.isValidTextValueForKey(values, 'startipv4')) {
-          params.startip = values.startipv4
-        }
-        if (this.isValidTextValueForKey(values, 'endipv4')) {
-          params.endip = values.endipv4
-        }
-        if (this.isValidTextValueForKey(values, 'routerip')) {
-          params.routerip = values.routerip
-        }
+        var usefulFields = ['gateway', 'netmask', 'startip', 'endip', 'routerip', 'dns1', 'dns2']
         // IPv4 (end)
 
         // IPv6 (begin)
-        if (this.isValidTextValueForKey(values, 'ip6gateway')) {
-          params.ip6gateway = values.ip6gateway
-        }
-        if (this.isValidTextValueForKey(values, 'ip6cidr')) {
-          params.ip6cidr = values.ip6cidr
-        }
-        if (this.isValidTextValueForKey(values, 'startipv6')) {
-          params.startipv6 = values.startipv6
-        }
-        if (this.isValidTextValueForKey(values, 'endipv6')) {
-          params.endipv6 = values.endipv6
-        }
-        if (this.isValidTextValueForKey(values, 'routeripv6')) {
-          params.routeripv6 = values.routeripv6
-        }
+        usefulFields = [...usefulFields, 'ip6gateway', 'ip6cidr', 'startipv6', 'endipv6', 'routeripv6', 'ip6dns1', 'ip6dns2']
         // IPv6 (end)
 
-        if (this.isValidTextValueForKey(values, 'networkdomain')) {
-          params.networkdomain = values.networkdomain
+        usefulFields.push('networkdomain')
+
+        for (var field of usefulFields) {
+          if (this.isValidTextValueForKey(values, field)) {
+            params[field] = values[field]
+          }
         }
         var hideipaddressusage = this.parseBooleanValueForKey(values, 'hideipaddressusage')
         if (hideipaddressusage) {
diff --git a/ui/src/views/network/CreateVpc.vue b/ui/src/views/network/CreateVpc.vue
index 381de40c1b..e0eee169d6 100644
--- a/ui/src/views/network/CreateVpc.vue
+++ b/ui/src/views/network/CreateVpc.vue
@@ -89,12 +89,57 @@
             optionFilterProp="label"
             :filterOption="(input, option) => {
               return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-            }" >
+            }"
+            @change="handleVpcOfferingChange" >
             <a-select-option :value="offering.id" v-for="offering in vpcOfferings" :key="offering.id">
               {{ offering.name }}
             </a-select-option>
           </a-select>
         </a-form-item>
+        <a-row :gutter="12" v-if="selectedVpcOfferingSupportsDns">
+          <a-col :md="12" :lg="12">
+            <a-form-item v-if="'dns1' in apiParams" name="dns1" ref="dns1">
+              <template #label>
+                <tooltip-label :title="$t('label.dns1')" :tooltip="apiParams.dns1.description"/>
+              </template>
+              <a-input
+                v-model:value="form.dns1"
+                :placeholder="apiParams.dns1.description"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :lg="12">
+            <a-form-item v-if="'dns2' in apiParams" name="dns2" ref="dns2">
+              <template #label>
+                <tooltip-label :title="$t('label.dns2')" :tooltip="apiParams.dns2.description"/>
+              </template>
+              <a-input
+                v-model:value="form.dns2"
+                :placeholder="apiParams.dns2.description"/>
+            </a-form-item>
+          </a-col>
+        </a-row>
+        <a-row :gutter="12" v-if="selectedVpcOfferingSupportsDns">
+          <a-col :md="12" :lg="12">
+            <a-form-item v-if="selectedVpcOffering && selectedVpcOffering.internetprotocol === 'DualStack' && 'ip6dns1' in apiParams" name="ip6dns1" ref="ip6dns1">
+              <template #label>
+                <tooltip-label :title="$t('label.ip6dns1')" :tooltip="apiParams.ip6dns1.description"/>
+              </template>
+              <a-input
+                v-model:value="form.ip6dns1"
+                :placeholder="apiParams.ip6dns1.description"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :lg="12">
+            <a-form-item v-if="selectedVpcOffering && selectedVpcOffering.internetprotocol === 'DualStack' && 'ip6dns2' in apiParams" name="ip6dns2" ref="ip6dns2">
+              <template #label>
+                <tooltip-label :title="$t('label.ip6dns2')" :tooltip="apiParams.ip6dns2.description"/>
+              </template>
+              <a-input
+                v-model:value="form.ip6dns2"
+                :placeholder="apiParams.ip6dns2.description"/>
+            </a-form-item>
+          </a-col>
+        </a-row>
         <a-form-item name="start" ref="start">
           <template #label>
             <tooltip-label :title="$t('label.start')" :tooltip="apiParams.start.description"/>
@@ -127,7 +172,8 @@ export default {
       loadingZone: false,
       loadingOffering: false,
       zones: [],
-      vpcOfferings: []
+      vpcOfferings: [],
+      selectedVpcOffering: {}
     }
   },
   beforeCreate () {
@@ -137,6 +183,16 @@ export default {
     this.initForm()
     this.fetchData()
   },
+  computed: {
+    selectedVpcOfferingSupportsDns () {
+      if (this.selectedVpcOffering) {
+        const services = this.selectedVpcOffering?.service || []
+        const dnsServices = services.filter(service => service.name === 'Dns')
+        return dnsServices && dnsServices.length === 1
+      }
+      return false
+    }
+  },
   methods: {
     initForm () {
       this.formRef = ref()
@@ -181,10 +237,23 @@ export default {
       api('listVPCOfferings', { zoneid: this.form.zoneid, state: 'Enabled' }).then((reponse) => {
         this.vpcOfferings = reponse.listvpcofferingsresponse.vpcoffering
         this.form.vpcofferingid = this.vpcOfferings[0].id || ''
+        this.selectedVpcOffering = this.vpcOfferings[0] || {}
       }).finally(() => {
         this.loadingOffering = false
       })
     },
+    handleVpcOfferingChange (value) {
+      this.selectedVpcOffering = {}
+      if (!value) {
+        return
+      }
+      for (var offering of this.vpcOfferings) {
+        if (offering.id === value) {
+          this.selectedVpcOffering = offering
+          return
+        }
+      }
+    },
     closeAction () {
       this.$emit('close-action')
     },
diff --git a/ui/src/views/network/UpdateNetwork.vue b/ui/src/views/network/UpdateNetwork.vue
index f3e63b7344..cf64a96327 100644
--- a/ui/src/views/network/UpdateNetwork.vue
+++ b/ui/src/views/network/UpdateNetwork.vue
@@ -101,6 +101,52 @@
           </template>
           <a-switch v-model:checked="form.updateinsequence" />
         </a-form-item>
+        <div v-if="selectedNetworkOfferingSupportsDns">
+          <a-row :gutter="12">
+            <a-col :md="12" :lg="12">
+              <a-form-item v-if="'dns1' in apiParams" name="dns1" ref="dns1">
+                <template #label>
+                  <tooltip-label :title="$t('label.dns1')" :tooltip="apiParams.dns1.description"/>
+                </template>
+                <a-input
+                  v-model:value="form.dns1"
+                  :placeholder="apiParams.dns1.description"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :lg="12">
+              <a-form-item v-if="'dns2' in apiParams" name="dns2" ref="dns2">
+                <template #label>
+                  <tooltip-label :title="$t('label.dns2')" :tooltip="apiParams.dns2.description"/>
+                </template>
+                <a-input
+                  v-model:value="form.dns2"
+                  :placeholder="apiParams.dns2.description"/>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-row :gutter="12">
+            <a-col :md="12" :lg="12">
+              <a-form-item v-if="networkOffering && ((networkOffering.guestiptype === 'Isolated' && networkOffering.internetprotocol === 'DualStack') || (networkOffering.guestiptype === 'Shared' && resource.ip6cidr)) && 'ip6dns1' in apiParams" name="ip6dns1" ref="ip6dns1">
+                <template #label>
+                  <tooltip-label :title="$t('label.ip6dns1')" :tooltip="apiParams.ip6dns1.description"/>
+                </template>
+                <a-input
+                  v-model:value="form.ip6dns1"
+                  :placeholder="apiParams.ip6dns1.description"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :lg="12">
+              <a-form-item v-if="networkOffering && ((networkOffering.guestiptype === 'Isolated' && networkOffering.internetprotocol === 'DualStack') || (networkOffering.guestiptype === 'Shared' && resource.ip6cidr)) && 'ip6dns1' in apiParams" name="ip6dns2" ref="ip6dns2">
+                <template #label>
+                  <tooltip-label :title="$t('label.ip6dns2')" :tooltip="apiParams.ip6dns2.description"/>
+                </template>
+                <a-input
+                  v-model:value="form.ip6dns2"
+                  :placeholder="apiParams.ip6dns2.description"/>
+              </a-form-item>
+            </a-col>
+          </a-row>
+        </div>
         <a-form-item name="displaynetwork" ref="displaynetwork" v-if="isAdmin()">
           <template #label>
             <tooltip-label :title="$t('label.displaynetwork')" :tooltip="apiParams.displaynetwork.description"/>
@@ -160,7 +206,11 @@ export default {
     this.resourceValues = {
       name: this.resource.name,
       displaytext: this.resource.displaytext,
-      guestvmcidr: this.resource.cidr
+      guestvmcidr: this.resource.cidr,
+      dns1: this.resource.dns1,
+      dns2: this.resource.dns2,
+      ip6dns1: this.resource.ip6dns1,
+      ip6dns2: this.resource.ip6dns2
     }
     if (this.isUpdatingIsolatedNetwork) {
       this.resourceValues.networkdomain = this.resource.networkdomain
@@ -176,6 +226,14 @@ export default {
   computed: {
     isUpdatingIsolatedNetwork () {
       return this.resource && this.resource.type === 'Isolated'
+    },
+    selectedNetworkOfferingSupportsDns () {
+      if (this.networkOffering) {
+        const services = this.networkOffering?.service || []
+        const dnsServices = services.filter(service => service.name === 'Dns')
+        return dnsServices && dnsServices.length === 1
+      }
+      return false
     }
   },
   methods: {
@@ -200,13 +258,15 @@ export default {
     },
     fetchNetworkOfferingData () {
       this.networkOfferings = []
-      if (!this.isUpdatingIsolatedNetwork) return
       const params = {
         zoneid: this.resource.zoneid,
         state: 'Enabled',
         guestiptype: this.resource.type,
         forvpc: !!this.resource.vpcid
       }
+      if (!this.isUpdatingIsolatedNetwork) {
+        params.id = this.resource.networkofferingid
+      }
       this.networkOfferingLoading = true
       api('listNetworkOfferings', params).then(json => {
         this.networkOfferings = json.listnetworkofferingsresponse.networkoffering