You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by we...@apache.org on 2024/11/30 07:45:23 UTC

(cloudstack) branch 4.20 updated: Routed mode: minor improvements and fixes (#9697)

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

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


The following commit(s) were added to refs/heads/4.20 by this push:
     new 22a66044918 Routed mode: minor improvements and fixes (#9697)
22a66044918 is described below

commit 22a66044918ce37370ee4aa01ae1e20fbc41f581
Author: Wei Zhou <we...@apache.org>
AuthorDate: Sat Nov 30 08:45:15 2024 +0100

    Routed mode: minor improvements and fixes (#9697)
    
    * Routed: add global setting to enable/disable routed mode
    
    * Routed: add unit tests
    
    * Routed: add unit tests RoutedIpv4ManagerImplTest
    
    * PR9697: fix end of files lint error
    
    * PR9697: fix unit tests error with JDK17
    
    * Routed: do not show ROUTED mode when create network/vpc offering if routed is disabled
    
    * Routed: check if routed network is enabled when create ipv4 subnet/bgp peer/ASN range/network/vpc
    
    * Routed: UI bug fix and improvements
    
    * Routed: apply available BGP peers when VR is restarted
---
 api/src/main/java/com/cloud/bgp/BGPService.java    |    5 +
 .../org/apache/cloudstack/api/ApiConstants.java    |    1 +
 .../cloudstack/api/response/ZoneResponse.java      |   13 +
 .../cloudstack/network/RoutedIpv4Manager.java      |    9 +
 .../cloud/api/query/dao/DataCenterJoinDaoImpl.java |    3 +
 .../main/java/com/cloud/bgp/BGPServiceImpl.java    |   59 +-
 .../configuration/ConfigurationManagerImpl.java    |   11 +
 .../java/com/cloud/network/NetworkServiceImpl.java |   13 +-
 .../router/VirtualNetworkApplianceManagerImpl.java |   13 +-
 .../java/com/cloud/network/vpc/VpcManagerImpl.java |   21 +-
 .../com/cloud/server/ManagementServerImpl.java     |   11 -
 .../cloudstack/network/RoutedIpv4ManagerImpl.java  |   75 +-
 .../java/com/cloud/bgp/BGPServiceImplTest.java     |  133 ++-
 .../com/cloud/network/NetworkServiceImplTest.java  |   92 +-
 .../network/element/VirtualRouterElementTest.java  |   56 +
 .../network/router/CommandSetupHelperTest.java     |  110 +-
 .../VirtualNetworkApplianceManagerImplTest.java    |   63 +
 .../com/cloud/network/vpc/VpcManagerImplTest.java  |   27 +
 .../network/RoutedIpv4ManagerImplTest.java         | 1217 ++++++++++++++++++++
 ui/src/config/section/infra/zones.js               |    9 +-
 ui/src/config/section/network.js                   |   15 +-
 .../views/network/CreateIpv4SubnetForNetwork.vue   |    1 +
 ui/src/views/network/CreateIsolatedNetworkForm.vue |    5 +-
 ui/src/views/network/CreateVpc.vue                 |    4 +
 ui/src/views/offering/AddNetworkOffering.vue       |   13 +
 ui/src/views/offering/AddVpcOffering.vue           |   13 +
 26 files changed, 1902 insertions(+), 90 deletions(-)

diff --git a/api/src/main/java/com/cloud/bgp/BGPService.java b/api/src/main/java/com/cloud/bgp/BGPService.java
index 935237092dd..61d149f2847 100644
--- a/api/src/main/java/com/cloud/bgp/BGPService.java
+++ b/api/src/main/java/com/cloud/bgp/BGPService.java
@@ -21,6 +21,7 @@ import com.cloud.network.Network;
 import com.cloud.network.vpc.Vpc;
 import com.cloud.utils.Pair;
 import org.apache.cloudstack.api.command.user.bgp.ListASNumbersCmd;
+import org.apache.cloudstack.network.BgpPeer;
 
 import java.util.List;
 
@@ -36,4 +37,8 @@ public interface BGPService {
     boolean applyBgpPeers(Network network, boolean continueOnError) throws ResourceUnavailableException;
 
     boolean applyBgpPeers(Vpc vpc, boolean continueOnError) throws ResourceUnavailableException;
+
+    List<? extends BgpPeer> getBgpPeersForNetwork(Network network);
+
+    List<? extends BgpPeer> getBgpPeersForVpc(Vpc vpc);
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index bb16b0ff90d..6df8d7f5f18 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -986,6 +986,7 @@ public class ApiConstants {
     public static final String ACL_NAME = "aclname";
     public static final String NUMBER = "number";
     public static final String IS_DYNAMICALLY_SCALABLE = "isdynamicallyscalable";
+    public static final String ROUTED_MODE_ENABLED = "routedmodeenabled";
     public static final String ROUTING = "isrouting";
     public static final String ROUTING_MODE = "routingmode";
     public static final String MAX_CONNECTIONS = "maxconnections";
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java
index 143dfad0eaf..4a5279753a1 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java
@@ -157,6 +157,11 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso
     @Param(description = "AS Number Range")
     private String asnRange;
 
+    @SerializedName(ApiConstants.ROUTED_MODE_ENABLED)
+    @Param(description = "true, if routed network/vpc is enabled", since = "4.20.1")
+    private boolean routedModeEnabled = false;
+
+
     public ZoneResponse() {
         tags = new LinkedHashSet<ResourceTagResponse>();
     }
@@ -412,4 +417,12 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso
     public String getAsnRange() {
         return asnRange;
     }
+
+    public boolean isRoutedModeEnabled() {
+        return routedModeEnabled;
+    }
+
+    public void setRoutedModeEnabled(boolean routedModeEnabled) {
+        this.routedModeEnabled = routedModeEnabled;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/network/RoutedIpv4Manager.java b/api/src/main/java/org/apache/cloudstack/network/RoutedIpv4Manager.java
index 2f704e9f47d..221a550ad63 100644
--- a/api/src/main/java/org/apache/cloudstack/network/RoutedIpv4Manager.java
+++ b/api/src/main/java/org/apache/cloudstack/network/RoutedIpv4Manager.java
@@ -57,6 +57,13 @@ import java.util.List;
 
 public interface RoutedIpv4Manager extends PluggableService, Configurable {
 
+    ConfigKey<Boolean> RoutedNetworkVpcEnabled = new ConfigKey<>(ConfigKey.CATEGORY_NETWORK, Boolean.class,
+            "routed.network.vpc.enabled",
+            "true",
+            "If true, the Routed network and VPC are enabled in the zone.",
+            true,
+            ConfigKey.Scope.Zone);
+
     ConfigKey<Integer> RoutedNetworkIPv4MaxCidrSize = new ConfigKey<>(ConfigKey.CATEGORY_NETWORK, Integer.class,
             "routed.network.ipv4.max.cidr.size", "30", "The maximum value of the cidr size for isolated networks in ROUTED mode",
             true, ConfigKey.Scope.Account);
@@ -196,4 +203,6 @@ public interface RoutedIpv4Manager extends PluggableService, Configurable {
     void removeBgpPeersByAccountId(long accountId);
 
     void removeBgpPeersByDomainId(long domainId);
+
+    Boolean isRoutedNetworkVpcEnabled(long zoneId);
 }
diff --git a/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java
index 2b3be728bd3..d457f8f7931 100644
--- a/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java
@@ -34,6 +34,7 @@ import org.apache.cloudstack.api.response.ResourceIconResponse;
 import org.apache.cloudstack.api.response.ResourceTagResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.network.RoutedIpv4Manager;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.stereotype.Component;
@@ -141,6 +142,8 @@ public class DataCenterJoinDaoImpl extends GenericDaoBase<DataCenterJoinVO, Long
         String asRange = asNumberRange.stream().map(range -> range.getStartASNumber() + "-" + range.getEndASNumber()).collect(Collectors.joining(", "));
         zoneResponse.setAsnRange(asRange);
 
+        zoneResponse.setRoutedModeEnabled(RoutedIpv4Manager.RoutedNetworkVpcEnabled.valueIn(dataCenter.getId()));
+
         zoneResponse.setResourceDetails(ApiDBUtils.getResourceDetails(dataCenter.getId(), ResourceObjectType.Zone));
         zoneResponse.setHasAnnotation(annotationDao.hasAnnotations(dataCenter.getUuid(), AnnotationService.EntityType.ZONE.name(),
                 _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())));
diff --git a/server/src/main/java/com/cloud/bgp/BGPServiceImpl.java b/server/src/main/java/com/cloud/bgp/BGPServiceImpl.java
index 0e6ae7ade1a..672c6b7cd60 100644
--- a/server/src/main/java/com/cloud/bgp/BGPServiceImpl.java
+++ b/server/src/main/java/com/cloud/bgp/BGPServiceImpl.java
@@ -24,6 +24,7 @@ import com.cloud.dc.dao.ASNumberRangeDao;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.domain.Domain;
 import com.cloud.domain.dao.DomainDao;
+import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.network.Network;
 import com.cloud.network.NetworkModel;
@@ -54,6 +55,7 @@ import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.cloudstack.api.command.user.bgp.ListASNumbersCmd;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.network.BgpPeer;
 import org.apache.cloudstack.network.BgpPeerVO;
 import org.apache.cloudstack.network.RoutedIpv4Manager;
 import org.apache.cloudstack.network.dao.BgpPeerDao;
@@ -116,6 +118,9 @@ public class BGPServiceImpl implements BGPService {
             LOGGER.error(msg);
             throw new InvalidParameterException(msg);
         }
+        if (!routedIpv4Manager.isRoutedNetworkVpcEnabled(zoneId)) {
+            throw new InvalidParameterValueException("Cannot create ASN range as Routed networks and VPCs are not enabled for the zone.");
+        }
         if (startASNumber > endASNumber) {
             String msg = "Please specify a valid AS Number range";
             LOGGER.error(msg);
@@ -391,19 +396,7 @@ public class BGPServiceImpl implements BGPService {
         if (gatewayProviderStr != null) {
             NetworkElement provider = networkModel.getElementImplementingProvider(gatewayProviderStr);
             if (provider != null && provider instanceof BgpServiceProvider) {
-                List<BgpPeerVO> bgpPeers;
-                if (network.getVpcId() != null) {
-                    bgpPeers = bgpPeerDao.listNonRevokeByVpcId(network.getVpcId());
-                } else {
-                    bgpPeers = bgpPeerDao.listNonRevokeByNetworkId(network.getId());
-                }
-                if (CollectionUtils.isEmpty(bgpPeers)) {
-                    Account owner = accountDao.findByIdIncludingRemoved(network.getAccountId());
-                    List<Long> bgpPeerIds = routedIpv4Manager.getBgpPeerIdsForAccount(owner, network.getDataCenterId());
-                    bgpPeers = bgpPeerIds.stream()
-                            .map(bgpPeerId -> bgpPeerDao.findById(bgpPeerId))
-                            .collect(Collectors.toList());
-                }
+                List<? extends BgpPeer> bgpPeers = getBgpPeersForNetwork(network);
                 LOGGER.debug(String.format("Applying BPG Peers for network [%s]: [%s]", network, bgpPeers));
                 return ((BgpServiceProvider) provider).applyBgpPeers(null, network, bgpPeers);
             }
@@ -420,14 +413,7 @@ public class BGPServiceImpl implements BGPService {
         if (gatewayProviderStr != null) {
             NetworkElement provider = networkModel.getElementImplementingProvider(gatewayProviderStr);
             if (provider != null && provider instanceof BgpServiceProvider) {
-                List<BgpPeerVO> bgpPeers = bgpPeerDao.listNonRevokeByVpcId(vpc.getId());
-                if (CollectionUtils.isEmpty(bgpPeers)) {
-                    Account owner = accountDao.findByIdIncludingRemoved(vpc.getAccountId());
-                    List<Long> bgpPeerIds = routedIpv4Manager.getBgpPeerIdsForAccount(owner, vpc.getZoneId());
-                    bgpPeers = bgpPeerIds.stream()
-                            .map(bgpPeerId -> bgpPeerDao.findById(bgpPeerId))
-                            .collect(Collectors.toList());
-                }
+                List<? extends BgpPeer> bgpPeers = getBgpPeersForVpc(vpc);
                 LOGGER.debug(String.format("Applying BPG Peers for VPC [%s]: [%s]", vpc, bgpPeers));
                 return ((BgpServiceProvider) provider).applyBgpPeers(vpc, null, bgpPeers);
 
@@ -435,4 +421,35 @@ public class BGPServiceImpl implements BGPService {
         }
         return true;
     }
+
+    @Override
+    public List<? extends BgpPeer> getBgpPeersForNetwork(Network network) {
+        List<BgpPeerVO> bgpPeers;
+        if (network.getVpcId() != null) {
+            bgpPeers = bgpPeerDao.listNonRevokeByVpcId(network.getVpcId());
+        } else {
+            bgpPeers = bgpPeerDao.listNonRevokeByNetworkId(network.getId());
+        }
+        if (CollectionUtils.isEmpty(bgpPeers)) {
+            Account owner = accountDao.findByIdIncludingRemoved(network.getAccountId());
+            List<Long> bgpPeerIds = routedIpv4Manager.getBgpPeerIdsForAccount(owner, network.getDataCenterId());
+            bgpPeers = bgpPeerIds.stream()
+                    .map(bgpPeerId -> bgpPeerDao.findById(bgpPeerId))
+                    .collect(Collectors.toList());
+        }
+        return bgpPeers;
+    }
+
+    @Override
+    public List<? extends BgpPeer> getBgpPeersForVpc(Vpc vpc) {
+        List<BgpPeerVO> bgpPeers = bgpPeerDao.listNonRevokeByVpcId(vpc.getId());
+        if (CollectionUtils.isEmpty(bgpPeers)) {
+            Account owner = accountDao.findByIdIncludingRemoved(vpc.getAccountId());
+            List<Long> bgpPeerIds = routedIpv4Manager.getBgpPeerIdsForAccount(owner, vpc.getZoneId());
+            bgpPeers = bgpPeerIds.stream()
+                    .map(bgpPeerId -> bgpPeerDao.findById(bgpPeerId))
+                    .collect(Collectors.toList());
+        }
+        return bgpPeers;
+    }
 }
diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index 25cbd10de0a..4a9e03ba67e 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -106,6 +106,7 @@ import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
 import org.apache.cloudstack.framework.messagebus.MessageBus;
 import org.apache.cloudstack.framework.messagebus.MessageSubscriber;
 import org.apache.cloudstack.framework.messagebus.PublishScope;
+import org.apache.cloudstack.network.RoutedIpv4Manager;
 import org.apache.cloudstack.query.QueryService;
 import org.apache.cloudstack.region.PortableIp;
 import org.apache.cloudstack.region.PortableIpDao;
@@ -6673,6 +6674,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
                 throw new InvalidParameterValueException("networkMode should be set only for Isolated network offerings");
             }
             if (NetworkOffering.NetworkMode.ROUTED.equals(networkMode)) {
+                if (!RoutedIpv4Manager.RoutedNetworkVpcEnabled.value()) {
+                    throw new InvalidParameterValueException(String.format("Configuration %s needs to be enabled for Routed networks", RoutedIpv4Manager.RoutedNetworkVpcEnabled.key()));
+                }
+                if (zoneIds != null) {
+                    for (Long zoneId: zoneIds) {
+                        if (!RoutedIpv4Manager.RoutedNetworkVpcEnabled.valueIn(zoneId)) {
+                            throw new InvalidParameterValueException(String.format("Configuration %s needs to be enabled for Routed networks in zone (ID: %s)", RoutedIpv4Manager.RoutedNetworkVpcEnabled.key(), zoneId));
+                        }
+                    }
+                }
                 boolean useVirtualRouterOnly = true;
                 for (Service service : serviceProviderMap.keySet()) {
                     Set<Provider> providers = serviceProviderMap.get(service);
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index 2ccd5fdd820..ffb0be83494 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -1384,7 +1384,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
         }
     }
 
-    void validateNetworkCidrSize(Account caller, Integer cidrSize, String cidr, NetworkOffering networkOffering, long accountId) {
+    void validateNetworkCidrSize(Account caller, Integer cidrSize, String cidr, NetworkOffering networkOffering, long accountId, long zoneId) {
         if (!GuestType.Isolated.equals(networkOffering.getGuestType())) {
             if (cidrSize != null) {
                 throw new InvalidParameterValueException("network cidr size is only applicable on Isolated networks");
@@ -1405,11 +1405,11 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
             if (cidrSize == null) {
                 throw new InvalidParameterValueException("network cidr or cidr size is required for Isolated networks with ROUTED mode");
             }
-            Integer maxCidrSize = routedIpv4Manager.RoutedNetworkIPv4MaxCidrSize.valueIn(accountId);
+            Integer maxCidrSize = RoutedIpv4Manager.RoutedNetworkIPv4MaxCidrSize.valueIn(accountId);
             if (cidrSize > maxCidrSize) {
                 throw new InvalidParameterValueException("network cidr size cannot be bigger than maximum cidr size " + maxCidrSize);
             }
-            Integer minCidrSize = routedIpv4Manager.RoutedNetworkIPv4MinCidrSize.valueIn(accountId);
+            Integer minCidrSize = RoutedIpv4Manager.RoutedNetworkIPv4MinCidrSize.valueIn(accountId);
             if (cidrSize < minCidrSize) {
                 throw new InvalidParameterValueException("network cidr size cannot be smaller than minimum cidr size " + minCidrSize);
             }
@@ -1651,11 +1651,16 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
             }
         }
 
+        if (NetworkOffering.NetworkMode.ROUTED.equals(ntwkOff.getNetworkMode())
+                && !routedIpv4Manager.isRoutedNetworkVpcEnabled(zone.getId())) {
+            throw new InvalidParameterValueException("Routed network is not enabled in this zone");
+        }
+
         if (isNonVpcNetworkSupportingDynamicRouting(ntwkOff) && ntwkOff.isSpecifyAsNumber() && asNumber == null) {
             throw new InvalidParameterValueException("AS number is required for the network but not passed.");
         }
 
-        validateNetworkCidrSize(caller, networkCidrSize, cidr, ntwkOff, owner.getAccountId());
+        validateNetworkCidrSize(caller, networkCidrSize, cidr, ntwkOff, owner.getAccountId(), zone.getId());
 
         validateSharedNetworkRouterIPs(gateway, startIP, endIP, netmask, routerIPv4, routerIPv6, startIPv6, endIPv6, ip6Cidr, ntwkOff);
 
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 8f07fcfca3b..8a28eeabe21 100644
--- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
@@ -65,10 +65,8 @@ import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
 import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO;
 import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
-import org.apache.cloudstack.network.BgpPeerVO;
+import org.apache.cloudstack.network.BgpPeer;
 import org.apache.cloudstack.network.RoutedIpv4Manager;
-import org.apache.cloudstack.network.dao.BgpPeerDao;
-import org.apache.cloudstack.network.dao.BgpPeerNetworkMapDao;
 import org.apache.cloudstack.network.topology.NetworkTopology;
 import org.apache.cloudstack.network.topology.NetworkTopologyContext;
 import org.apache.cloudstack.utils.CloudStackVersion;
@@ -114,6 +112,7 @@ import com.cloud.api.query.dao.DomainRouterJoinDao;
 import com.cloud.api.query.dao.UserVmJoinDao;
 import com.cloud.api.query.vo.DomainRouterJoinVO;
 import com.cloud.api.query.vo.UserVmJoinVO;
+import com.cloud.bgp.BGPService;
 import com.cloud.cluster.ManagementServerHostVO;
 import com.cloud.cluster.dao.ManagementServerHostDao;
 import com.cloud.configuration.Config;
@@ -348,9 +347,7 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
     @Inject
     RoutedIpv4Manager routedIpv4Manager;
     @Inject
-    BgpPeerDao bgpPeerDao;
-    @Inject
-    BgpPeerNetworkMapDao bgpPeerNetworkMapDao;
+    BGPService bgpService;
 
     private int _routerRamSize;
     private int _routerCpuMHz;
@@ -2508,12 +2505,12 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
         if (guestNetwork.getVpcId() != null) {
             final Vpc vpc = _vpcDao.findById(guestNetwork.getVpcId());
             if (routedIpv4Manager.isDynamicRoutedVpc(vpc)) {
-                final List<BgpPeerVO> bgpPeers = bgpPeerDao.listNonRevokeByVpcId(guestNetwork.getVpcId());
+                List<? extends BgpPeer> bgpPeers = bgpService.getBgpPeersForVpc(vpc);
                 _commandSetupHelper.createBgpPeersCommands(bgpPeers, router, cmds, guestNetwork);
             }
         } else {
             if (routedIpv4Manager.isDynamicRoutedNetwork(guestNetwork)) {
-                final List<BgpPeerVO> bgpPeers = bgpPeerDao.listNonRevokeByNetworkId(guestNetworkId);
+                List<? extends BgpPeer> bgpPeers = bgpService.getBgpPeersForNetwork(guestNetwork);
                 _commandSetupHelper.createBgpPeersCommands(bgpPeers, router, cmds, guestNetwork);
             }
         }
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 b956ccc16ed..6d24c0fe700 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -500,6 +500,18 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
             }
             networkMode = NetworkOffering.NetworkMode.valueOf(networkModeStr);
         }
+        if (NetworkOffering.NetworkMode.ROUTED.equals(networkMode)) {
+            if (!RoutedIpv4Manager.RoutedNetworkVpcEnabled.value()) {
+                throw new InvalidParameterValueException(String.format("Configuration %s needs to be enabled for Routed VPCs", RoutedIpv4Manager.RoutedNetworkVpcEnabled.key()));
+            }
+            if (zoneIds != null) {
+                for (Long zoneId: zoneIds) {
+                    if (!RoutedIpv4Manager.RoutedNetworkVpcEnabled.valueIn(zoneId)) {
+                        throw new InvalidParameterValueException(String.format("Configuration %s needs to be enabled for Routed VPCs in zone (ID: %s)", RoutedIpv4Manager.RoutedNetworkVpcEnabled.key(), zoneId));
+                    }
+                }
+            }
+        }
         boolean specifyAsNumber = cmd.getSpecifyAsNumber();
         String routingModeString = cmd.getRoutingMode();
 
@@ -1161,12 +1173,17 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
             throw ex;
         }
 
+        if (NetworkOffering.NetworkMode.ROUTED.equals(vpcOff.getNetworkMode())
+                && !routedIpv4Manager.RoutedNetworkVpcEnabled.valueIn(zoneId)) {
+            throw new InvalidParameterValueException("Routed VPC is not enabled in this zone");
+        }
+
         if (NetworkOffering.RoutingMode.Dynamic.equals(vpcOff.getRoutingMode()) && vpcOff.isSpecifyAsNumber() && asNumber == null) {
             throw new InvalidParameterValueException("AS number is required for the VPC but not passed.");
         }
 
         // Validate VPC cidr/cidrsize
-        validateVpcCidrSize(caller, owner.getAccountId(), vpcOff, cidr, cidrSize);
+        validateVpcCidrSize(caller, owner.getAccountId(), vpcOff, cidr, cidrSize, zoneId);
 
         // Validate BGP peers
         if (CollectionUtils.isNotEmpty(bgpPeerIds)) {
@@ -1251,7 +1268,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
         return newVpc;
     }
 
-    private void validateVpcCidrSize(Account caller, long accountId, VpcOffering vpcOffering, String cidr, Integer cidrSize) {
+    private void validateVpcCidrSize(Account caller, long accountId, VpcOffering vpcOffering, String cidr, Integer cidrSize, long zoneId) {
         if (ObjectUtils.allNull(cidr, cidrSize)) {
             throw new InvalidParameterValueException("VPC cidr or cidr size must be specified");
         }
diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
index 87b3dd3cbd9..2062ee1e94d 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -68,11 +68,6 @@ import org.apache.cloudstack.api.command.admin.affinitygroup.UpdateVMAffinityGro
 import org.apache.cloudstack.api.command.admin.alert.GenerateAlertCmd;
 import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd;
 import org.apache.cloudstack.api.command.admin.autoscale.DeleteCounterCmd;
-import org.apache.cloudstack.api.command.admin.bgp.CreateASNRangeCmd;
-import org.apache.cloudstack.api.command.admin.bgp.DeleteASNRangeCmd;
-import org.apache.cloudstack.api.command.admin.bgp.ListASNRangesCmd;
-import org.apache.cloudstack.api.command.user.bgp.ListASNumbersCmd;
-import org.apache.cloudstack.api.command.admin.bgp.ReleaseASNumberCmd;
 import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd;
 import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd;
 import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
@@ -4017,12 +4012,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(RemoveSecondaryStorageSelectorCmd.class);
         cmdList.add(ListAffectedVmsForStorageScopeChangeCmd.class);
 
-        cmdList.add(CreateASNRangeCmd.class);
-        cmdList.add(ListASNRangesCmd.class);
-        cmdList.add(DeleteASNRangeCmd.class);
-        cmdList.add(ListASNumbersCmd.class);
-        cmdList.add(ReleaseASNumberCmd.class);
-
         // Out-of-band management APIs for admins
         cmdList.add(EnableOutOfBandManagementForHostCmd.class);
         cmdList.add(DisableOutOfBandManagementForHostCmd.class);
diff --git a/server/src/main/java/org/apache/cloudstack/network/RoutedIpv4ManagerImpl.java b/server/src/main/java/org/apache/cloudstack/network/RoutedIpv4ManagerImpl.java
index bbad93737f1..ab05895b8d2 100644
--- a/server/src/main/java/org/apache/cloudstack/network/RoutedIpv4ManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/network/RoutedIpv4ManagerImpl.java
@@ -57,6 +57,10 @@ import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.NetUtils;
 
+import org.apache.cloudstack.api.command.admin.bgp.CreateASNRangeCmd;
+import org.apache.cloudstack.api.command.admin.bgp.DeleteASNRangeCmd;
+import org.apache.cloudstack.api.command.admin.bgp.ListASNRangesCmd;
+import org.apache.cloudstack.api.command.admin.bgp.ReleaseASNumberCmd;
 import org.apache.cloudstack.api.command.admin.network.CreateIpv4SubnetForZoneCmd;
 import org.apache.cloudstack.api.command.admin.network.CreateIpv4SubnetForGuestNetworkCmd;
 import org.apache.cloudstack.api.command.admin.network.DedicateIpv4SubnetForZoneCmd;
@@ -74,6 +78,7 @@ import org.apache.cloudstack.api.command.admin.network.bgp.DeleteBgpPeerCmd;
 import org.apache.cloudstack.api.command.admin.network.bgp.ListBgpPeersCmd;
 import org.apache.cloudstack.api.command.admin.network.bgp.ReleaseDedicatedBgpPeerCmd;
 import org.apache.cloudstack.api.command.admin.network.bgp.UpdateBgpPeerCmd;
+import org.apache.cloudstack.api.command.user.bgp.ListASNumbersCmd;
 import org.apache.cloudstack.api.command.user.network.routing.CreateRoutingFirewallRuleCmd;
 import org.apache.cloudstack.api.command.user.network.routing.DeleteRoutingFirewallRuleCmd;
 import org.apache.cloudstack.api.command.user.network.routing.ListRoutingFirewallRulesCmd;
@@ -154,6 +159,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
     @Override
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey[] {
+                RoutedNetworkVpcEnabled,
                 RoutedNetworkIPv4MaxCidrSize, RoutedNetworkIPv4MinCidrSize, RoutedIPv4NetworkCidrAutoAllocationEnabled,
                 RoutedVpcIPv4MaxCidrSize, RoutedVpcIPv4MinCidrSize, UseSystemBgpPeers
         };
@@ -162,19 +168,25 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
     @Override
     public List<Class<?>> getCommands() {
         final List<Class<?>> cmdList = new ArrayList<Class<?>>();
+        if (!RoutedNetworkVpcEnabled.value()) {
+            return cmdList;
+        }
         cmdList.add(CreateIpv4SubnetForZoneCmd.class);
         cmdList.add(DeleteIpv4SubnetForZoneCmd.class);
         cmdList.add(ListIpv4SubnetsForZoneCmd.class);
         cmdList.add(UpdateIpv4SubnetForZoneCmd.class);
         cmdList.add(DedicateIpv4SubnetForZoneCmd.class);
         cmdList.add(ReleaseDedicatedIpv4SubnetForZoneCmd.class);
+
         cmdList.add(CreateIpv4SubnetForGuestNetworkCmd.class);
         cmdList.add(ListIpv4SubnetsForGuestNetworkCmd.class);
         cmdList.add(DeleteIpv4SubnetForGuestNetworkCmd.class);
+
         cmdList.add(CreateRoutingFirewallRuleCmd.class);
         cmdList.add(ListRoutingFirewallRulesCmd.class);
         cmdList.add(UpdateRoutingFirewallRuleCmd.class);
         cmdList.add(DeleteRoutingFirewallRuleCmd.class);
+
         cmdList.add(CreateBgpPeerCmd.class);
         cmdList.add(DeleteBgpPeerCmd.class);
         cmdList.add(ListBgpPeersCmd.class);
@@ -183,6 +195,13 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         cmdList.add(ReleaseDedicatedBgpPeerCmd.class);
         cmdList.add(ChangeBgpPeersForNetworkCmd.class);
         cmdList.add(ChangeBgpPeersForVpcCmd.class);
+
+        cmdList.add(CreateASNRangeCmd.class);
+        cmdList.add(ListASNRangesCmd.class);
+        cmdList.add(DeleteASNRangeCmd.class);
+        cmdList.add(ListASNumbersCmd.class);
+        cmdList.add(ReleaseASNumberCmd.class);
+
         return cmdList;
     }
 
@@ -198,6 +217,8 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
             throw new InvalidParameterValueException("Invalid IPv4 subnet: " + subnet);
         }
 
+        checkIfRoutedNetworkVpcEnabled(zoneId);
+
         // check conflicts
         List<DataCenterIpv4GuestSubnetVO> existingSubnets = dataCenterIpv4GuestSubnetDao.listByDataCenterId(zoneId);
         checkConflicts(existingSubnets, subnet, null);
@@ -319,7 +340,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         return dataCenterIpv4GuestSubnetDao.findById(subnetId);
     }
 
-    private void checkConflicts(List<DataCenterIpv4GuestSubnetVO> existingSubnets, String newSubnet, Long ignoreSubnetId) {
+    protected void checkConflicts(List<DataCenterIpv4GuestSubnetVO> existingSubnets, String newSubnet, Long ignoreSubnetId) {
         for (DataCenterIpv4GuestSubnetVO existing : existingSubnets) {
             if ((ignoreSubnetId == null || existing.getId() != ignoreSubnetId) && NetUtils.isNetworksOverlap(existing.getSubnet(), newSubnet)) {
                 throw new InvalidParameterValueException(String.format("Existing zone subnet %s has overlap with: %s", existing.getSubnet(), newSubnet));
@@ -553,11 +574,6 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
                 response.setParentSubnet(parent.getSubnet());
                 zoneId = parent.getDataCenterId();
             }
-        } else if (subnet.getNetworkId() != null) {
-            Network network = ApiDBUtils.findNetworkById(subnet.getNetworkId());
-            if (network != null) {
-                zoneId = network.getDataCenterId();
-            }
         }
         if (zoneId != null) {
             DataCenter zone = ApiDBUtils.findZoneById(zoneId);
@@ -590,7 +606,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         return getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(vpcCidrSize, vpc.getDomainId(), vpc.getAccountId(), vpc.getZoneId());
     }
 
-    private Ipv4GuestSubnetNetworkMap getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, Long ownerDomainId, Long ownerAccountId, Long zoneId) {
+    protected Ipv4GuestSubnetNetworkMap getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, Long ownerDomainId, Long ownerAccountId, Long zoneId) {
         validateNetworkCidrSize(ownerAccountId, cidrSize);
         List<DataCenterIpv4GuestSubnetVO> subnets = getZoneSubnetsForAccount(ownerDomainId, ownerAccountId, zoneId);
         for (DataCenterIpv4GuestSubnetVO subnet : subnets) {
@@ -602,7 +618,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         return null;
     }
 
-    private Ipv4GuestSubnetNetworkMap getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, DataCenterIpv4GuestSubnetVO subnet) {
+    protected Ipv4GuestSubnetNetworkMap getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(Integer cidrSize, DataCenterIpv4GuestSubnetVO subnet) {
         Ipv4GuestSubnetNetworkMap map = ipv4GuestSubnetNetworkMapDao.findFirstAvailable(subnet.getId(), cidrSize);
         if (map != null) {
             return map;
@@ -615,7 +631,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         return null;
     }
 
-    private void getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(String networkCidr, Long ownerDomainId, Long ownerAccountId, Long zoneId) {
+    protected void getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(String networkCidr, Long ownerDomainId, Long ownerAccountId, Long zoneId) {
         Ipv4GuestSubnetNetworkMapVO subnetMap = ipv4GuestSubnetNetworkMapDao.findBySubnet(networkCidr);
         if (subnetMap != null) {
             // check if the subnet is in use
@@ -650,7 +666,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         }
     }
 
-    private DataCenterIpv4GuestSubnet getParentOfNetworkCidr(Long zoneId, String networkCidr) {
+    protected DataCenterIpv4GuestSubnet getParentOfNetworkCidr(Long zoneId, String networkCidr) {
         List<DataCenterIpv4GuestSubnetVO> existingSubnets = dataCenterIpv4GuestSubnetDao.listByDataCenterId(zoneId);
         for (DataCenterIpv4GuestSubnetVO existing : existingSubnets) {
             if (NetUtils.isNetworkAWithinNetworkB(networkCidr, existing.getSubnet())) {
@@ -689,14 +705,22 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
 
     private List<DataCenterIpv4GuestSubnetVO> getZoneSubnetsForAccount(long domainId, long accountId, long zoneId) {
         // Get dedicated guest subnets for the account
-        List<DataCenterIpv4GuestSubnetVO> subnets = dataCenterIpv4GuestSubnetDao.listByDataCenterIdAndAccountId(zoneId, accountId);
+        List<DataCenterIpv4GuestSubnetVO> subnets = new ArrayList<>();
+        subnets.addAll(dataCenterIpv4GuestSubnetDao.listByDataCenterIdAndAccountId(zoneId, accountId));
         subnets.addAll(dataCenterIpv4GuestSubnetDao.listByDataCenterIdAndDomainId(zoneId, domainId));
         // Get non-dedicated zone guest subnets for the account
         subnets.addAll(dataCenterIpv4GuestSubnetDao.listNonDedicatedByDataCenterId(zoneId));
         return subnets;
     }
 
-    private Ipv4GuestSubnetNetworkMap createIpv4SubnetFromParentSubnet(DataCenterIpv4GuestSubnet parent, Integer networkCidrSize) {
+    protected Ipv4GuestSubnetNetworkMap createIpv4SubnetFromParentSubnet(DataCenterIpv4GuestSubnet parent, Integer networkCidrSize) {
+        String networkCidr = createIpv4SubnetStringFromParentSubnet(parent, networkCidrSize);
+        // create DB record
+        Ipv4GuestSubnetNetworkMapVO subnetMap = new Ipv4GuestSubnetNetworkMapVO(parent.getId(), NetUtils.transformCidr(networkCidr), null, State.Free);
+        return ipv4GuestSubnetNetworkMapDao.persist(subnetMap);
+    }
+
+    protected String createIpv4SubnetStringFromParentSubnet(DataCenterIpv4GuestSubnet parent, Integer networkCidrSize) {
         DataCenterIpv4GuestSubnetVO subnetVO = dataCenterIpv4GuestSubnetDao.findById(parent.getId());
         if (subnetVO == null) {
             throw new InvalidParameterValueException(String.format("Invalid subnet ID: %s", parent.getId()));
@@ -733,9 +757,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         if (networkCidr == null) {
             throw new CloudRuntimeException("Failed to automatically allocate a subnet with specified cidrsize");
         }
-        // create DB record
-        Ipv4GuestSubnetNetworkMapVO subnetMap = new Ipv4GuestSubnetNetworkMapVO(parent.getId(), NetUtils.transformCidr(networkCidr), null, State.Free);
-        return ipv4GuestSubnetNetworkMapDao.persist(subnetMap);
+        return networkCidr;
     }
 
     private String getFreeNetworkCidr(List<Pair<Long, Integer>> subnetsInFreeIpRanges, int networkCidrSize) {
@@ -752,7 +774,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         return null;
     }
 
-    private Ipv4GuestSubnetNetworkMap createIpv4SubnetFromParentSubnet(DataCenterIpv4GuestSubnet parent, String networkCidr) {
+    protected Ipv4GuestSubnetNetworkMap createIpv4SubnetFromParentSubnet(DataCenterIpv4GuestSubnet parent, String networkCidr) {
         // Validate the network cidr
         if (!NetUtils.isNetworkAWithinNetworkB(networkCidr, parent.getSubnet())) {
             throw new InvalidParameterValueException(String.format("networkCidr %s is not within parent cidr: %s", networkCidr, parent.getSubnet()));
@@ -941,9 +963,11 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         }
         if (!FirewallRule.Purpose.Firewall.equals(rule.getPurpose())) {
             logger.error(String.format("Cannot apply routing firewall rule with ID: %d as purpose %s is not %s", id, rule.getPurpose(), FirewallRule.Purpose.Firewall));
+            return false;
         }
         logger.debug(String.format("Applying routing firewall rules for rule with ID: %s", rule.getUuid()));
-        List<FirewallRuleVO> rules = firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), rule.getPurpose(), FirewallRule.TrafficType.Egress);
+        List<FirewallRuleVO> rules = new ArrayList<>();
+        rules.addAll(firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), rule.getPurpose(), FirewallRule.TrafficType.Egress));
         rules.addAll(firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(), rule.getPurpose(), FirewallRule.TrafficType.Ingress));
         return firewallManager.applyFirewallRules(rules, false, CallContext.current().getCallingAccount());
     }
@@ -1014,6 +1038,8 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         String password = createBgpPeerCmd.getPassword();
         Map<String, String> detailsStr = createBgpPeerCmd.getDetails();
 
+        checkIfRoutedNetworkVpcEnabled(zoneId);
+
         if (ObjectUtils.allNull(ip4Address, ip6Address)) {
             throw new InvalidParameterValueException("At least one of IPv4 and IPv6 address must be specified.");
         }
@@ -1398,7 +1424,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         return changeBgpPeersForNetworkInternal(network, null);
     }
 
-    private Network changeBgpPeersForNetworkInternal(Network network, List<Long> bgpPeerIds) {
+    protected Network changeBgpPeersForNetworkInternal(Network network, List<Long> bgpPeerIds) {
         final List<Long> bgpPeerIdsToBeAdded;
         if (CollectionUtils.isNotEmpty(bgpPeerIds)) {
             bgpPeerIdsToBeAdded = new ArrayList<>(bgpPeerIds);
@@ -1529,7 +1555,7 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
         return bgpPeerDao.listAvailableBgpPeerIdsForAccount(zoneId, owner.getDomainId(), owner.getId(), UseSystemBgpPeers.valueIn(owner.getId()));
     }
 
-    private Vpc changeBgpPeersForVpcInternal(Vpc vpc, List<Long> bgpPeerIds) {
+    protected Vpc changeBgpPeersForVpcInternal(Vpc vpc, List<Long> bgpPeerIds) {
         final List<Long> bgpPeerIdsToBeAdded;
         if (CollectionUtils.isNotEmpty(bgpPeerIds)) {
             bgpPeerIdsToBeAdded = new ArrayList<>(bgpPeerIds);
@@ -1618,4 +1644,15 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
     public void removeBgpPeersByDomainId(long domainId) {
         bgpPeerDao.removeByDomainId(domainId);
     }
+
+    @Override
+    public Boolean isRoutedNetworkVpcEnabled(long zoneId) {
+        return RoutedNetworkVpcEnabled.valueIn(zoneId);
+    }
+
+    private void checkIfRoutedNetworkVpcEnabled(long zoneId) {
+        if (!isRoutedNetworkVpcEnabled(zoneId)) {
+            throw new InvalidParameterValueException("Routed networks and VPCs are not enabled for the zone.");
+        }
+    }
 }
diff --git a/server/src/test/java/com/cloud/bgp/BGPServiceImplTest.java b/server/src/test/java/com/cloud/bgp/BGPServiceImplTest.java
index ace7bc85691..be31a1c6502 100644
--- a/server/src/test/java/com/cloud/bgp/BGPServiceImplTest.java
+++ b/server/src/test/java/com/cloud/bgp/BGPServiceImplTest.java
@@ -18,14 +18,39 @@
 
 package com.cloud.bgp;
 
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.dao.NetworkServiceMapDao;
+import com.cloud.network.element.VirtualRouterElement;
+import com.cloud.network.element.VpcVirtualRouterElement;
+import com.cloud.network.vpc.Vpc;
+import com.cloud.network.vpc.dao.VpcServiceMapDao;
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
+import org.apache.cloudstack.network.BgpPeerVO;
+import org.apache.cloudstack.network.RoutedIpv4Manager;
+import org.apache.cloudstack.network.dao.BgpPeerDao;
+
 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.mockito.Spy;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 @RunWith(MockitoJUnitRunner.class)
 public class BGPServiceImplTest {
 
@@ -33,6 +58,24 @@ public class BGPServiceImplTest {
     @InjectMocks
     BGPServiceImpl bGPServiceImplSpy = new BGPServiceImpl();
 
+    @Mock
+    RoutedIpv4Manager routedIpv4Manager;
+
+    @Mock
+    NetworkServiceMapDao ntwkSrvcDao;
+
+    @Mock
+    NetworkModel networkModel;
+
+    @Mock
+    BgpPeerDao bgpPeerDao;
+
+    @Mock
+    AccountDao accountDao;
+
+    @Mock
+    VpcServiceMapDao vpcServiceMapDao;
+
     @Test
     public void testASNumbersOverlap() {
         Assert.assertEquals(bGPServiceImplSpy.isASNumbersOverlap(1,2,3,4), false);
@@ -42,4 +85,92 @@ public class BGPServiceImplTest {
         Assert.assertEquals(bGPServiceImplSpy.isASNumbersOverlap(1,4,2,3), true);
         Assert.assertEquals(bGPServiceImplSpy.isASNumbersOverlap(3,4,1,2), false);
     }
+
+    @Test
+    public void testApplyBgpPeersForIsolatedNetwork() throws ResourceUnavailableException {
+        Long networkId = 11L;
+        Network network = Mockito.mock(Network.class);
+        when(network.getId()).thenReturn(networkId);
+        when(network.getVpcId()).thenReturn(null);
+
+        when(routedIpv4Manager.isDynamicRoutedNetwork(network)).thenReturn(true);
+        when(ntwkSrvcDao.getProviderForServiceInNetwork(networkId, Network.Service.Gateway)).thenReturn("VirtualRouter");
+        VirtualRouterElement virtualRouterElement = Mockito.mock(VirtualRouterElement.class);
+        when(networkModel.getElementImplementingProvider("VirtualRouter")).thenReturn(virtualRouterElement);
+
+        BgpPeerVO bgpPeer1 = Mockito.mock(BgpPeerVO.class);
+        List<BgpPeerVO> bgpPeers = Arrays.asList(bgpPeer1);
+        when(bgpPeerDao.listNonRevokeByNetworkId(networkId)).thenReturn(bgpPeers);
+        doReturn(true).when(virtualRouterElement).applyBgpPeers(null, network, bgpPeers);
+
+        bGPServiceImplSpy.applyBgpPeers(network, true);
+
+        verify(virtualRouterElement).applyBgpPeers(null, network, bgpPeers);
+    }
+
+    @Test
+    public void testApplyBgpPeersForVpcTier() throws ResourceUnavailableException {
+        Long networkId = 11L;
+        Long accountId = 12L;
+        Long vpcId = 13L;
+        Long zoneId = 1L;
+        Network network = Mockito.mock(Network.class);
+        when(network.getId()).thenReturn(networkId);
+        when(network.getVpcId()).thenReturn(vpcId);
+        when(network.getAccountId()).thenReturn(accountId);
+        when(network.getDataCenterId()).thenReturn(zoneId);
+
+        when(routedIpv4Manager.isDynamicRoutedNetwork(network)).thenReturn(true);
+        when(ntwkSrvcDao.getProviderForServiceInNetwork(networkId, Network.Service.Gateway)).thenReturn("VirtualRouter");
+        VirtualRouterElement virtualRouterElement = Mockito.mock(VirtualRouterElement.class);
+        when(networkModel.getElementImplementingProvider("VirtualRouter")).thenReturn(virtualRouterElement);
+
+        when(bgpPeerDao.listNonRevokeByVpcId(vpcId)).thenReturn(new ArrayList<>());
+
+        AccountVO owner = Mockito.mock(AccountVO.class);
+        when(accountDao.findByIdIncludingRemoved(accountId)).thenReturn(owner);
+
+        Long bgpPeerId1 = 14L;
+        BgpPeerVO bgpPeer1 = Mockito.mock(BgpPeerVO.class);
+        when(bgpPeerDao.findById(bgpPeerId1)).thenReturn(bgpPeer1);
+        when(routedIpv4Manager.getBgpPeerIdsForAccount(owner, zoneId)).thenReturn(Arrays.asList(bgpPeerId1));
+
+        doReturn(true).when(virtualRouterElement).applyBgpPeers(eq(null), eq(network), any());
+
+        bGPServiceImplSpy.applyBgpPeers(network, true);
+
+        verify(virtualRouterElement).applyBgpPeers(eq(null), eq(network), any());
+    }
+
+    @Test
+    public void testApplyBgpPeersForVpcWithBgpPeers() throws ResourceUnavailableException {
+        Long accountId = 12L;
+        Long vpcId = 13L;
+        Long zoneId = 1L;
+        Vpc vpc = Mockito.mock(Vpc.class);
+        when(vpc.getId()).thenReturn(vpcId);
+        when(vpc.getAccountId()).thenReturn(accountId);
+        when(vpc.getZoneId()).thenReturn(zoneId);
+
+        when(routedIpv4Manager.isDynamicRoutedVpc(vpc)).thenReturn(true);
+        when(vpcServiceMapDao.getProviderForServiceInVpc(vpcId, Network.Service.Gateway)).thenReturn("VPCVirtualRouter");
+        VpcVirtualRouterElement vpcVirtualRouterElement = Mockito.mock(VpcVirtualRouterElement.class);
+        when(networkModel.getElementImplementingProvider("VPCVirtualRouter")).thenReturn(vpcVirtualRouterElement);
+
+        when(bgpPeerDao.listNonRevokeByVpcId(vpcId)).thenReturn(new ArrayList<>());
+
+        AccountVO owner = Mockito.mock(AccountVO.class);
+        when(accountDao.findByIdIncludingRemoved(accountId)).thenReturn(owner);
+
+        Long bgpPeerId1 = 14L;
+        BgpPeerVO bgpPeer1 = Mockito.mock(BgpPeerVO.class);
+        when(bgpPeerDao.findById(bgpPeerId1)).thenReturn(bgpPeer1);
+        when(routedIpv4Manager.getBgpPeerIdsForAccount(owner, zoneId)).thenReturn(Arrays.asList(bgpPeerId1));
+
+        doReturn(true).when(vpcVirtualRouterElement).applyBgpPeers(eq(vpc), eq(null), any());
+
+        bGPServiceImplSpy.applyBgpPeers(vpc, true);
+
+        verify(vpcVirtualRouterElement).applyBgpPeers(eq(vpc), eq(null), any());
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
index 64d813c9ba8..51d5a61cbca 100644
--- a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
+++ b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
@@ -29,6 +30,7 @@ import static org.mockito.Mockito.doReturn;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
@@ -46,6 +48,7 @@ import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.net.Ip;
 import com.cloud.exception.InsufficientAddressCapacityException;
 import org.apache.cloudstack.alert.AlertService;
+import org.apache.cloudstack.api.command.admin.network.CreateNetworkCmdByAdmin;
 import org.apache.cloudstack.api.command.user.address.UpdateQuarantinedIpCmd;
 import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
 import org.apache.cloudstack.api.command.user.network.UpdateNetworkCmd;
@@ -753,13 +756,14 @@ public class NetworkServiceImplTest {
     }
 
     @Test
-    public void testCreateIpv4RoutedNetwork() throws InsufficientCapacityException, ResourceAllocationException {
+    public void testCreateIpv4RoutedNetwork() {
         registerCallContext();
         CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class);
         Mockito.when(cmd.getCidrSize()).thenReturn(24);
         prepareCreateNetworkDnsMocks(cmd, Network.GuestType.Isolated, false, false, true);
         when(networkOfferingVO.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.ROUTED);
         when(networkOfferingVO.getRoutingMode()).thenReturn(NetworkOffering.RoutingMode.Static);
+        when(routedIpv4Manager.isRoutedNetworkVpcEnabled(nullable(Long.class))).thenReturn(true);
         when(routedIpv4Manager.isVirtualRouterGateway(networkOfferingVO)).thenReturn(true);
         doNothing().when(routedIpv4Manager).assignIpv4SubnetToNetwork(nullable(Network.class));
 
@@ -777,6 +781,92 @@ public class NetworkServiceImplTest {
         Mockito.verify(routedIpv4Manager).assignIpv4SubnetToNetwork(nullable(Network.class));
     }
 
+    @Test
+    public void testCreateIpv4RoutedNetworkWithBgpPeersFailure1() {
+        registerCallContext();
+        CreateNetworkCmdByAdmin cmd = Mockito.mock(CreateNetworkCmdByAdmin.class);
+        Mockito.when(cmd.getCidrSize()).thenReturn(24);
+        List<Long> bgpPeerIds = Arrays.asList(11L, 12L);
+        Mockito.when(cmd.getBgpPeerIds()).thenReturn(bgpPeerIds);
+
+        prepareCreateNetworkDnsMocks(cmd, Network.GuestType.Isolated, false, true, true);
+        when(networkOfferingVO.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.ROUTED);
+        when(networkOfferingVO.getRoutingMode()).thenReturn(NetworkOffering.RoutingMode.Static);
+        when(routedIpv4Manager.isRoutedNetworkVpcEnabled(nullable(Long.class))).thenReturn(true);
+        when(routedIpv4Manager.isVirtualRouterGateway(networkOfferingVO)).thenReturn(true);
+
+        DataCenterVO zone = Mockito.mock(DataCenterVO.class);
+        when(cmd.getZoneId()).thenReturn(zoneId);
+        when(dcDao.findById(zoneId)).thenReturn(zone);
+        when(zone.getId()).thenReturn(zoneId);
+
+        try {
+            service.createGuestNetwork(cmd);
+        } catch (InsufficientCapacityException | ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals("The BGP peers of VPC tiers will inherit from the VPC, do not add separately.", ex.getMessage());
+        }
+    }
+
+    @Test
+    public void testCreateIpv4RoutedNetworkWithBgpPeersFailure2() {
+        registerCallContext();
+        CreateNetworkCmdByAdmin cmd = Mockito.mock(CreateNetworkCmdByAdmin.class);
+        Mockito.when(cmd.getCidrSize()).thenReturn(24);
+        List<Long> bgpPeerIds = Arrays.asList(11L, 12L);
+        Mockito.when(cmd.getBgpPeerIds()).thenReturn(bgpPeerIds);
+
+        prepareCreateNetworkDnsMocks(cmd, Network.GuestType.Isolated, false, false, true);
+        when(networkOfferingVO.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.ROUTED);
+        when(networkOfferingVO.getRoutingMode()).thenReturn(NetworkOffering.RoutingMode.Static);
+        when(routedIpv4Manager.isRoutedNetworkVpcEnabled(nullable(Long.class))).thenReturn(true);
+        when(routedIpv4Manager.isVirtualRouterGateway(networkOfferingVO)).thenReturn(true);
+
+        DataCenterVO zone = Mockito.mock(DataCenterVO.class);
+        when(cmd.getZoneId()).thenReturn(zoneId);
+        when(dcDao.findById(zoneId)).thenReturn(zone);
+        when(zone.getId()).thenReturn(zoneId);
+
+        try {
+            service.createGuestNetwork(cmd);
+        } catch (InsufficientCapacityException | ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals("The network offering does not support Dynamic routing", ex.getMessage());
+        }
+    }
+
+    @Test
+    public void testCreateIpv4RoutedNetworkWithBgpPeersFailure3() {
+        registerCallContext();
+        CreateNetworkCmdByAdmin cmd = Mockito.mock(CreateNetworkCmdByAdmin.class);
+        Mockito.when(cmd.getCidrSize()).thenReturn(24);
+        List<Long> bgpPeerIds = Arrays.asList(11L, 12L);
+        Mockito.when(cmd.getBgpPeerIds()).thenReturn(bgpPeerIds);
+
+        prepareCreateNetworkDnsMocks(cmd, Network.GuestType.Isolated, false, false, true);
+        when(networkOfferingVO.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.ROUTED);
+        when(networkOfferingVO.getRoutingMode()).thenReturn(NetworkOffering.RoutingMode.Static);
+        when(routedIpv4Manager.isRoutedNetworkVpcEnabled(nullable(Long.class))).thenReturn(true);
+        when(routedIpv4Manager.isVirtualRouterGateway(networkOfferingVO)).thenReturn(true);
+        when(routedIpv4Manager.isDynamicRoutedNetwork(networkOfferingVO)).thenReturn(true);
+        doThrow(new InvalidParameterValueException("validation error")).when(routedIpv4Manager).validateBgpPeers(nullable(Account.class), nullable(Long.class), any(List.class));
+
+        DataCenterVO zone = Mockito.mock(DataCenterVO.class);
+        when(cmd.getZoneId()).thenReturn(zoneId);
+        when(dcDao.findById(zoneId)).thenReturn(zone);
+        when(zone.getId()).thenReturn(zoneId);
+
+        try {
+            service.createGuestNetwork(cmd);
+        } catch (InsufficientCapacityException | ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals("validation error", ex.getMessage());
+        }
+    }
+
     @Test
     public void testCheckAndUpdateNetworkResetSuccess() {
         NetworkVO networkVO = new NetworkVO();
diff --git a/server/src/test/java/com/cloud/network/element/VirtualRouterElementTest.java b/server/src/test/java/com/cloud/network/element/VirtualRouterElementTest.java
index b0d9cdc9dc4..de9858d2f07 100644
--- a/server/src/test/java/com/cloud/network/element/VirtualRouterElementTest.java
+++ b/server/src/test/java/com/cloud/network/element/VirtualRouterElementTest.java
@@ -65,6 +65,7 @@ import com.cloud.network.router.VirtualRouter;
 import com.cloud.network.router.VirtualRouter.RedundantState;
 import com.cloud.network.router.VpcVirtualNetworkApplianceManagerImpl;
 import com.cloud.network.rules.dao.PortForwardingRulesDao;
+import com.cloud.network.vpc.VpcVO;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offerings.NetworkOfferingVO;
 import com.cloud.offerings.dao.NetworkOfferingDao;
@@ -98,7 +99,11 @@ import com.cloud.vm.dao.UserVmDetailsDao;
 import com.cloud.vm.dao.VMInstanceDao;
 import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.network.BgpPeerVO;
 import org.apache.cloudstack.network.router.deployment.RouterDeploymentDefinitionBuilder;
+import org.apache.cloudstack.network.topology.NetworkTopology;
+import org.apache.cloudstack.network.topology.NetworkTopologyContext;
+import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -111,6 +116,7 @@ import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -122,6 +128,7 @@ import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -178,6 +185,7 @@ public class VirtualRouterElementTest {
     @Mock private ResourceManager _resourceMgr;
     @Mock private UserVmManager _userVmMgr;
     @Mock private VirtualMachineManager _itMgr;
+    @Mock private NetworkTopologyContext networkTopologyContext;
 
     @InjectMocks
     private RouterDeploymentDefinitionBuilder routerDeploymentDefinitionBuilder;
@@ -517,4 +525,52 @@ public class VirtualRouterElementTest {
         assertTrue(counterNames.contains(AutoScaleCounterType.Memory.getName()));
         assertTrue(counterNames.contains(AutoScaleCounterType.VirtualRouter.getName()));
     }
+
+    @Test
+    public void testApplyBgpPeersForVpc() throws ResourceUnavailableException {
+        List<BgpPeerVO> bgpPeers = Mockito.mock(List.class);
+        VpcVO vpc = Mockito.mock(VpcVO.class);
+
+        DomainRouterVO router = Mockito.mock(DomainRouterVO.class);
+        when(router.getState()).thenReturn(VirtualMachine.State.Running);
+        long zoneId = 10L;
+        long vpcId = 11L;
+        when(vpc.getId()).thenReturn(vpcId);
+        when(vpc.getZoneId()).thenReturn(zoneId);
+        when(_routerDao.listByVpcId(vpcId)).thenReturn(Arrays.asList(router));
+        DataCenterVO dc = Mockito.mock(DataCenterVO.class);
+        when(_dcDao.findById(zoneId)).thenReturn(dc);
+        NetworkTopology networkTopology = Mockito.mock(NetworkTopology.class);
+        when(networkTopologyContext.retrieveNetworkTopology(dc)).thenReturn(networkTopology);
+        doReturn(true).when(networkTopology).applyBgpPeers(any(), any(), any());
+
+        boolean result = virtualRouterElement.applyBgpPeers(vpc, null, bgpPeers);
+
+        Assert.assertTrue(result);
+        verify(networkTopology).applyBgpPeers(any(), any(), any());
+    }
+
+    @Test
+    public void testApplyBgpPeersForNetwork() throws ResourceUnavailableException {
+        List<BgpPeerVO> bgpPeers = Mockito.mock(List.class);
+        NetworkVO network = Mockito.mock(NetworkVO.class);
+
+        DomainRouterVO router = Mockito.mock(DomainRouterVO.class);
+        when(router.getState()).thenReturn(VirtualMachine.State.Running);
+        long zoneId = 10L;
+        long networkId = 11L;
+        when(network.getId()).thenReturn(networkId);
+        when(network.getDataCenterId()).thenReturn(zoneId);
+        when(_routerDao.listByNetworkAndRole(networkId, VirtualRouter.Role.VIRTUAL_ROUTER)).thenReturn(Arrays.asList(router));
+        DataCenterVO dc = Mockito.mock(DataCenterVO.class);
+        when(_dcDao.findById(zoneId)).thenReturn(dc);
+        NetworkTopology networkTopology = Mockito.mock(NetworkTopology.class);
+        when(networkTopologyContext.retrieveNetworkTopology(dc)).thenReturn(networkTopology);
+        doReturn(true).when(networkTopology).applyBgpPeers(any(), any(), any());
+
+        boolean result = virtualRouterElement.applyBgpPeers(null, network, bgpPeers);
+
+        Assert.assertTrue(result);
+        verify(networkTopology).applyBgpPeers(any(), any(), any());
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/router/CommandSetupHelperTest.java b/server/src/test/java/com/cloud/network/router/CommandSetupHelperTest.java
index 37fa13baf98..bdd905841f9 100644
--- a/server/src/test/java/com/cloud/network/router/CommandSetupHelperTest.java
+++ b/server/src/test/java/com/cloud/network/router/CommandSetupHelperTest.java
@@ -17,12 +17,15 @@
 package com.cloud.network.router;
 
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.routing.SetBgpPeersCommand;
 import com.cloud.agent.api.routing.VmDataCommand;
 import com.cloud.agent.manager.Commands;
 import com.cloud.configuration.ConfigurationManager;
+import com.cloud.dc.ASNumberVO;
 import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.ASNumberDao;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.VlanDao;
 import com.cloud.network.NetworkModel;
@@ -43,6 +46,8 @@ import com.cloud.utils.net.Ip;
 import com.cloud.vm.NicVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.dao.NicDao;
+import org.apache.cloudstack.network.BgpPeerVO;
+import org.apache.cloudstack.network.dao.BgpPeerDetailsDao;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -55,10 +60,13 @@ import org.mockito.junit.MockitoJUnitRunner;
 import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static org.mockito.Mockito.when;
+
 @RunWith(MockitoJUnitRunner.class)
 public class CommandSetupHelperTest {
 
@@ -88,6 +96,10 @@ public class CommandSetupHelperTest {
     RouterControlHelper routerControlHelper;
     @Mock
     DataCenterDao dcDao;
+    @Mock
+    ASNumberDao asNumberDao;
+    @Mock
+    BgpPeerDetailsDao bgpPeerDetailsDao;
 
     @Before
     public void setUp() {
@@ -173,24 +185,90 @@ public class CommandSetupHelperTest {
         VpcVO vpc = new VpcVO();
         DataCenterVO dc = new DataCenterVO(1L, null, null, null, null, null, null, null, null, null, DataCenter.NetworkType.Advanced, null, null);
 
-        Mockito.when(router.getId()).thenReturn(14L);
-        Mockito.when(router.getDataCenterId()).thenReturn(4L);
-        Mockito.when(nicDao.listByVmId(ArgumentMatchers.anyLong())).thenReturn(List.of(nicVO));
-        Mockito.when(networkDao.findById(ArgumentMatchers.anyLong())).thenReturn(networkVO);
-        Mockito.when(ipAddressDao.listByAssociatedVpc(ArgumentMatchers.anyLong(), ArgumentMatchers.nullable(Boolean.class))).thenReturn(userIps);
-        Mockito.when(vlanDao.findById(ArgumentMatchers.anyLong())).thenReturn(vlanVO);
-        Mockito.when(networkModel.getNetworkRate(ArgumentMatchers.anyLong(), ArgumentMatchers.anyLong())).thenReturn(1200);
-        Mockito.when(networkModel.getNetwork(ArgumentMatchers.anyLong())).thenReturn(networkVO);
-        Mockito.when(networkOfferingDao.findById(ArgumentMatchers.anyLong())).thenReturn(networkOfferingVO);
-        Mockito.when(configurationManager.getNetworkOfferingNetworkRate(ArgumentMatchers.anyLong(), ArgumentMatchers.anyLong())).thenReturn(1200);
-        Mockito.when(networkModel.isSecurityGroupSupportedInNetwork(networkVO)).thenReturn(false);
-        Mockito.when(networkOfferingDetailsDao.getNtwkOffDetails(ArgumentMatchers.anyLong())).thenReturn(details);
-        Mockito.when(networkDetailsDao.findDetail(ArgumentMatchers.anyLong(), ArgumentMatchers.anyString())).thenReturn(null);
-        Mockito.when(vpcDao.findById(ArgumentMatchers.anyLong())).thenReturn(vpc);
-        Mockito.when(routerControlHelper.getRouterControlIp(ArgumentMatchers.anyLong())).thenReturn("10.1.11.101");
-        Mockito.when(dcDao.findById(ArgumentMatchers.anyLong())).thenReturn(dc);
+        when(router.getId()).thenReturn(14L);
+        when(router.getDataCenterId()).thenReturn(4L);
+        when(nicDao.listByVmId(ArgumentMatchers.anyLong())).thenReturn(List.of(nicVO));
+        when(networkDao.findById(ArgumentMatchers.anyLong())).thenReturn(networkVO);
+        when(ipAddressDao.listByAssociatedVpc(ArgumentMatchers.anyLong(), ArgumentMatchers.nullable(Boolean.class))).thenReturn(userIps);
+        when(vlanDao.findById(ArgumentMatchers.anyLong())).thenReturn(vlanVO);
+        when(networkModel.getNetworkRate(ArgumentMatchers.anyLong(), ArgumentMatchers.anyLong())).thenReturn(1200);
+        when(networkModel.getNetwork(ArgumentMatchers.anyLong())).thenReturn(networkVO);
+        when(networkOfferingDao.findById(ArgumentMatchers.anyLong())).thenReturn(networkOfferingVO);
+        when(configurationManager.getNetworkOfferingNetworkRate(ArgumentMatchers.anyLong(), ArgumentMatchers.anyLong())).thenReturn(1200);
+        when(networkModel.isSecurityGroupSupportedInNetwork(networkVO)).thenReturn(false);
+        when(networkOfferingDetailsDao.getNtwkOffDetails(ArgumentMatchers.anyLong())).thenReturn(details);
+        when(networkDetailsDao.findDetail(ArgumentMatchers.anyLong(), ArgumentMatchers.anyString())).thenReturn(null);
+        when(vpcDao.findById(ArgumentMatchers.anyLong())).thenReturn(vpc);
+        when(routerControlHelper.getRouterControlIp(ArgumentMatchers.anyLong())).thenReturn("10.1.11.101");
+        when(dcDao.findById(ArgumentMatchers.anyLong())).thenReturn(dc);
 
         commandSetupHelper.createVpcAssociatePublicIPCommands(router, pubIpList, commands, vlanMacAddress);
         Assert.assertEquals(2, commands.size());
     }
+
+    @Test
+    public void testCreateBgpPeersCommandsForNetwork() {
+        BgpPeerVO bgpPeer1 = Mockito.mock(BgpPeerVO.class);
+        BgpPeerVO bgpPeer2 = Mockito.mock(BgpPeerVO.class);
+        List<BgpPeerVO> bgpPeers = Arrays.asList(bgpPeer1, bgpPeer2);
+        Commands cmds = new Commands(Command.OnError.Stop);
+        VirtualRouter router = Mockito.mock(VirtualRouter.class);
+        NetworkVO network = Mockito.mock(NetworkVO.class);
+
+        long zoneId = 10L;
+        long networkId = 11L;
+        when(router.getDataCenterId()).thenReturn(zoneId);
+        when(router.getVpcId()).thenReturn(null);
+        when(network.getId()).thenReturn(networkId);
+        ASNumberVO asNumberVO = Mockito.mock(ASNumberVO.class);
+        when(asNumberDao.findByZoneAndNetworkId(zoneId, networkId)).thenReturn(asNumberVO);
+        DataCenterVO dc = Mockito.mock(DataCenterVO.class);
+        when(dcDao.findById(zoneId)).thenReturn(dc);
+        when(dc.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
+
+        commandSetupHelper.createBgpPeersCommands(bgpPeers, router, cmds, network);
+
+        Assert.assertEquals(1, cmds.size());
+        Command cmd = cmds.toCommands()[0];
+        Assert.assertTrue(cmd instanceof SetBgpPeersCommand);
+        Assert.assertEquals(2, ((SetBgpPeersCommand) cmd).getBpgPeers().length);
+    }
+
+    @Test
+    public void testCreateBgpPeersCommandsForVpc() {
+        BgpPeerVO bgpPeer1 = Mockito.mock(BgpPeerVO.class);
+        BgpPeerVO bgpPeer2 = Mockito.mock(BgpPeerVO.class);
+        List<BgpPeerVO> bgpPeers = Arrays.asList(bgpPeer1, bgpPeer2);
+        Commands cmds = new Commands(Command.OnError.Stop);
+        VirtualRouter router = Mockito.mock(VirtualRouter.class);
+        NetworkVO network = Mockito.mock(NetworkVO.class);
+
+        long zoneId = 10L;
+        long vpcId = 11L;
+        when(router.getDataCenterId()).thenReturn(zoneId);
+        when(router.getVpcId()).thenReturn(vpcId);
+        ASNumberVO asNumberVO = Mockito.mock(ASNumberVO.class);
+        when(asNumberDao.findByZoneAndVpcId(zoneId, vpcId)).thenReturn(asNumberVO);
+
+        long networkOfferingId = 12L;
+        NetworkOfferingVO offering = Mockito.mock(NetworkOfferingVO.class);
+        when(networkOfferingDao.findByIdIncludingRemoved(networkOfferingId)).thenReturn(offering);
+        when(offering.getRoutingMode()).thenReturn(NetworkOffering.RoutingMode.Dynamic);
+        NetworkVO network1 = Mockito.mock(NetworkVO.class);
+        when(network1.getNetworkOfferingId()).thenReturn(networkOfferingId);
+        NetworkVO network2 = Mockito.mock(NetworkVO.class);
+        when(network2.getNetworkOfferingId()).thenReturn(networkOfferingId);
+        when(networkDao.listByVpc(vpcId)).thenReturn(Arrays.asList(network1, network2));
+
+        DataCenterVO dc = Mockito.mock(DataCenterVO.class);
+        when(dcDao.findById(zoneId)).thenReturn(dc);
+        when(dc.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
+
+        commandSetupHelper.createBgpPeersCommands(bgpPeers, router, cmds, network);
+
+        Assert.assertEquals(1, cmds.size());
+        Command cmd = cmds.toCommands()[0];
+        Assert.assertTrue(cmd instanceof SetBgpPeersCommand);
+        Assert.assertEquals(4, ((SetBgpPeersCommand) cmd).getBpgPeers().length);
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/router/VirtualNetworkApplianceManagerImplTest.java b/server/src/test/java/com/cloud/network/router/VirtualNetworkApplianceManagerImplTest.java
index ec5fdc0730f..1e55f55fbd6 100644
--- a/server/src/test/java/com/cloud/network/router/VirtualNetworkApplianceManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/router/VirtualNetworkApplianceManagerImplTest.java
@@ -19,7 +19,10 @@ package com.cloud.network.router;
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.CheckS2SVpnConnectionsAnswer;
 import com.cloud.agent.api.CheckS2SVpnConnectionsCommand;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.manager.Commands;
 import com.cloud.alert.AlertManager;
+import com.cloud.bgp.BGPService;
 import com.cloud.cluster.dao.ManagementServerHostDao;
 import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.dao.DataCenterDao;
@@ -30,6 +33,8 @@ import com.cloud.host.HostVO;
 import com.cloud.host.Status;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
 import com.cloud.network.Site2SiteVpnConnection;
 import com.cloud.network.dao.FirewallRulesDao;
 import com.cloud.network.dao.IPAddressDao;
@@ -37,6 +42,7 @@ import com.cloud.network.dao.LoadBalancerDao;
 import com.cloud.network.dao.LoadBalancerVMMapDao;
 import com.cloud.network.dao.MonitoringServiceDao;
 import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.dao.OpRouterMonitorServiceDao;
 import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
 import com.cloud.network.dao.RemoteAccessVpnDao;
@@ -49,6 +55,8 @@ import com.cloud.network.dao.UserIpv6AddressDao;
 import com.cloud.network.dao.VirtualRouterProviderDao;
 import com.cloud.network.dao.VpnUserDao;
 import com.cloud.network.rules.dao.PortForwardingRulesDao;
+import com.cloud.network.vpc.VpcVO;
+import com.cloud.network.vpc.dao.VpcDao;
 import com.cloud.network.vpn.Site2SiteVpnManager;
 import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.service.dao.ServiceOfferingDao;
@@ -69,12 +77,15 @@ import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.UserVmDetailsDao;
 import com.cloud.vm.dao.VMInstanceDao;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.network.BgpPeer;
+import org.apache.cloudstack.network.RoutedIpv4Manager;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
 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.mockito.junit.MockitoJUnitRunner;
 
 import java.util.ArrayList;
@@ -233,6 +244,20 @@ public class VirtualNetworkApplianceManagerImplTest {
     @InjectMocks
     private VirtualNetworkApplianceManagerImpl virtualNetworkApplianceManagerImpl;
 
+    @Mock
+    private NetworkModel _networkModel;
+
+    @Mock
+    private RoutedIpv4Manager routedIpv4Manager;
+
+    @Mock
+    private CommandSetupHelper _commandSetupHelper;
+
+    @Mock
+    private VpcDao _vpcDao;
+
+    @Mock
+    private BGPService bgpService;
 
     //    @InjectMocks
     //    private VirtualNetworkApplianceManagerImpl virtualNetworkApplianceManagerImpl;
@@ -328,4 +353,42 @@ public class VirtualNetworkApplianceManagerImplTest {
         result = virtualNetworkApplianceManagerImpl.checkLogrotateTimerPattern(foo);
         Assert.assertTrue(result);
     }
+
+    @Test
+    public void testFinalizeNetworkRulesForNetwork() {
+        Long guestNetworkId = 10L;
+        Commands cmds = new Commands(Command.OnError.Stop);
+        DomainRouterVO router = Mockito.mock(DomainRouterVO.class);
+
+        NetworkVO network = Mockito.mock(NetworkVO.class);
+        when(_networkDao.findById(guestNetworkId)).thenReturn(network);
+        when(network.getVpcId()).thenReturn(null);
+        when(routedIpv4Manager.isDynamicRoutedNetwork(network)).thenReturn(true);
+        List<? extends BgpPeer> bgpPeers = Mockito.mock(List.class);
+        doReturn(bgpPeers).when(bgpService).getBgpPeersForNetwork(network);
+        virtualNetworkApplianceManagerImpl.finalizeNetworkRulesForNetwork(cmds, router, Network.Provider.VirtualRouter, guestNetworkId);
+
+        Mockito.verify(_commandSetupHelper).createBgpPeersCommands(bgpPeers, router, cmds, network);
+    }
+
+    @Test
+    public void testFinalizeNetworkRulesForVpcNetwork() {
+        Long guestNetworkId = 10L;
+        Long vpcId = 11L;
+        Commands cmds = new Commands(Command.OnError.Stop);
+        DomainRouterVO router = Mockito.mock(DomainRouterVO.class);
+
+        NetworkVO network = Mockito.mock(NetworkVO.class);
+        when(_networkDao.findById(guestNetworkId)).thenReturn(network);
+        when(network.getVpcId()).thenReturn(vpcId);
+        VpcVO vpc = Mockito.mock(VpcVO.class);
+        when(_vpcDao.findById(vpcId)).thenReturn(vpc);
+        when(routedIpv4Manager.isDynamicRoutedVpc(vpc)).thenReturn(true);
+        List<? extends BgpPeer> bgpPeers = Mockito.mock(List.class);
+        doReturn(bgpPeers).when(bgpService).getBgpPeersForVpc(vpc);
+
+        virtualNetworkApplianceManagerImpl.finalizeNetworkRulesForNetwork(cmds, router, Network.Provider.VirtualRouter, guestNetworkId);
+
+        Mockito.verify(_commandSetupHelper).createBgpPeersCommands(bgpPeers, router, cmds, network);
+    }
 }
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 54acaa58acc..ee56a092dd1 100644
--- a/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
@@ -73,6 +73,7 @@ import org.apache.cloudstack.api.command.user.vpc.UpdateVPCCmd;
 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.network.Ipv4GuestSubnetNetworkMap;
 import org.apache.cloudstack.network.RoutedIpv4Manager;
 import org.junit.After;
 import org.junit.Assert;
@@ -87,6 +88,7 @@ import org.springframework.test.util.ReflectionTestUtils;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -98,6 +100,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyMap;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -541,6 +544,30 @@ public class VpcManagerImplTest {
         verify(routedIpv4Manager).getOrCreateIpv4SubnetForVpc(any(), anyString());
     }
 
+    @Test
+    public void testCreateRoutedVpcWithDynamicRouting() {
+        mockVpcDnsResources(true, false);
+        VpcVO vpc = Mockito.mock(VpcVO.class);
+        Mockito.when(vpcDao.persist(any(), anyMap())).thenReturn(vpc);
+        Mockito.when(vpc.getUuid()).thenReturn("uuid");
+        doReturn(true).when(routedIpv4Manager).isRoutedVpc(any());
+        doReturn(true).when(routedIpv4Manager).isVpcVirtualRouterGateway(vpcOfferingVO);
+        doReturn(true).when(routedIpv4Manager).isDynamicRoutedVpc(vpcOfferingVO);
+        Ipv4GuestSubnetNetworkMap ipv4GuestSubnetNetworkMap = Mockito.mock(Ipv4GuestSubnetNetworkMap.class);
+        doReturn(ipv4GuestSubnetNetworkMap).when(routedIpv4Manager).getOrCreateIpv4SubnetForVpc(any(), anyInt());
+        List<Long> bgpPeerIds = Arrays.asList(11L, 12L);
+        try {
+            doNothing().when(resourceLimitService).checkResourceLimit(account, Resource.ResourceType.vpc);
+            manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, null, vpcDomain,
+                    ip4Dns[0], ip4Dns[1], null, null, true, 1500, 24, null, bgpPeerIds);
+        } catch (ResourceAllocationException e) {
+            Assert.fail(String.format("failure with exception: %s", e.getMessage()));
+        }
+
+        verify(routedIpv4Manager).getOrCreateIpv4SubnetForVpc(any(), anyInt());
+        verify(routedIpv4Manager).validateBgpPeers(any(), any(), any());
+    }
+
     @Test
     public void validateVpcPrivateGatewayAclIdTestNullAclVoThrowsInvalidParameterValueException() {
         Mockito.doReturn(null).when(networkACLDaoMock).findById(aclId);
diff --git a/server/src/test/java/org/apache/cloudstack/network/RoutedIpv4ManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/network/RoutedIpv4ManagerImplTest.java
new file mode 100644
index 00000000000..5351abe2e2d
--- /dev/null
+++ b/server/src/test/java/org/apache/cloudstack/network/RoutedIpv4ManagerImplTest.java
@@ -0,0 +1,1217 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package org.apache.cloudstack.network;
+
+import com.cloud.api.ApiDBUtils;
+import com.cloud.bgp.BGPService;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.domain.DomainVO;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.dao.FirewallRulesDao;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkServiceMapDao;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.element.VirtualRouterElement;
+import com.cloud.network.firewall.FirewallService;
+import com.cloud.network.rules.FirewallManager;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRuleVO;
+import com.cloud.network.vpc.Vpc;
+import com.cloud.network.vpc.VpcOfferingVO;
+import com.cloud.network.vpc.VpcVO;
+import com.cloud.network.vpc.dao.VpcDao;
+import com.cloud.network.vpc.dao.VpcOfferingDao;
+import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
+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.projects.ProjectVO;
+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.exception.CloudRuntimeException;
+import com.cloud.utils.net.NetUtils;
+
+import org.apache.cloudstack.api.command.admin.network.CreateIpv4SubnetForGuestNetworkCmd;
+import org.apache.cloudstack.api.command.admin.network.CreateIpv4SubnetForZoneCmd;
+import org.apache.cloudstack.api.command.admin.network.DedicateIpv4SubnetForZoneCmd;
+import org.apache.cloudstack.api.command.admin.network.DeleteIpv4SubnetForGuestNetworkCmd;
+import org.apache.cloudstack.api.command.admin.network.DeleteIpv4SubnetForZoneCmd;
+import org.apache.cloudstack.api.command.admin.network.ReleaseDedicatedIpv4SubnetForZoneCmd;
+import org.apache.cloudstack.api.command.admin.network.UpdateIpv4SubnetForZoneCmd;
+import org.apache.cloudstack.api.command.admin.network.bgp.ChangeBgpPeersForNetworkCmd;
+import org.apache.cloudstack.api.command.admin.network.bgp.ChangeBgpPeersForVpcCmd;
+import org.apache.cloudstack.api.command.admin.network.bgp.CreateBgpPeerCmd;
+import org.apache.cloudstack.api.command.admin.network.bgp.DedicateBgpPeerCmd;
+import org.apache.cloudstack.api.command.admin.network.bgp.DeleteBgpPeerCmd;
+import org.apache.cloudstack.api.command.admin.network.bgp.ReleaseDedicatedBgpPeerCmd;
+import org.apache.cloudstack.api.command.admin.network.bgp.UpdateBgpPeerCmd;
+import org.apache.cloudstack.api.command.user.network.routing.CreateRoutingFirewallRuleCmd;
+import org.apache.cloudstack.api.command.user.network.routing.UpdateRoutingFirewallRuleCmd;
+import org.apache.cloudstack.api.response.BgpPeerResponse;
+import org.apache.cloudstack.api.response.DataCenterIpv4SubnetResponse;
+import org.apache.cloudstack.api.response.Ipv4SubnetForGuestNetworkResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.datacenter.DataCenterIpv4GuestSubnet;
+import org.apache.cloudstack.datacenter.DataCenterIpv4GuestSubnetVO;
+import org.apache.cloudstack.datacenter.dao.DataCenterIpv4GuestSubnetDao;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.network.dao.BgpPeerDao;
+import org.apache.cloudstack.network.dao.BgpPeerDetailsDao;
+import org.apache.cloudstack.network.dao.BgpPeerNetworkMapDao;
+import org.apache.cloudstack.network.dao.Ipv4GuestSubnetNetworkMapDao;
+import org.apache.commons.collections.CollectionUtils;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockedStatic;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RoutedIpv4ManagerImplTest {
+
+    @Spy
+    @InjectMocks
+    RoutedIpv4ManagerImpl routedIpv4Manager = new RoutedIpv4ManagerImpl();
+
+    @Mock
+    DataCenterIpv4GuestSubnetDao dataCenterIpv4GuestSubnetDao;
+    @Mock
+    Ipv4GuestSubnetNetworkMapDao ipv4GuestSubnetNetworkMapDao;
+    @Mock
+    FirewallService firewallService;
+    @Mock
+    FirewallManager firewallManager;
+    @Mock
+    FirewallRulesDao firewallDao;
+    @Mock
+    NetworkServiceMapDao networkServiceMapDao;
+    @Mock
+    NetworkOfferingServiceMapDao networkOfferingServiceMapDao;
+    @Mock
+    NetworkOfferingDao networkOfferingDao;
+    @Mock
+    NetworkModel networkModel;
+    @Mock
+    AccountManager accountManager;
+    @Mock
+    VpcOfferingDao vpcOfferingDao;
+    @Mock
+    VpcOfferingServiceMapDao vpcOfferingServiceMapDao;
+    @Mock
+    VpcDao vpcDao;
+    @Mock
+    BgpPeerDao bgpPeerDao;
+    @Mock
+    BgpPeerDetailsDao bgpPeerDetailsDao;
+    @Mock
+    BgpPeerNetworkMapDao bgpPeerNetworkMapDao;
+    @Mock
+    NetworkDao networkDao;
+    @Mock
+    BGPService bgpService;
+
+    static MockedStatic<ApiDBUtils> apiDBUtilsMocked;
+
+    @Mock
+    DataCenterIpv4GuestSubnetVO subnetVO;
+    @Mock
+    DomainVO domain;
+    @Mock
+    AccountVO account;
+    @Mock
+    ProjectVO project;
+    @Mock
+    Ipv4GuestSubnetNetworkMapVO ipv4GuestSubnetNetworkMap;
+    @Mock
+    NetworkVO network;
+    @Mock
+    VpcVO vpc;
+    @Mock
+    DataCenterVO zone;
+    @Mock
+    FirewallRuleVO rule;
+    @Mock
+    BgpPeerVO bgpPeer;
+    @Mock
+    NetworkOfferingVO networkOffering;
+    @Mock
+    VpcOfferingVO vpcOffering;
+
+    Long zoneId = 1L;
+    String zoneUuid = "zone-uuid";
+    String zoneName = "zone-name";
+    Long zoneSubnetId = 2L;
+    String zoneSubnetUuid = "zone-subnet-uuid";
+    Long domainId = 3L;
+    Long accountId = 4L;
+    Long ipv4GuestSubnetNetworkMapId = 5L;
+    Long networkId = 6L;
+    String networkUuid = "network-uuid";
+    String networkName = "network-name";
+    Long vpcId = 7L;
+    String vpcUuid = "vpc-uuid";
+    String vpcName = "vpc-name";
+    String domainName = "domain";
+    String domainUuid = "domain-uuid";
+    String accountName = "user";
+    String subnet = "172.16.1.0/24";
+    String newSubnet = "172.16.2.0/24";
+    String subnetForNetwork = "172.16.1.0/28";
+    String newSubnetForNetwork = "172.16.1.64/28";
+    String newSubnetForNetworkTooSmall = "172.16.1.0/30";
+    String newSubnetForNetworkTooBig = "172.16.1.0/23";
+    Integer cidrSize = 28;
+    Ipv4GuestSubnetNetworkMap.State ipv4GuestSubnetNetworkMapState = Ipv4GuestSubnetNetworkMap.State.Free;
+    Date created = new Date();
+    String uuid = "xxx-yyy-zzz";
+    Long ruleId = 8L;
+    String ip4Address = "10.10.11.11";
+    String ip6Address = "fd00:10:10:11:11::1";
+    Long asNumber = 9999L;
+    String password = "password-text";
+    Long bgpPeerId = 9L;
+    String bgpPeerUuid = "bgp-peer-uuid";
+    Long projectId = 10L;
+    String projectName = "project";
+    String projectUuid = "project-uuid";
+    Long networkOfferingId = 11L;
+    Long vpcOfferingId = 12L;
+
+    @BeforeClass
+    public static void setup() {
+        apiDBUtilsMocked = Mockito.mockStatic(ApiDBUtils.class);
+        apiDBUtilsMocked.when(() -> ApiDBUtils.findZoneById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class));
+
+        CallContext.unregister();
+        AccountVO account = new AccountVO("admin", 1L, "", Account.Type.ADMIN, "uuid");
+        account.setId(2L);
+        UserVO user = new UserVO(1, "admin", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
+        CallContext.register(user, account);
+    }
+
+    @AfterClass
+    public static void close() {
+        apiDBUtilsMocked.close();
+
+        CallContext.unregister();
+    }
+
+    @Test
+    public void testGetCommands() throws NoSuchFieldException, IllegalAccessException {
+        Assert.assertTrue(CollectionUtils.isNotEmpty(routedIpv4Manager.getCommands()));
+        Assert.assertEquals(26, routedIpv4Manager.getCommands().size());
+
+        overrideDefaultConfigValue(RoutedIpv4Manager.RoutedNetworkVpcEnabled, "_defaultValue", "false");
+        Assert.assertTrue(CollectionUtils.isEmpty(routedIpv4Manager.getCommands()));
+    }
+
+    private static void overrideDefaultConfigValue(final ConfigKey configKey, final String name, final Object o) throws IllegalAccessException, NoSuchFieldException {
+        Field f = ConfigKey.class.getDeclaredField(name);
+        f.setAccessible(true);
+        f.set(configKey, o);
+    }
+
+    @Test
+    public void testCreateDataCenterIpv4GuestSubnet() {
+        CreateIpv4SubnetForZoneCmd cmd = new CreateIpv4SubnetForZoneCmd();
+        ReflectionTestUtils.setField(cmd,"zoneId", zoneId);
+        ReflectionTestUtils.setField(cmd,"subnet", subnet);
+
+        routedIpv4Manager.createDataCenterIpv4GuestSubnet(cmd);
+
+        verify(routedIpv4Manager).checkConflicts(new ArrayList<>(), subnet, null);
+        verify(dataCenterIpv4GuestSubnetDao).persist(any());
+    }
+
+    @Test
+    public void testCreateDataCenterIpv4SubnetResponse() {
+        DataCenterIpv4GuestSubnetVO subnetVO = new DataCenterIpv4GuestSubnetVO(zoneId, NetUtils.transformCidr(subnet));
+        DataCenterIpv4SubnetResponse response = routedIpv4Manager.createDataCenterIpv4SubnetResponse(subnetVO);
+
+        Assert.assertEquals(subnet, response.getSubnet());
+        Assert.assertEquals(subnetVO.getUuid(), response.getId());
+        Assert.assertEquals("zoneipv4subnet", response.getObjectName());
+    }
+
+    @Test
+    public void testDeleteDataCenterIpv4GuestSubnet() {
+        DeleteIpv4SubnetForZoneCmd cmd = new DeleteIpv4SubnetForZoneCmd();
+        ReflectionTestUtils.setField(cmd,"id", zoneSubnetId);
+
+        routedIpv4Manager.deleteDataCenterIpv4GuestSubnet(cmd);
+
+        verify(ipv4GuestSubnetNetworkMapDao).deleteByParentId(zoneSubnetId);
+        verify(dataCenterIpv4GuestSubnetDao).remove(zoneSubnetId);
+    }
+
+    @Test
+    public void testUpdateDataCenterIpv4GuestSubnet() {
+        UpdateIpv4SubnetForZoneCmd cmd = new UpdateIpv4SubnetForZoneCmd();
+        ReflectionTestUtils.setField(cmd,"id", zoneSubnetId);
+        ReflectionTestUtils.setField(cmd,"subnet", newSubnet);
+
+        when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
+
+        routedIpv4Manager.updateDataCenterIpv4GuestSubnet(cmd);
+
+        verify(routedIpv4Manager).checkConflicts(new ArrayList<>(), newSubnet, zoneSubnetId);
+        verify(ipv4GuestSubnetNetworkMapDao).listByParent(zoneSubnetId);
+        verify(dataCenterIpv4GuestSubnetDao).update(eq(zoneSubnetId), any(DataCenterIpv4GuestSubnetVO.class));
+    }
+
+    @Test
+    public void testCheckConflicts1() {
+        DataCenterIpv4GuestSubnetVO existingSubnet = Mockito.mock(DataCenterIpv4GuestSubnetVO.class);
+        when(existingSubnet.getSubnet()).thenReturn(subnet);
+        List<DataCenterIpv4GuestSubnetVO> existingSubnets = Arrays.asList(existingSubnet);
+        routedIpv4Manager.checkConflicts(existingSubnets, newSubnet, null);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testCheckConflicts2() {
+        DataCenterIpv4GuestSubnetVO existingSubnet = Mockito.mock(DataCenterIpv4GuestSubnetVO.class);
+        when(existingSubnet.getSubnet()).thenReturn(subnet);
+        List<DataCenterIpv4GuestSubnetVO> existingSubnets = Arrays.asList(existingSubnet);
+        routedIpv4Manager.checkConflicts(existingSubnets, subnet, null);
+    }
+
+    @Test
+    public void testCheckConflicts3() {
+        DataCenterIpv4GuestSubnetVO existingSubnet = Mockito.mock(DataCenterIpv4GuestSubnetVO.class);
+        when(existingSubnet.getId()).thenReturn(zoneSubnetId);
+        List<DataCenterIpv4GuestSubnetVO> existingSubnets = Arrays.asList(existingSubnet);
+        routedIpv4Manager.checkConflicts(existingSubnets, subnet, zoneSubnetId);
+    }
+
+    @Test
+    public void testDedicateDataCenterIpv4GuestSubnet() {
+        DedicateIpv4SubnetForZoneCmd cmd = new DedicateIpv4SubnetForZoneCmd();
+        ReflectionTestUtils.setField(cmd,"id", zoneSubnetId);
+        ReflectionTestUtils.setField(cmd,"domainId", domainId);
+        ReflectionTestUtils.setField(cmd,"accountName", accountName);
+        ReflectionTestUtils.setField(cmd,"projectId", null);
+
+        when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
+
+        when(accountManager.finalyzeAccountId(accountName, domainId, null, false)).thenReturn(accountId);
+        when(accountManager.getAccount(accountId)).thenReturn(account);
+        when(account.getDomainId()).thenReturn(domainId);
+        when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
+
+        routedIpv4Manager.dedicateDataCenterIpv4GuestSubnet(cmd);
+
+        verify(subnetVO).setDomainId(domainId);
+        verify(subnetVO).setAccountId(accountId);
+        verify(dataCenterIpv4GuestSubnetDao).update(zoneSubnetId, subnetVO);
+    }
+
+    @Test
+    public void testReleaseDedicatedDataCenterIpv4GuestSubnet() {
+        ReleaseDedicatedIpv4SubnetForZoneCmd cmd = new ReleaseDedicatedIpv4SubnetForZoneCmd();
+        ReflectionTestUtils.setField(cmd,"id", zoneSubnetId);
+        when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
+
+        routedIpv4Manager.releaseDedicatedDataCenterIpv4GuestSubnet(cmd);
+
+        verify(subnetVO).setDomainId(null);
+        verify(subnetVO).setAccountId(null);
+        verify(dataCenterIpv4GuestSubnetDao).update(zoneSubnetId, subnetVO);
+    }
+
+    @Test
+    public void testCreateIpv4SubnetForGuestNetwork1() {
+        CreateIpv4SubnetForGuestNetworkCmd cmd = new CreateIpv4SubnetForGuestNetworkCmd();
+
+        try {
+            routedIpv4Manager.createIpv4SubnetForGuestNetwork(cmd);
+            Assert.fail("creating IPv4 subnet for guest network should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals("One of subnet and cidrsize must be specified", ex.getMessage());
+        }
+    }
+
+    @Test
+    public void testCreateIpv4SubnetForGuestNetwork2() {
+        CreateIpv4SubnetForGuestNetworkCmd cmd = new CreateIpv4SubnetForGuestNetworkCmd();
+        ReflectionTestUtils.setField(cmd,"subnet", subnet);
+        ReflectionTestUtils.setField(cmd,"cidrSize", cidrSize);
+        try {
+            routedIpv4Manager.createIpv4SubnetForGuestNetwork(cmd);
+            Assert.fail("creating IPv4 subnet for guest network should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals("subnet and cidrsize are mutually exclusive", ex.getMessage());
+        }
+    }
+
+    @Test
+    public void testCreateIpv4SubnetForGuestNetwork3() {
+        CreateIpv4SubnetForGuestNetworkCmd cmd = new CreateIpv4SubnetForGuestNetworkCmd();
+        ReflectionTestUtils.setField(cmd,"subnet", subnet);
+        ReflectionTestUtils.setField(cmd,"parentId", zoneSubnetId);
+        when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
+        doReturn(ipv4GuestSubnetNetworkMap).when(routedIpv4Manager).createIpv4SubnetFromParentSubnet(subnetVO, subnet);
+
+        Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.createIpv4SubnetForGuestNetwork(cmd);
+
+        Assert.assertEquals(ipv4GuestSubnetNetworkMap, result);
+    }
+
+    @Test
+    public void testCreateIpv4SubnetForGuestNetwork4() {
+        CreateIpv4SubnetForGuestNetworkCmd cmd = new CreateIpv4SubnetForGuestNetworkCmd();
+        ReflectionTestUtils.setField(cmd,"cidrSize", cidrSize);
+        ReflectionTestUtils.setField(cmd,"parentId", zoneSubnetId);
+        when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
+        doReturn(ipv4GuestSubnetNetworkMap).when(routedIpv4Manager).createIpv4SubnetFromParentSubnet(subnetVO, cidrSize);
+
+        Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.createIpv4SubnetForGuestNetwork(cmd);
+
+        Assert.assertEquals(ipv4GuestSubnetNetworkMap, result);
+    }
+
+    @Test
+    public void testDeleteIpv4SubnetForGuestNetwork() {
+        DeleteIpv4SubnetForGuestNetworkCmd cmd = new DeleteIpv4SubnetForGuestNetworkCmd();
+        ReflectionTestUtils.setField(cmd,"id", ipv4GuestSubnetNetworkMapId);
+
+        when(ipv4GuestSubnetNetworkMapDao.findById(ipv4GuestSubnetNetworkMapId)).thenReturn(ipv4GuestSubnetNetworkMap);
+        when(ipv4GuestSubnetNetworkMap.getState()).thenReturn(ipv4GuestSubnetNetworkMapState);
+        when(ipv4GuestSubnetNetworkMap.getNetworkId()).thenReturn(null);
+
+        routedIpv4Manager.deleteIpv4SubnetForGuestNetwork(cmd);
+
+        verify(ipv4GuestSubnetNetworkMapDao).remove(ipv4GuestSubnetNetworkMapId);
+    }
+
+    @Test
+    public void testReleaseIpv4SubnetForGuestNetwork() {
+        when(ipv4GuestSubnetNetworkMapDao.findByNetworkId(networkId)).thenReturn(ipv4GuestSubnetNetworkMap);
+        when(ipv4GuestSubnetNetworkMap.getId()).thenReturn(ipv4GuestSubnetNetworkMapId);
+
+        routedIpv4Manager.releaseIpv4SubnetForGuestNetwork(networkId);
+
+        verify(ipv4GuestSubnetNetworkMapDao).remove(ipv4GuestSubnetNetworkMapId);
+    }
+
+    @Test
+    public void testReleaseIpv4SubnetForVpc() {
+        when(ipv4GuestSubnetNetworkMapDao.findByVpcId(vpcId)).thenReturn(ipv4GuestSubnetNetworkMap);
+        when(ipv4GuestSubnetNetworkMap.getId()).thenReturn(ipv4GuestSubnetNetworkMapId);
+
+        routedIpv4Manager.releaseIpv4SubnetForVpc(vpcId);
+
+        verify(ipv4GuestSubnetNetworkMapDao).remove(ipv4GuestSubnetNetworkMapId);
+    }
+
+    @Test
+    public void testCreateIpv4SubnetForGuestNetworkResponse() {
+        when(ipv4GuestSubnetNetworkMap.getCreated()).thenReturn(created);
+        when(ipv4GuestSubnetNetworkMap.getSubnet()).thenReturn(subnet);
+        when(ipv4GuestSubnetNetworkMap.getState()).thenReturn(ipv4GuestSubnetNetworkMapState);
+        when(ipv4GuestSubnetNetworkMap.getUuid()).thenReturn(uuid);
+
+        when(ipv4GuestSubnetNetworkMap.getNetworkId()).thenReturn(networkId);
+        apiDBUtilsMocked.when(() -> ApiDBUtils.findNetworkById(Mockito.anyLong())).thenReturn(network);
+        when(network.getName()).thenReturn(networkName);
+        when(network.getUuid()).thenReturn(networkUuid);
+        when(network.getDataCenterId()).thenReturn(zoneId);
+
+        when(ipv4GuestSubnetNetworkMap.getVpcId()).thenReturn(vpcId);
+        apiDBUtilsMocked.when(() -> ApiDBUtils.findVpcById(Mockito.anyLong())).thenReturn(vpc);
+        when(vpc.getName()).thenReturn(vpcName);
+        when(vpc.getUuid()).thenReturn(vpcUuid);
+        when(vpc.getZoneId()).thenReturn(zoneId);
+
+        when(ipv4GuestSubnetNetworkMap.getParentId()).thenReturn(zoneSubnetId);
+        when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
+        when(subnetVO.getSubnet()).thenReturn(subnet);
+        when(subnetVO.getUuid()).thenReturn(zoneSubnetUuid);
+        when(subnetVO.getDataCenterId()).thenReturn(zoneId);
+
+        apiDBUtilsMocked.when(() -> ApiDBUtils.findZoneById(zoneId)).thenReturn(zone);
+        when(zone.getName()).thenReturn(zoneName);
+        when(zone.getUuid()).thenReturn(zoneUuid);
+
+        Ipv4SubnetForGuestNetworkResponse response = routedIpv4Manager.createIpv4SubnetForGuestNetworkResponse(ipv4GuestSubnetNetworkMap);
+
+        Assert.assertEquals(created, response.getCreated());
+        Assert.assertEquals(subnet, response.getSubnet());
+        Assert.assertEquals(ipv4GuestSubnetNetworkMapState.name(), response.getState());
+        Assert.assertEquals(uuid, response.getId());
+        Assert.assertEquals(networkName, response.getNetworkName());
+        Assert.assertEquals(networkUuid, response.getNetworkId());
+        Assert.assertEquals(vpcName, response.getVpcName());
+        Assert.assertEquals(vpcUuid, response.getVpcId());
+        Assert.assertEquals(subnet, response.getParentSubnet());
+        Assert.assertEquals(zoneSubnetUuid, response.getParentId());
+        Assert.assertEquals(zoneUuid, response.getZoneId());
+        Assert.assertEquals(zoneName, response.getZoneName());
+        Assert.assertEquals("ipv4subnetforguestnetwork", response.getObjectName());
+    }
+
+    @Test
+    public void testGetOrCreateIpv4SubnetForGuestNetworkOrVpcInternalByCidr1() {
+        when(ipv4GuestSubnetNetworkMapDao.findBySubnet(subnet)).thenReturn(ipv4GuestSubnetNetworkMap);
+        when(ipv4GuestSubnetNetworkMap.getNetworkId()).thenReturn(null);
+        when(ipv4GuestSubnetNetworkMap.getVpcId()).thenReturn(null);
+        when(ipv4GuestSubnetNetworkMap.getParentId()).thenReturn(zoneSubnetId);
+        when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
+        when(subnetVO.getDomainId()).thenReturn(domainId);
+        when(subnetVO.getAccountId()).thenReturn(accountId);
+
+        routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(subnet, domainId, accountId, zoneId);
+    }
+
+    @Test
+    public void testGetOrCreateIpv4SubnetForGuestNetworkOrVpcInternalByCidr2() {
+        when(ipv4GuestSubnetNetworkMapDao.findBySubnet(subnet)).thenReturn(null);
+
+        routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(subnet, domainId, accountId, zoneId);
+
+        verify(ipv4GuestSubnetNetworkMapDao).persist(any(Ipv4GuestSubnetNetworkMapVO.class));
+    }
+
+    @Test
+    public void testGetOrCreateIpv4SubnetForGuestNetworkOrVpcInternalByCidr3() {
+        when(ipv4GuestSubnetNetworkMapDao.findBySubnet(subnet)).thenReturn(null);
+        when(routedIpv4Manager.getParentOfNetworkCidr(zoneId, subnet)).thenReturn(subnetVO);
+        when(subnetVO.getDomainId()).thenReturn(domainId);
+        when(subnetVO.getAccountId()).thenReturn(accountId);
+
+        routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(subnet, domainId, accountId, zoneId);
+
+        verify(ipv4GuestSubnetNetworkMapDao).persist(any(Ipv4GuestSubnetNetworkMapVO.class));
+    }
+
+    @Test
+    public void testGetOrCreateIpv4SubnetForGuestNetworkOrVpcInternalByCidrSize1() {
+        Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, domainId, accountId, zoneId);
+        Assert.assertNull(result);
+    }
+
+    @Test
+    public void testGetOrCreateIpv4SubnetForGuestNetworkOrVpcInternalByCidrSize2() {
+        DataCenterIpv4GuestSubnetVO subnet1 = Mockito.mock(DataCenterIpv4GuestSubnetVO.class);
+        when(dataCenterIpv4GuestSubnetDao.listByDataCenterIdAndAccountId(zoneId, accountId)).thenReturn(Arrays.asList(subnet1));
+        DataCenterIpv4GuestSubnetVO subnet2 = Mockito.mock(DataCenterIpv4GuestSubnetVO.class);
+        when(dataCenterIpv4GuestSubnetDao.listByDataCenterIdAndDomainId(zoneId, domainId)).thenReturn(Arrays.asList(subnet2));
+        DataCenterIpv4GuestSubnetVO subnet3 = Mockito.mock(DataCenterIpv4GuestSubnetVO.class);
+        when(dataCenterIpv4GuestSubnetDao.listNonDedicatedByDataCenterId(zoneId)).thenReturn(Arrays.asList(subnet3));
+
+        doReturn(null).doReturn(null).doReturn(ipv4GuestSubnetNetworkMap).when(routedIpv4Manager).getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(eq(cidrSize), any());
+
+        Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, domainId, accountId, zoneId);
+
+        Assert.assertEquals(ipv4GuestSubnetNetworkMap, result);
+        verify(routedIpv4Manager, times(3)).getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(eq(cidrSize), any());
+    }
+
+    @Test
+    public void testGetOrCreateIpv4SubnetForGuestNetworkOrVpcInternalByCidrAndParentSubnet1() {
+        Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, subnetVO);
+        Assert.assertNull(result);
+    }
+
+    @Test
+    public void testGetOrCreateIpv4SubnetForGuestNetworkOrVpcInternalByCidrAndParentSubnet2() {
+        when(subnetVO.getId()).thenReturn(zoneSubnetId);
+        when(ipv4GuestSubnetNetworkMapDao.findFirstAvailable(zoneSubnetId, cidrSize)).thenReturn(ipv4GuestSubnetNetworkMap);
+
+        Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, subnetVO);
+        Assert.assertEquals(ipv4GuestSubnetNetworkMap, result);
+    }
+
+    @Test
+    public void testGetOrCreateIpv4SubnetForGuestNetworkOrVpcInternalByCidrAndParentSubnet3() {
+        when(subnetVO.getId()).thenReturn(zoneSubnetId);
+        when(ipv4GuestSubnetNetworkMapDao.findFirstAvailable(zoneSubnetId, cidrSize)).thenReturn(null);
+        doReturn(ipv4GuestSubnetNetworkMap).when(routedIpv4Manager).createIpv4SubnetFromParentSubnet(subnetVO, cidrSize);
+
+        Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.getOrCreateIpv4SubnetForGuestNetworkOrVpcInternal(cidrSize, subnetVO);
+        Assert.assertEquals(ipv4GuestSubnetNetworkMap, result);
+    }
+
+    @Test
+    public void testGetParentOfNetworkCidr() {
+        when(subnetVO.getId()).thenReturn(zoneSubnetId);
+        when(subnetVO.getSubnet()).thenReturn(subnet);
+        when(dataCenterIpv4GuestSubnetDao.listByDataCenterId(zoneId)).thenReturn(Arrays.asList(subnetVO));
+        when(ipv4GuestSubnetNetworkMapDao.listByParent(zoneSubnetId)).thenReturn(Arrays.asList(ipv4GuestSubnetNetworkMap));
+        when(ipv4GuestSubnetNetworkMap.getSubnet()).thenReturn(subnetForNetwork);
+
+        try {
+            routedIpv4Manager.getParentOfNetworkCidr(zoneId, newSubnetForNetworkTooSmall);
+            Assert.fail("Getting parent of network cidr should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals(String.format("Existing subnet %s has overlap with: %s", subnetForNetwork, newSubnetForNetworkTooSmall), ex.getMessage());
+        }
+
+        try {
+            routedIpv4Manager.getParentOfNetworkCidr(zoneId, newSubnetForNetworkTooBig);
+            Assert.fail("Getting parent of network cidr should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals(String.format("Existing zone subnet %s has overlap with: %s", subnet, newSubnetForNetworkTooBig), ex.getMessage());
+        }
+
+        DataCenterIpv4GuestSubnet result = routedIpv4Manager.getParentOfNetworkCidr(zoneId, newSubnetForNetwork);
+        Assert.assertEquals(subnetVO, result);
+    }
+
+    @Test
+    public void testCreateIpv4SubnetFromParentSubnetByCidr() {
+        when(subnetVO.getSubnet()).thenReturn(subnet);
+        when(subnetVO.getId()).thenReturn(zoneSubnetId);
+
+        try {
+            routedIpv4Manager.createIpv4SubnetFromParentSubnet(subnetVO, newSubnetForNetworkTooBig);
+            Assert.fail("Creating ipv4 subnet should fail.");
+        } catch (CloudRuntimeException ex) {
+            Assert.assertEquals(String.format("networkCidr %s is not within parent cidr: %s", newSubnetForNetworkTooBig, subnet), ex.getMessage());
+        }
+
+        when(ipv4GuestSubnetNetworkMap.getSubnet()).thenReturn(subnetForNetwork);
+        when(ipv4GuestSubnetNetworkMapDao.listByParent(zoneSubnetId)).thenReturn(Arrays.asList(ipv4GuestSubnetNetworkMap));
+        when(ipv4GuestSubnetNetworkMapDao.persist(any())).thenReturn(ipv4GuestSubnetNetworkMap);
+
+        Ipv4GuestSubnetNetworkMap result = routedIpv4Manager.createIpv4SubnetFromParentSubnet(subnetVO, newSubnetForNetwork);
+        Assert.assertEquals(ipv4GuestSubnetNetworkMap, result);
+    }
+
+    @Test
+    public void testCreateIpv4SubnetFromParentSubnetByCidrSize() {
+        when(subnetVO.getId()).thenReturn(zoneSubnetId);
+        when(dataCenterIpv4GuestSubnetDao.findById(zoneSubnetId)).thenReturn(subnetVO);
+
+        Ipv4GuestSubnetNetworkMapVO ipv4GuestSubnetNetworkMap1 = new Ipv4GuestSubnetNetworkMapVO(zoneSubnetId, "172.16.1.0/28", null, Ipv4GuestSubnetNetworkMap.State.Free);
+        Ipv4GuestSubnetNetworkMapVO ipv4GuestSubnetNetworkMap2 = new Ipv4GuestSubnetNetworkMapVO(zoneSubnetId, "172.16.1.64/28", null, Ipv4GuestSubnetNetworkMap.State.Free);
+        when(ipv4GuestSubnetNetworkMapDao.listByParent(zoneSubnetId)).thenReturn(Arrays.asList(ipv4GuestSubnetNetworkMap1, ipv4GuestSubnetNetworkMap2));
+        when(subnetVO.getSubnet()).thenReturn("172.16.1.0/24");
+
+        String networkCidr = routedIpv4Manager.createIpv4SubnetStringFromParentSubnet(subnetVO, 28);
+        Assert.assertEquals("172.16.1.16/28", networkCidr);
+        networkCidr = routedIpv4Manager.createIpv4SubnetStringFromParentSubnet(subnetVO, 27);
+        Assert.assertEquals("172.16.1.32/27", networkCidr);
+        networkCidr = routedIpv4Manager.createIpv4SubnetStringFromParentSubnet(subnetVO, 26);
+        Assert.assertEquals("172.16.1.128/26", networkCidr);
+        networkCidr = routedIpv4Manager.createIpv4SubnetStringFromParentSubnet(subnetVO, 25);
+        Assert.assertEquals("172.16.1.128/25", networkCidr);
+
+        Ipv4GuestSubnetNetworkMapVO ipv4GuestSubnetNetworkMap3 = new Ipv4GuestSubnetNetworkMapVO(zoneSubnetId, "172.16.1.16/28", null, Ipv4GuestSubnetNetworkMap.State.Free);
+        Ipv4GuestSubnetNetworkMapVO ipv4GuestSubnetNetworkMap4 = new Ipv4GuestSubnetNetworkMapVO(zoneSubnetId, "172.16.1.128/28", null, Ipv4GuestSubnetNetworkMap.State.Free);
+        when(ipv4GuestSubnetNetworkMapDao.listByParent(zoneSubnetId)).thenReturn(Arrays.asList(ipv4GuestSubnetNetworkMap1, ipv4GuestSubnetNetworkMap2,
+                ipv4GuestSubnetNetworkMap3, ipv4GuestSubnetNetworkMap4));
+        networkCidr = routedIpv4Manager.createIpv4SubnetStringFromParentSubnet(subnetVO, 28);
+        Assert.assertEquals("172.16.1.80/28", networkCidr);
+        networkCidr = routedIpv4Manager.createIpv4SubnetStringFromParentSubnet(subnetVO, 27);
+        Assert.assertEquals("172.16.1.32/27", networkCidr);
+        networkCidr = routedIpv4Manager.createIpv4SubnetStringFromParentSubnet(subnetVO, 26);
+        Assert.assertEquals("172.16.1.192/26", networkCidr);
+        try {
+            networkCidr = routedIpv4Manager.createIpv4SubnetStringFromParentSubnet(subnetVO, 25);
+            Assert.fail("Creating ipv4 subnet should fail.");
+        } catch (CloudRuntimeException ex) {
+            Assert.assertEquals("Failed to automatically allocate a subnet with specified cidrsize", ex.getMessage());
+        }
+    }
+
+    @Test
+    public void testAssignIpv4SubnetToNetwork() {
+        when(network.getId()).thenReturn(networkId);
+        when(network.getCidr()).thenReturn(subnet);
+        when(ipv4GuestSubnetNetworkMapDao.findBySubnet(subnet)).thenReturn(ipv4GuestSubnetNetworkMap);
+        when(ipv4GuestSubnetNetworkMap.getId()).thenReturn(ipv4GuestSubnetNetworkMapId);
+
+        routedIpv4Manager.assignIpv4SubnetToNetwork(network);
+
+        verify(ipv4GuestSubnetNetworkMapDao).update(eq(ipv4GuestSubnetNetworkMapId), any());
+    }
+
+    @Test
+    public void testAssignIpv4SubnetToVpc() {
+        when(vpc.getId()).thenReturn(vpcId);
+        when(vpc.getCidr()).thenReturn(subnet);
+        when(ipv4GuestSubnetNetworkMapDao.findBySubnet(subnet)).thenReturn(ipv4GuestSubnetNetworkMap);
+        when(ipv4GuestSubnetNetworkMap.getId()).thenReturn(ipv4GuestSubnetNetworkMapId);
+
+        routedIpv4Manager.assignIpv4SubnetToVpc(vpc);
+
+        verify(ipv4GuestSubnetNetworkMapDao).update(eq(ipv4GuestSubnetNetworkMapId), any());
+    }
+
+    @Test
+    public void testCreateRoutingFirewallRule() throws NetworkRuleConflictException {
+        CreateRoutingFirewallRuleCmd cmd = new CreateRoutingFirewallRuleCmd();
+        ReflectionTestUtils.setField(cmd, "protocol", "tcp");
+        List<String> sourceCidrList = Arrays.asList("192.168.0.0/24", "10.0.0.0/8");
+        ReflectionTestUtils.setField(cmd, "sourceCidrList", sourceCidrList);
+        List<String> destinationCidrlist = Arrays.asList("192.168.0.0/24", "10.0.0.0/8");
+        ReflectionTestUtils.setField(cmd, "destinationCidrlist", destinationCidrlist);
+        ReflectionTestUtils.setField(cmd, "publicStartPort", 1111);
+        ReflectionTestUtils.setField(cmd, "publicEndPort", 2222);
+        ReflectionTestUtils.setField(cmd, "networkId", networkId);
+
+        when(networkModel.getNetwork(networkId)).thenReturn(network);
+        when(network.getId()).thenReturn(networkId);
+        when(network.getDomainId()).thenReturn(domainId);
+        when(network.getAccountId()).thenReturn(accountId);
+        VirtualRouterElement virtualRouterElement = new VirtualRouterElement();
+        when(networkModel.getNetworkServiceCapabilities(networkId, Network.Service.Firewall)).thenReturn(virtualRouterElement.getCapabilities().get(Network.Service.Firewall));
+        when(firewallDao.persist(any())).thenReturn(rule);
+        when(firewallDao.setStateToAdd(any())).thenReturn(true);
+
+        // create Ingress rule
+        ReflectionTestUtils.setField(cmd, "trafficType", "ingress");
+        FirewallRule result = routedIpv4Manager.createRoutingFirewallRule(cmd);
+        Assert.assertNotNull(result);
+        Assert.assertEquals(rule, result);
+
+        // create Egress rule
+        ReflectionTestUtils.setField(cmd, "trafficType", "egress");
+        result = routedIpv4Manager.createRoutingFirewallRule(cmd);
+        Assert.assertNotNull(result);
+        Assert.assertEquals(rule, result);
+    }
+
+    @Test
+    public void testUpdateRoutingFirewallRule1() {
+        UpdateRoutingFirewallRuleCmd cmd = new UpdateRoutingFirewallRuleCmd();
+        ReflectionTestUtils.setField(cmd, "id", ruleId);
+
+        when(firewallDao.findById(ruleId)).thenReturn(rule);
+        when(rule.getId()).thenReturn(ruleId);
+        when(rule.getTrafficType()).thenReturn(FirewallRule.TrafficType.Ingress);
+
+        routedIpv4Manager.updateRoutingFirewallRule(cmd);
+
+        verify(firewallManager).updateIngressFirewallRule(ruleId, null, true);
+    }
+
+    @Test
+    public void testUpdateRoutingFirewallRule2() {
+        UpdateRoutingFirewallRuleCmd cmd = new UpdateRoutingFirewallRuleCmd();
+        ReflectionTestUtils.setField(cmd, "id", ruleId);
+
+        when(firewallDao.findById(ruleId)).thenReturn(rule);
+        when(rule.getId()).thenReturn(ruleId);
+        when(rule.getTrafficType()).thenReturn(FirewallRule.TrafficType.Egress);
+
+        routedIpv4Manager.updateRoutingFirewallRule(cmd);
+
+        verify(firewallManager).updateEgressFirewallRule(ruleId, null, true);
+    }
+
+    @Test
+    public void testRevokeRoutingFirewallRule1() {
+        when(firewallDao.findById(ruleId)).thenReturn(rule);
+        when(rule.getId()).thenReturn(ruleId);
+        when(rule.getTrafficType()).thenReturn(FirewallRule.TrafficType.Ingress);
+
+        routedIpv4Manager.revokeRoutingFirewallRule(ruleId);
+
+        verify(firewallManager).revokeIngressFirewallRule(ruleId, true);
+    }
+
+    @Test
+    public void testRevokeRoutingFirewallRule2() {
+        when(firewallDao.findById(ruleId)).thenReturn(rule);
+        when(rule.getId()).thenReturn(ruleId);
+        when(rule.getTrafficType()).thenReturn(FirewallRule.TrafficType.Egress);
+
+        routedIpv4Manager.revokeRoutingFirewallRule(ruleId);
+
+        verify(firewallManager).revokeEgressFirewallRule(ruleId, true);
+    }
+
+    @Test
+    public void testApplyRoutingFirewallRule1() {
+        when(firewallDao.findById(ruleId)).thenReturn(rule);
+        when(rule.getPurpose()).thenReturn(FirewallRule.Purpose.Firewall);
+        when(rule.getNetworkId()).thenReturn(networkId);
+
+        FirewallRuleVO rule1 = Mockito.mock(FirewallRuleVO.class);
+        when(firewallDao.listByNetworkPurposeTrafficType(networkId, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress)).thenReturn(Arrays.asList(rule1));
+        FirewallRuleVO rule2 = Mockito.mock(FirewallRuleVO.class);
+        when(firewallDao.listByNetworkPurposeTrafficType(networkId, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress)).thenReturn(Arrays.asList(rule2));
+        when(firewallManager.applyFirewallRules(any(), eq(false), any())).thenReturn(true);
+
+        boolean result = routedIpv4Manager.applyRoutingFirewallRule(ruleId);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testApplyRoutingFirewallRule2() {
+        when(firewallDao.findById(ruleId)).thenReturn(rule);
+        when(rule.getPurpose()).thenReturn(FirewallRule.Purpose.LoadBalancing);
+
+        boolean result = routedIpv4Manager.applyRoutingFirewallRule(ruleId);
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void testCreateBgpPeer() {
+        CreateBgpPeerCmd cmd = new CreateBgpPeerCmd();
+        ReflectionTestUtils.setField(cmd, "zoneId", zoneId);
+        ReflectionTestUtils.setField(cmd, "ip4Address", ip4Address);
+        ReflectionTestUtils.setField(cmd, "ip6Address", ip6Address);
+        ReflectionTestUtils.setField(cmd, "asNumber", asNumber);
+        ReflectionTestUtils.setField(cmd, "password", password);
+
+        when(bgpPeerDao.findByZoneAndAsNumberAndAddress(zoneId, asNumber, ip4Address, null)).thenReturn(null);
+        when(bgpPeerDao.findByZoneAndAsNumberAndAddress(zoneId, asNumber, null, ip6Address)).thenReturn(null);
+
+        routedIpv4Manager.createBgpPeer(cmd);
+
+        verify(bgpPeerDao).persist(any(BgpPeerVO.class), any(Map.class));
+    }
+
+    @Test
+    public void testCreateBgpPeerResponse() {
+        BgpPeerVO bgpPeer = Mockito.mock(BgpPeerVO.class);
+        when(bgpPeer.getDataCenterId()).thenReturn(zoneId);
+        when(bgpPeer.getDomainId()).thenReturn(domainId);
+        when(bgpPeer.getAccountId()).thenReturn(accountId);
+        when(bgpPeer.getCreated()).thenReturn(created);
+        when(bgpPeer.getAsNumber()).thenReturn(asNumber);
+        when(bgpPeer.getUuid()).thenReturn(bgpPeerUuid);
+        when(bgpPeer.getIp4Address()).thenReturn(ip4Address);
+        when(bgpPeer.getIp6Address()).thenReturn(ip6Address);
+
+        apiDBUtilsMocked.when(() -> ApiDBUtils.findZoneById(zoneId)).thenReturn(zone);
+        when(zone.getName()).thenReturn(zoneName);
+        when(zone.getUuid()).thenReturn(zoneUuid);
+
+        apiDBUtilsMocked.when(() -> ApiDBUtils.findDomainById(domainId)).thenReturn(domain);
+        when(domain.getName()).thenReturn(domainName);
+        when(domain.getUuid()).thenReturn(domainUuid);
+
+        apiDBUtilsMocked.when(() -> ApiDBUtils.findAccountById(accountId)).thenReturn(account);
+        when(account.getType()).thenReturn(Account.Type.PROJECT);
+        when(account.getId()).thenReturn(accountId);
+
+        apiDBUtilsMocked.when(() -> ApiDBUtils.findProjectByProjectAccountId(accountId)).thenReturn(project);
+        when(project.getName()).thenReturn(projectName);
+        when(project.getUuid()).thenReturn(projectUuid);
+
+        BgpPeerResponse response = routedIpv4Manager.createBgpPeerResponse(bgpPeer);
+
+        Assert.assertEquals(created, response.getCreated());
+        Assert.assertEquals(asNumber, response.getAsNumber());
+        Assert.assertEquals(ip4Address, response.getIp4Address());
+        Assert.assertEquals(ip6Address, response.getIp6Address());
+        Assert.assertEquals(bgpPeerUuid, response.getId());
+        Assert.assertEquals(zoneUuid, response.getZoneId());
+        Assert.assertEquals(zoneName, response.getZoneName());
+        Assert.assertEquals(domainUuid, response.getDomainId());
+        Assert.assertEquals(domainName, response.getDomainName());
+        Assert.assertEquals(projectName, response.getProjectName());
+        Assert.assertEquals(projectUuid, response.getProjectId());
+        Assert.assertNull(response.getAccountName());
+
+        Assert.assertEquals("bgppeer", response.getObjectName());
+
+    }
+
+    @Test
+    public void testDeleteBgpPeer1() {
+        DeleteBgpPeerCmd cmd = new DeleteBgpPeerCmd();
+        ReflectionTestUtils.setField(cmd, "id", bgpPeerId);
+
+        BgpPeerNetworkMapVO bgpPeerNetworkMapVO = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMapDao.listByBgpPeerId(bgpPeerId)).thenReturn(Arrays.asList(bgpPeerNetworkMapVO));
+
+        try {
+            routedIpv4Manager.deleteBgpPeer(cmd);
+            Assert.fail("Deleting BGP peer should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals("The BGP peer is being used by 1 guest networks.", ex.getMessage());
+        }
+    }
+
+    @Test
+    public void testDeleteBgpPeer2() {
+        DeleteBgpPeerCmd cmd = new DeleteBgpPeerCmd();
+        ReflectionTestUtils.setField(cmd, "id", bgpPeerId);
+
+        routedIpv4Manager.deleteBgpPeer(cmd);
+
+        verify(bgpPeerDao).remove(bgpPeerId);
+    }
+
+    @Test
+    public void testUpdateBgpPeer() {
+        UpdateBgpPeerCmd cmd = new UpdateBgpPeerCmd();
+        ReflectionTestUtils.setField(cmd, "id", bgpPeerId);
+        ReflectionTestUtils.setField(cmd, "asNumber", asNumber+1);
+        ReflectionTestUtils.setField(cmd, "ip4Address", ip4Address + "1");
+        ReflectionTestUtils.setField(cmd, "ip6Address", ip6Address + "1");
+
+        when(bgpPeerDao.findById(bgpPeerId)).thenReturn(bgpPeer);
+        when(bgpPeer.getDataCenterId()).thenReturn(zoneId);
+
+        routedIpv4Manager.updateBgpPeer(cmd);
+
+        verify(bgpPeerDao).update(bgpPeerId, bgpPeer);
+        verify(bgpPeerDao).findByZoneAndAsNumberAndAddress(zoneId, asNumber+1, ip4Address + "1", null);
+        verify(bgpPeerDao).findByZoneAndAsNumberAndAddress(zoneId, asNumber+1, null, ip6Address + "1");
+    }
+
+    @Test
+    public void testDedicateBgpPeer() {
+        DedicateBgpPeerCmd cmd = new DedicateBgpPeerCmd();
+        ReflectionTestUtils.setField(cmd,"id", bgpPeerId);
+        ReflectionTestUtils.setField(cmd,"domainId", domainId);
+        ReflectionTestUtils.setField(cmd,"accountName", accountName);
+        ReflectionTestUtils.setField(cmd,"projectId", null);
+
+        when(bgpPeerDao.findById(bgpPeerId)).thenReturn(bgpPeer);
+        when(accountManager.finalyzeAccountId(accountName, domainId, null, false)).thenReturn(accountId);
+        when(accountManager.getAccount(accountId)).thenReturn(account);
+        when(account.getDomainId()).thenReturn(domainId);
+
+        routedIpv4Manager.dedicateBgpPeer(cmd);
+
+        verify(bgpPeerDao).update(bgpPeerId, bgpPeer);
+        verify(bgpPeerNetworkMapDao).listUsedNetworksByOtherDomains(bgpPeerId, domainId);
+        verify(bgpPeerNetworkMapDao).listUsedVpcsByOtherDomains(bgpPeerId, domainId);
+        verify(bgpPeerNetworkMapDao).listUsedNetworksByOtherAccounts(bgpPeerId, accountId);
+        verify(bgpPeerNetworkMapDao).listUsedVpcsByOtherAccounts(bgpPeerId, accountId);
+    }
+
+    @Test
+    public void testReleaseDedicatedBgpPeer() {
+        ReleaseDedicatedBgpPeerCmd cmd = new ReleaseDedicatedBgpPeerCmd();
+        ReflectionTestUtils.setField(cmd,"id", bgpPeerId);
+        when(bgpPeerDao.findById(bgpPeerId)).thenReturn(bgpPeer);
+
+        routedIpv4Manager.releaseDedicatedBgpPeer(cmd);
+
+        verify(bgpPeer).setDomainId(null);
+        verify(bgpPeer).setAccountId(null);
+        verify(bgpPeerDao).update(bgpPeerId, bgpPeer);
+    }
+
+    @Test
+    public void testChangeBgpPeersForNetwork() {
+        ChangeBgpPeersForNetworkCmd cmd = new ChangeBgpPeersForNetworkCmd();
+        ReflectionTestUtils.setField(cmd,"networkId", networkId);
+        List<Long> bgpPeerIds = Arrays.asList(bgpPeerId);
+        ReflectionTestUtils.setField(cmd,"bgpPeerIds", bgpPeerIds);
+
+        when(networkDao.findById(networkId)).thenReturn(network);
+
+        try {
+            when(network.getVpcId()).thenReturn(vpcId);
+            routedIpv4Manager.changeBgpPeersForNetwork(cmd);
+            Assert.fail("Changing BGP peers for guest network should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals("The BGP peers of VPC tiers will inherit from the VPC, do not add separately.", ex.getMessage());
+        }
+
+        when(network.getVpcId()).thenReturn(null);
+        when(network.getAccountId()).thenReturn(accountId);
+        when(accountManager.getAccount(accountId)).thenReturn(account);
+        when(network.getNetworkOfferingId()).thenReturn(networkOfferingId);
+        when(networkOfferingDao.findById(networkOfferingId)).thenReturn(networkOffering);
+        when(network.getDataCenterId()).thenReturn(zoneId);
+
+        try {
+            when(networkOffering.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.ROUTED);
+            when(networkOffering.getRoutingMode()).thenReturn(NetworkOffering.RoutingMode.Static);
+            routedIpv4Manager.changeBgpPeersForNetwork(cmd);
+            Assert.fail("Changing BGP peers for guest network should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals("The network does not support Dynamic routing", ex.getMessage());
+        }
+
+        when(networkOffering.getRoutingMode()).thenReturn(NetworkOffering.RoutingMode.Dynamic);
+
+        doNothing().when(routedIpv4Manager).validateBgpPeers(account, zoneId, bgpPeerIds);
+        doReturn(network).when(routedIpv4Manager).changeBgpPeersForNetworkInternal(network, bgpPeerIds);
+
+        routedIpv4Manager.changeBgpPeersForNetwork(cmd);
+
+        verify(routedIpv4Manager).validateBgpPeers(account, zoneId, bgpPeerIds);
+        verify(routedIpv4Manager).changeBgpPeersForNetworkInternal(network, bgpPeerIds);
+    }
+
+    @Test
+    public void testChangeBgpPeersForNetworkInternal() throws ResourceUnavailableException {
+        Long bgpPeerId1 = 11L; // to be kept
+        Long bgpPeerId2 = 12L; // to be removed
+        Long bgpPeerId3 = 13L; // to be added
+        Long bgpPeerNetworkMapId2 = 14L; // to be removed
+
+        when(network.getId()).thenReturn(networkId);
+        when(networkDao.findById(networkId)).thenReturn(network);
+
+        BgpPeerNetworkMapVO bgpPeerNetworkMap1 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap1.getBgpPeerId()).thenReturn(bgpPeerId1);
+        when(bgpPeerNetworkMap1.getState()).thenReturn(BgpPeer.State.Active);
+        BgpPeerNetworkMapVO bgpPeerNetworkMap2 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap2.getBgpPeerId()).thenReturn(bgpPeerId2);
+        when(bgpPeerNetworkMap2.getState()).thenReturn(BgpPeer.State.Revoke);
+        BgpPeerNetworkMapVO bgpPeerNetworkMap3 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap3.getState()).thenReturn(BgpPeer.State.Add);
+
+        when(bgpPeerNetworkMap2.getId()).thenReturn(bgpPeerNetworkMapId2);
+
+        when(bgpPeerNetworkMapDao.listByNetworkId(networkId)).thenReturn(Arrays.asList(bgpPeerNetworkMap1, bgpPeerNetworkMap2))
+                .thenReturn(Arrays.asList(bgpPeerNetworkMap1, bgpPeerNetworkMap2, bgpPeerNetworkMap3));
+        when(bgpService.applyBgpPeers(network, false)).thenReturn(true);
+
+        Network result = routedIpv4Manager.changeBgpPeersForNetworkInternal(network, Arrays.asList(bgpPeerId1, bgpPeerId3));
+        Assert.assertEquals(network, result);
+
+        verify(bgpPeerNetworkMap2).setState(BgpPeer.State.Revoke);
+        verify(bgpPeerNetworkMapDao).persist(any());
+        verify(bgpPeerNetworkMap3).setState(BgpPeer.State.Active);
+        verify(bgpPeerNetworkMapDao).remove(bgpPeerNetworkMapId2);
+    }
+
+    @Test
+    public void testChangeBgpPeersForNetworkInternalFailure() throws ResourceUnavailableException {
+        Long bgpPeerId1 = 11L; // to be kept
+        Long bgpPeerId2 = 12L; // to be removed, but finally not
+        Long bgpPeerId3 = 13L; // to be added, but finally not
+        Long bgpPeerNetworkMapId3 = 15L; // to be added, but finally not
+
+        when(network.getId()).thenReturn(networkId);
+
+        BgpPeerNetworkMapVO bgpPeerNetworkMap1 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap1.getBgpPeerId()).thenReturn(bgpPeerId1);
+        when(bgpPeerNetworkMap1.getState()).thenReturn(BgpPeer.State.Active);
+        BgpPeerNetworkMapVO bgpPeerNetworkMap2 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap2.getBgpPeerId()).thenReturn(bgpPeerId2);
+        when(bgpPeerNetworkMap2.getState()).thenReturn(BgpPeer.State.Revoke);
+        BgpPeerNetworkMapVO bgpPeerNetworkMap3 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap3.getState()).thenReturn(BgpPeer.State.Add);
+
+        when(bgpPeerNetworkMap3.getId()).thenReturn(bgpPeerNetworkMapId3);
+
+        when(bgpPeerNetworkMapDao.listByNetworkId(networkId)).thenReturn(Arrays.asList(bgpPeerNetworkMap1, bgpPeerNetworkMap2))
+                .thenReturn(Arrays.asList(bgpPeerNetworkMap1, bgpPeerNetworkMap2, bgpPeerNetworkMap3));
+        when(bgpService.applyBgpPeers(network, false)).thenReturn(false);
+
+        Network result = routedIpv4Manager.changeBgpPeersForNetworkInternal(network, Arrays.asList(bgpPeerId1, bgpPeerId3));
+        Assert.assertNull(result);
+
+        verify(bgpPeerNetworkMap2).setState(BgpPeer.State.Revoke);
+        verify(bgpPeerNetworkMapDao).persist(any());
+        verify(bgpPeerNetworkMap2).setState(BgpPeer.State.Add);
+        verify(bgpPeerNetworkMapDao).remove(bgpPeerNetworkMapId3);
+    }
+
+    @Test
+    public void testValidateBgpPeers() {
+        List<Long> bgpPeerIds = Arrays.asList(bgpPeerId);
+        try {
+            routedIpv4Manager.validateBgpPeers(account, zoneId, bgpPeerIds);
+            Assert.fail("Validating BGP peers for guest network should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals(String.format("Invalid BGP peer ID: %s", bgpPeerId), ex.getMessage());
+        }
+
+        when(account.getDomainId()).thenReturn(domainId);
+        when(account.getAccountId()).thenReturn(accountId);
+        when(bgpPeerDao.findById(bgpPeerId)).thenReturn(bgpPeer);
+        when(bgpPeer.getUuid()).thenReturn(bgpPeerUuid);
+        try {
+            when(bgpPeer.getDataCenterId()).thenReturn(zoneId + 1);
+            routedIpv4Manager.validateBgpPeers(account, zoneId, bgpPeerIds);
+            Assert.fail("Validating BGP peers for guest network should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals(String.format("BGP peer (ID: %s) belongs to a different zone", bgpPeerUuid), ex.getMessage());
+        }
+
+        when(bgpPeer.getDataCenterId()).thenReturn(zoneId);
+        try {
+            when(bgpPeer.getDomainId()).thenReturn(domainId + 1);
+            routedIpv4Manager.validateBgpPeers(account, zoneId, bgpPeerIds);
+            Assert.fail("Validating BGP peers for guest network should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals(String.format("BGP peer (ID: %s) belongs to a different domain", bgpPeerUuid), ex.getMessage());
+        }
+
+        when(bgpPeer.getDomainId()).thenReturn(domainId);
+        try {
+            when(bgpPeer.getAccountId()).thenReturn(accountId + 1);
+            routedIpv4Manager.validateBgpPeers(account, zoneId, bgpPeerIds);
+            Assert.fail("Validating BGP peers for guest network should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals(String.format("BGP peer (ID: %s) belongs to a different account", bgpPeerUuid), ex.getMessage());
+        }
+
+        when(bgpPeer.getAccountId()).thenReturn(accountId);
+        routedIpv4Manager.validateBgpPeers(account, zoneId, bgpPeerIds);
+    }
+
+    @Test
+    public void testChangeBgpPeersForVpc() {
+        ChangeBgpPeersForVpcCmd cmd = new ChangeBgpPeersForVpcCmd();
+        ReflectionTestUtils.setField(cmd,"vpcId", vpcId);
+        List<Long> bgpPeerIds = Arrays.asList(bgpPeerId);
+        ReflectionTestUtils.setField(cmd,"bgpPeerIds", bgpPeerIds);
+
+        when(vpcDao.findById(vpcId)).thenReturn(vpc);
+        when(vpc.getAccountId()).thenReturn(accountId);
+        when(accountManager.getAccount(accountId)).thenReturn(account);
+        when(vpc.getVpcOfferingId()).thenReturn(vpcOfferingId);
+        when(vpcOfferingDao.findById(vpcOfferingId)).thenReturn(vpcOffering);
+        when(vpc.getZoneId()).thenReturn(zoneId);
+
+        try {
+            when(vpcOffering.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.ROUTED);
+            when(vpcOffering.getRoutingMode()).thenReturn(NetworkOffering.RoutingMode.Static);
+            routedIpv4Manager.changeBgpPeersForVpc(cmd);
+            Assert.fail("Changing BGP peers for VPC should fail.");
+        } catch (InvalidParameterValueException ex) {
+            Assert.assertEquals("The VPC does not support Dynamic routing", ex.getMessage());
+        }
+
+        when(vpcOffering.getRoutingMode()).thenReturn(NetworkOffering.RoutingMode.Dynamic);
+
+        doNothing().when(routedIpv4Manager).validateBgpPeers(account, zoneId, bgpPeerIds);
+        doReturn(vpc).when(routedIpv4Manager).changeBgpPeersForVpcInternal(vpc, bgpPeerIds);
+
+        routedIpv4Manager.changeBgpPeersForVpc(cmd);
+
+        verify(routedIpv4Manager).validateBgpPeers(account, zoneId, bgpPeerIds);
+        verify(routedIpv4Manager).changeBgpPeersForVpcInternal(vpc, bgpPeerIds);
+    }
+
+    @Test
+    public void testChangeBgpPeersForVpcInternal() throws ResourceUnavailableException {
+        Long bgpPeerId1 = 11L; // to be kept
+        Long bgpPeerId2 = 12L; // to be removed
+        Long bgpPeerId3 = 13L; // to be added
+        Long bgpPeerNetworkMapId2 = 14L; // to be removed
+
+        when(vpc.getId()).thenReturn(vpcId);
+        when(vpcDao.findById(vpcId)).thenReturn(vpc);
+
+        BgpPeerNetworkMapVO bgpPeerNetworkMap1 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap1.getBgpPeerId()).thenReturn(bgpPeerId1);
+        when(bgpPeerNetworkMap1.getState()).thenReturn(BgpPeer.State.Active);
+        BgpPeerNetworkMapVO bgpPeerNetworkMap2 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap2.getBgpPeerId()).thenReturn(bgpPeerId2);
+        when(bgpPeerNetworkMap2.getState()).thenReturn(BgpPeer.State.Revoke);
+        BgpPeerNetworkMapVO bgpPeerNetworkMap3 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap3.getState()).thenReturn(BgpPeer.State.Add);
+
+        when(bgpPeerNetworkMap2.getId()).thenReturn(bgpPeerNetworkMapId2);
+
+        when(bgpPeerNetworkMapDao.listByVpcId(vpcId)).thenReturn(Arrays.asList(bgpPeerNetworkMap1, bgpPeerNetworkMap2))
+                .thenReturn(Arrays.asList(bgpPeerNetworkMap1, bgpPeerNetworkMap2, bgpPeerNetworkMap3));
+        when(bgpService.applyBgpPeers(vpc, false)).thenReturn(true);
+
+        Vpc result = routedIpv4Manager.changeBgpPeersForVpcInternal(vpc, Arrays.asList(bgpPeerId1, bgpPeerId3));
+        Assert.assertEquals(vpc, result);
+
+        verify(bgpPeerNetworkMap2).setState(BgpPeer.State.Revoke);
+        verify(bgpPeerNetworkMapDao).persist(any());
+        verify(bgpPeerNetworkMap3).setState(BgpPeer.State.Active);
+        verify(bgpPeerNetworkMapDao).remove(bgpPeerNetworkMapId2);
+    }
+
+    @Test
+    public void testChangeBgpPeersForVpcInternalFailure() throws ResourceUnavailableException {
+        Long bgpPeerId1 = 11L; // to be kept
+        Long bgpPeerId2 = 12L; // to be removed, but finally not
+        Long bgpPeerId3 = 13L; // to be added, but finally not
+        Long bgpPeerNetworkMapId3 = 15L; // to be added, but finally not
+
+        when(vpc.getId()).thenReturn(vpcId);
+
+        BgpPeerNetworkMapVO bgpPeerNetworkMap1 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap1.getBgpPeerId()).thenReturn(bgpPeerId1);
+        when(bgpPeerNetworkMap1.getState()).thenReturn(BgpPeer.State.Active);
+        BgpPeerNetworkMapVO bgpPeerNetworkMap2 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap2.getBgpPeerId()).thenReturn(bgpPeerId2);
+        when(bgpPeerNetworkMap2.getState()).thenReturn(BgpPeer.State.Revoke);
+        BgpPeerNetworkMapVO bgpPeerNetworkMap3 = Mockito.mock(BgpPeerNetworkMapVO.class);
+        when(bgpPeerNetworkMap3.getState()).thenReturn(BgpPeer.State.Add);
+
+        when(bgpPeerNetworkMap3.getId()).thenReturn(bgpPeerNetworkMapId3);
+
+        when(bgpPeerNetworkMapDao.listByVpcId(vpcId)).thenReturn(Arrays.asList(bgpPeerNetworkMap1, bgpPeerNetworkMap2))
+                .thenReturn(Arrays.asList(bgpPeerNetworkMap1, bgpPeerNetworkMap2, bgpPeerNetworkMap3));
+        when(bgpService.applyBgpPeers(vpc, false)).thenReturn(false);
+
+        Vpc result = routedIpv4Manager.changeBgpPeersForVpcInternal(vpc, Arrays.asList(bgpPeerId1, bgpPeerId3));
+        Assert.assertNull(result);
+
+        verify(bgpPeerNetworkMap2).setState(BgpPeer.State.Revoke);
+        verify(bgpPeerNetworkMapDao).persist(any());
+        verify(bgpPeerNetworkMap2).setState(BgpPeer.State.Add);
+        verify(bgpPeerNetworkMapDao).remove(bgpPeerNetworkMapId3);
+    }
+
+    @Test
+    public void testRemoveIpv4SubnetsForZoneByAccountId() {
+        when(dataCenterIpv4GuestSubnetDao.listByAccountId(accountId)).thenReturn(Arrays.asList(subnetVO));
+        when(subnetVO.getId()).thenReturn(zoneSubnetId);
+
+        routedIpv4Manager.removeIpv4SubnetsForZoneByAccountId(accountId);
+
+        verify(ipv4GuestSubnetNetworkMapDao).deleteByParentId(zoneSubnetId);
+        verify(dataCenterIpv4GuestSubnetDao).remove(zoneSubnetId);
+    }
+
+    @Test
+    public void testRemoveIpv4SubnetsForZoneByDomainId() {
+        when(dataCenterIpv4GuestSubnetDao.listByDomainId(domainId)).thenReturn(Arrays.asList(subnetVO));
+        when(subnetVO.getId()).thenReturn(zoneSubnetId);
+
+        routedIpv4Manager.removeIpv4SubnetsForZoneByDomainId(domainId);
+
+        verify(ipv4GuestSubnetNetworkMapDao).deleteByParentId(zoneSubnetId);
+        verify(dataCenterIpv4GuestSubnetDao).remove(zoneSubnetId);
+    }
+}
diff --git a/ui/src/config/section/infra/zones.js b/ui/src/config/section/infra/zones.js
index 25535979e4d..b4a34372e10 100644
--- a/ui/src/config/section/infra/zones.js
+++ b/ui/src/config/section/infra/zones.js
@@ -74,13 +74,16 @@ export default {
     component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/PhysicalNetworksTab.vue')))
   }, {
     name: 'ipv4.subnets',
-    component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/Ipv4GuestSubnetsTab.vue')))
+    component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/Ipv4GuestSubnetsTab.vue'))),
+    show: (record) => { return record.routedmodeenabled && 'listIpv4SubnetsForZone' in store.getters.apis }
   }, {
     name: 'asnumber',
-    component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/AsNumbersTab.vue')))
+    component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/AsNumbersTab.vue'))),
+    show: (record) => { return record.routedmodeenabled && 'listASNumbers' in store.getters.apis }
   }, {
     name: 'bgp.peers',
-    component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/BgpPeersTab.vue')))
+    component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/BgpPeersTab.vue'))),
+    show: (record) => { return record.routedmodeenabled && 'listBgpPeers' in store.getters.apis }
   }, {
     name: 'system.vms',
     component: shallowRef(defineAsyncComponent(() => import('@/views/infra/zone/SystemVmsTab.vue'))),
diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js
index 79eae34f537..3bb2c75eabf 100644
--- a/ui/src/config/section/network.js
+++ b/ui/src/config/section/network.js
@@ -872,7 +872,14 @@ export default {
       icon: 'partition-outlined',
       permission: ['listASNumbers'],
       show: () => {
-        return ['Admin'].includes(store.getters.userInfo.roletype)
+        if (!store.getters.zones || store.getters.zones.length === 0) {
+          return false
+        }
+        const AdvancedZonesWithRoutedmode = store.getters.zones.filter(zone => zone.routedmodeenabled)
+        if (isAdmin() && (AdvancedZonesWithRoutedmode && AdvancedZonesWithRoutedmode.length > 0)) {
+          return true
+        }
+        return false
       },
       filters: ['all', 'allocatedonly', 'free'],
       columns: ['asnumber', 'allocationstate', 'asnrange', 'associatednetworkname', 'vpcname', 'allocated', 'account', 'domain', 'zonename'],
@@ -1446,7 +1453,11 @@ export default {
         if (!store.getters.zones || store.getters.zones.length === 0) {
           return false
         }
-        return isAdmin()
+        const AdvancedZonesWithRoutedmode = store.getters.zones.filter(zone => zone.routedmodeenabled)
+        if (isAdmin() && (AdvancedZonesWithRoutedmode && AdvancedZonesWithRoutedmode.length > 0)) {
+          return true
+        }
+        return false
       },
       actions: [
         {
diff --git a/ui/src/views/network/CreateIpv4SubnetForNetwork.vue b/ui/src/views/network/CreateIpv4SubnetForNetwork.vue
index 44af8246066..af1ef8c0e25 100644
--- a/ui/src/views/network/CreateIpv4SubnetForNetwork.vue
+++ b/ui/src/views/network/CreateIpv4SubnetForNetwork.vue
@@ -150,6 +150,7 @@ export default {
       const params = { showicon: true }
       api('listZones', params).then(json => {
         this.zones = json.listzonesresponse.zone || []
+        this.zones = this.zones.filter(zone => zone.routedmodeenabled)
         this.form.zoneid = this.zones[0].id || ''
         this.fetchParentSubnets(this.form.zoneid)
       }).finally(() => {
diff --git a/ui/src/views/network/CreateIsolatedNetworkForm.vue b/ui/src/views/network/CreateIsolatedNetworkForm.vue
index b60223219e7..2c3fa17fa35 100644
--- a/ui/src/views/network/CreateIsolatedNetworkForm.vue
+++ b/ui/src/views/network/CreateIsolatedNetworkForm.vue
@@ -552,8 +552,9 @@ export default {
       this.selectedNetworkOffering = {}
       api('listNetworkOfferings', params).then(json => {
         this.networkOfferings = json.listnetworkofferingsresponse.networkoffering
-        if (this.selectedZone.isnsxenabled) {
-          this.networkOfferings = this.networkOfferings.filter(offering => offering.fornsx)
+        this.networkOfferings = this.networkOfferings.filter(offering => offering.fornsx === this.selectedZone.isnsxenabled)
+        if (!this.selectedZone.routedmodeenabled) {
+          this.networkOfferings = this.networkOfferings.filter(offering => offering.networkmode !== 'ROUTED')
         }
       }).catch(error => {
         this.$notifyError(error)
diff --git a/ui/src/views/network/CreateVpc.vue b/ui/src/views/network/CreateVpc.vue
index b0a56ca724a..6fb9a712262 100644
--- a/ui/src/views/network/CreateVpc.vue
+++ b/ui/src/views/network/CreateVpc.vue
@@ -345,6 +345,10 @@ export default {
       this.loadingOffering = true
       api('listVPCOfferings', { zoneid: this.form.zoneid, state: 'Enabled' }).then((response) => {
         this.vpcOfferings = response.listvpcofferingsresponse.vpcoffering
+        this.vpcOfferings = this.vpcOfferings.filter(offering => offering.fornsx === this.selectedZone.isnsxenabled)
+        if (!this.selectedZone.routedmodeenabled) {
+          this.vpcOfferings = this.vpcOfferings.filter(offering => offering.networkmode !== 'ROUTED')
+        }
         this.form.vpcofferingid = this.vpcOfferings[0].id || ''
         this.selectedVpcOffering = this.vpcOfferings[0] || {}
       }).finally(() => {
diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue
index 66d7a4a675e..f637823812e 100644
--- a/ui/src/views/offering/AddNetworkOffering.vue
+++ b/ui/src/views/offering/AddNetworkOffering.vue
@@ -615,6 +615,7 @@ export default {
       zones: [],
       zoneLoading: false,
       ipv6NetworkOfferingEnabled: false,
+      routedNetworkEnabled: false,
       loading: false,
       networkmode: '',
       networkmodes: [
@@ -704,6 +705,7 @@ export default {
       this.fetchSupportedServiceData()
       this.fetchServiceOfferingData()
       this.fetchIpv6NetworkOfferingConfiguration()
+      this.fetchRoutedNetworkConfiguration()
     },
     isAdmin () {
       return isAdmin()
@@ -732,6 +734,17 @@ export default {
         this.ipv6NetworkOfferingEnabled = value === 'true'
       })
     },
+    fetchRoutedNetworkConfiguration () {
+      this.routedNetworkEnabled = false
+      var params = { name: 'routed.network.vpc.enabled' }
+      api('listConfigurations', params).then(json => {
+        var value = json?.listconfigurationsresponse?.configuration?.[0].value || null
+        this.routedNetworkEnabled = value === 'true'
+        if (!this.routedNetworkEnabled) {
+          this.networkmodes.pop()
+        }
+      })
+    },
     fetchZoneData () {
       const params = {}
       params.showicon = true
diff --git a/ui/src/views/offering/AddVpcOffering.vue b/ui/src/views/offering/AddVpcOffering.vue
index c914467a088..450ee117715 100644
--- a/ui/src/views/offering/AddVpcOffering.vue
+++ b/ui/src/views/offering/AddVpcOffering.vue
@@ -283,6 +283,7 @@ export default {
       sourceNatServiceChecked: false,
       selectedServiceProviderMap: {},
       ipv6NetworkOfferingEnabled: false,
+      routedNetworkEnabled: false,
       routingMode: 'static',
       networkmode: '',
       networkmodes: [
@@ -351,6 +352,7 @@ export default {
       this.fetchZoneData()
       this.fetchSupportedServiceData()
       this.fetchIpv6NetworkOfferingConfiguration()
+      this.fetchRoutedNetworkConfiguration()
     },
     isAdmin () {
       return isAdmin()
@@ -363,6 +365,17 @@ export default {
         this.ipv6NetworkOfferingEnabled = value === 'true'
       })
     },
+    fetchRoutedNetworkConfiguration () {
+      this.routedNetworkEnabled = false
+      var params = { name: 'routed.network.vpc.enabled' }
+      api('listConfigurations', params).then(json => {
+        var value = json?.listconfigurationsresponse?.configuration?.[0].value || null
+        this.routedNetworkEnabled = value === 'true'
+        if (!this.routedNetworkEnabled) {
+          this.networkmodes.pop()
+        }
+      })
+    },
     fetchDomainData () {
       const params = {}
       params.listAll = true