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

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


The following commit(s) were added to refs/heads/main by this push:
     new f8d8a9c7b38 NSX Integration fixes (#8906)
f8d8a9c7b38 is described below

commit f8d8a9c7b389ea77a3559b5d69560f8ac5b0e355
Author: Pearl Dsilva <pearl1...@gmail.com>
AuthorDate: Fri Sep 6 15:56:50 2024 -0400

    NSX Integration fixes (#8906)
    
    * Prevent addition of duplicate PF rules on scale up and no rules left 
behind on scale down (#32)
    
    * fix missing dependency injection
    
    * NSX: Fix concurrency issues on port forwarding rules deletion (#37)
    
    * Fix concurrency issues on port forwarding rules deletion
    
    * Refactor objectExists
    
    * Fix unit test
    
    * Fix test
    
    * Small fixes
    
    * CKS: Externalize control and worker node setup wait time and installation 
attempts (#38)
    
    * NSX: Add shared network support (#41)
    
    * NSX: Fix number of physical networks for Guest traffic checks and 
leftover rules on CKS cluster deletion (#45)
    
    * Fix pf rules removal on CKS cluster deletion
    
    * Fix check for number of physical networks for guest traffic
    
    * Fix unit test
    
    * fix logger
    
    * NSX: Handle CheckHealthCommand to avoid host disconnection and errors on 
APIs
    
    * NSX: Handle CheckHealthCommand to avoid host disconnection and errors on 
APIs
    
    * Remove unused string
    
    * fix logger
    
    * Update UDP active monitor to ICMP
    
    * Fix NPE on restarting VPC with additional public IPs
    
    * NSX / VPC: Reuse Source NAT IP from systemVM range on restarts
    
    * CKS: Public IP not found for VPC networks
    
    * Externalize retries and inverval for NSX segment deletion (#67)
    
    * remove unused import
    
    * remove duplicate imports
    
    * remove unused import
    
    * revert externalizing cks settings
    
    * fix test
    
    * Refactor log messages
    
    * Address comments
    
    * Fix issue caused due to forward merge: 90fe1d
    
    ---------
    
    Co-authored-by: Nicolas Vazquez <nicovazque...@gmail.com>
    Co-authored-by: Rohit Yadav <rohit.ya...@shapeblue.com>
---
 .../java/com/cloud/network/nsx/NsxService.java     |  10 ++
 .../java/com/cloud/network/vpc/VpcManager.java     |   5 +-
 .../engine/orchestration/NetworkOrchestrator.java  |   2 +-
 .../resourcedetail/FirewallRuleDetailVO.java       |   4 +
 .../cloudstack/affinity/HostAffinityProcessor.java |   8 +-
 .../affinity/HostAntiAffinityProcessor.java        |   8 +-
 .../KubernetesClusterActionWorker.java             |   2 +-
 ...ernetesClusterResourceModifierActionWorker.java |  65 ++++++-----
 .../KubernetesClusterStartWorker.java              |   2 +
 .../main/java/org/apache/cloudstack/NsxAnswer.java |  10 ++
 .../apache/cloudstack/resource/NsxResource.java    |  28 +++--
 .../apache/cloudstack/service/NsxApiClient.java    | 106 ++++++++++++-----
 .../org/apache/cloudstack/service/NsxElement.java  | 125 ++++++++++++++-------
 .../apache/cloudstack/service/NsxServiceImpl.java  |  24 ++--
 .../cloudstack/utils/NsxControllerUtils.java       |   3 +
 .../cloudstack/service/NsxApiClientTest.java       |  15 +++
 .../apache/cloudstack/service/NsxElementTest.java  |   4 +
 .../configuration/ConfigurationManagerImpl.java    |   2 +-
 .../java/com/cloud/network/NetworkServiceImpl.java |   2 +-
 .../cloud/network/router/VpcNetworkHelperImpl.java |   1 +
 .../java/com/cloud/network/vpc/VpcManagerImpl.java |  33 ++++--
 .../deployment/VpcRouterDeploymentDefinition.java  |   6 +-
 .../VpcRouterDeploymentDefinitionTest.java         |   2 +-
 ui/src/views/network/CreateSharedNetworkForm.vue   |  11 +-
 24 files changed, 338 insertions(+), 140 deletions(-)

diff --git a/api/src/main/java/com/cloud/network/nsx/NsxService.java 
b/api/src/main/java/com/cloud/network/nsx/NsxService.java
index 79ad9547c73..bc4e6aafbfe 100644
--- a/api/src/main/java/com/cloud/network/nsx/NsxService.java
+++ b/api/src/main/java/com/cloud/network/nsx/NsxService.java
@@ -18,9 +18,19 @@ package com.cloud.network.nsx;
 
 import com.cloud.network.IpAddress;
 import com.cloud.network.vpc.Vpc;
+import org.apache.cloudstack.framework.config.ConfigKey;
 
 public interface NsxService {
 
+    ConfigKey<Integer> NSX_API_FAILURE_RETRIES = new ConfigKey<>("Advanced", 
Integer.class,
+            "nsx.api.failure.retries", "30",
+            "Number of retries for NSX API operations in case of failures",
+            true, ConfigKey.Scope.Zone);
+    ConfigKey<Integer> NSX_API_FAILURE_INTERVAL = new ConfigKey<>("Advanced", 
Integer.class,
+            "nsx.api.failure.interval", "60",
+            "Waiting time (in seconds) before retrying an NSX API operation in 
case of failure",
+            true, ConfigKey.Scope.Zone);
+
     boolean createVpcNetwork(Long zoneId, long accountId, long domainId, Long 
vpcId, String vpcName, boolean sourceNatEnabled);
     boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address);
 }
diff --git 
a/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java 
b/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java
index c6279e08012..a340f49c13f 100644
--- a/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java
+++ b/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java
@@ -115,7 +115,8 @@ public interface VpcManager {
             throws ConcurrentOperationException, 
InsufficientCapacityException, ResourceAllocationException;
 
     /**
-     * Assigns source nat public IP address to VPC
+     * Assigns source nat public IP address to VPC.
+     * In case of NSX backed VPCs: CloudStack deploys VRs with Public NIC IP 
different to the VPC source NAT IP, the source NAT IP is on the NSX Public range
      *
      * @param owner
      * @param vpc
@@ -123,7 +124,7 @@ public interface VpcManager {
      * @throws InsufficientAddressCapacityException
      * @throws ConcurrentOperationException
      */
-    PublicIp assignSourceNatIpAddressToVpc(Account owner, Vpc vpc) throws 
InsufficientAddressCapacityException, ConcurrentOperationException;
+    PublicIp assignSourceNatIpAddressToVpc(Account owner, Vpc vpc, Long podId) 
throws InsufficientAddressCapacityException, ConcurrentOperationException;
 
     /**
      * Validates network offering to find if it can be used for network 
creation in VPC
diff --git 
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
 
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index c8a0ce9e7e9..e1b798d16d6 100644
--- 
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ 
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -1645,7 +1645,7 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                 if (ips.isEmpty()) {
                     final Vpc vpc = _vpcMgr.getActiveVpc(network.getVpcId());
                     logger.debug("Creating a source nat ip for vpc {}", vpc);
-                    _vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc);
+                    _vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc, null);
                 }
             } else {
                 ips = _ipAddressDao.listByAssociatedNetwork(network.getId(), 
true);
diff --git 
a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java
 
b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java
index 636d889fafe..1149d0b13e7 100644
--- 
a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java
+++ 
b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/FirewallRuleDetailVO.java
@@ -79,4 +79,8 @@ public class FirewallRuleDetailVO implements ResourceDetail {
     public boolean isDisplay() {
         return display;
     }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
 }
diff --git 
a/plugins/affinity-group-processors/host-affinity/src/main/java/org/apache/cloudstack/affinity/HostAffinityProcessor.java
 
b/plugins/affinity-group-processors/host-affinity/src/main/java/org/apache/cloudstack/affinity/HostAffinityProcessor.java
index 4a5bbe8e787..b94cf49e4d9 100644
--- 
a/plugins/affinity-group-processors/host-affinity/src/main/java/org/apache/cloudstack/affinity/HostAffinityProcessor.java
+++ 
b/plugins/affinity-group-processors/host-affinity/src/main/java/org/apache/cloudstack/affinity/HostAffinityProcessor.java
@@ -63,7 +63,9 @@ public class HostAffinityProcessor extends 
AffinityProcessorBase implements Affi
             Transaction.execute(new TransactionCallbackNoReturn() {
                 @Override
                 public void doInTransactionWithoutResult(TransactionStatus 
status) {
-                    _affinityGroupDao.listByIds(affinityGroupIdList, true);
+                    if (!affinityGroupIdList.isEmpty()) {
+                        _affinityGroupDao.listByIds(affinityGroupIdList, true);
+                    }
                     for (AffinityGroupVMMapVO vmGroupMapping : 
vmGroupMappings) {
                         processAffinityGroup(vmGroupMapping, plan, vm, vmList);
                     }
@@ -149,7 +151,9 @@ public class HostAffinityProcessor extends 
AffinityProcessorBase implements Affi
         return Transaction.execute(new TransactionCallback<Boolean>() {
             @Override
             public Boolean doInTransaction(TransactionStatus status) {
-                _affinityGroupDao.listByIds(affinityGroupIds, true);
+                if (!affinityGroupIds.isEmpty()) {
+                    _affinityGroupDao.listByIds(affinityGroupIds, true);
+                }
                 for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
                     if (!checkAffinityGroup(vmGroupMapping, vm, 
plannedHostId)) {
                         return false;
diff --git 
a/plugins/affinity-group-processors/host-anti-affinity/src/main/java/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
 
b/plugins/affinity-group-processors/host-anti-affinity/src/main/java/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
index e724f02fe98..4681ce4321e 100644
--- 
a/plugins/affinity-group-processors/host-anti-affinity/src/main/java/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
+++ 
b/plugins/affinity-group-processors/host-anti-affinity/src/main/java/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
@@ -78,7 +78,9 @@ public class HostAntiAffinityProcessor extends 
AffinityProcessorBase implements
         Transaction.execute(new TransactionCallbackNoReturn() {
             @Override
             public void doInTransactionWithoutResult(TransactionStatus status) 
{
-                _affinityGroupDao.listByIds(affinityGroupIds, true);
+                if (!affinityGroupIds.isEmpty()) {
+                    _affinityGroupDao.listByIds(affinityGroupIds, true);
+                }
                 for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
                     processAffinityGroup(vmGroupMapping, avoid, vm);
                 }
@@ -165,7 +167,9 @@ public class HostAntiAffinityProcessor extends 
AffinityProcessorBase implements
         return Transaction.execute(new TransactionCallback<Boolean>() {
             @Override
             public Boolean doInTransaction(TransactionStatus status) {
-                _affinityGroupDao.listByIds(affinityGroupIds, true);
+                if (!affinityGroupIds.isEmpty()) {
+                    _affinityGroupDao.listByIds(affinityGroupIds, true);
+                }
                 for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
                     // if more than 1 VM's are present in the group then check 
for
                     // conflict due to parallel deployment
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java
index 2d993ac3cb6..743962a1f00 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java
@@ -360,7 +360,7 @@ public class KubernetesClusterActionWorker {
             return null;
         }
         IpAddress address = ipAddressDao.findByUuid(detailsVO.getValue());
-        if (address == null || network.getVpcId() != address.getVpcId()) {
+        if (address == null || !Objects.equals(network.getVpcId(), 
address.getVpcId())) {
             logger.warn(String.format("Public IP with ID: %s linked to the 
Kubernetes cluster: %s is not usable", detailsVO.getValue(), 
kubernetesCluster.getName()));
             return null;
         }
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
index 92a0315efb5..ec461610e32 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
@@ -17,6 +17,31 @@
 
 package com.cloud.kubernetes.cluster.actionworkers;
 
+import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+
+import com.cloud.network.rules.FirewallManager;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd;
+import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
+import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
 import com.cloud.capacity.CapacityManager;
 import com.cloud.dc.ClusterDetailsDao;
 import com.cloud.dc.ClusterDetailsVO;
@@ -61,9 +86,7 @@ import com.cloud.network.vpc.NetworkACLItem;
 import com.cloud.network.vpc.NetworkACLItemDao;
 import com.cloud.network.vpc.NetworkACLItemVO;
 import com.cloud.network.vpc.NetworkACLService;
-import com.cloud.offering.NetworkOffering;
 import com.cloud.offering.ServiceOffering;
-import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.resource.ResourceManager;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeApiService;
@@ -88,29 +111,9 @@ import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VmDetailConstants;
 import com.cloud.vm.dao.VMInstanceDao;
 import org.apache.cloudstack.api.ApiCommandResourceType;
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseCmd;
-import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd;
-import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
-import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
 import org.apache.cloudstack.context.CallContext;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.Level;
 
-import javax.inject.Inject;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
-import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
-
 public class KubernetesClusterResourceModifierActionWorker extends 
KubernetesClusterActionWorker {
 
     @Inject
@@ -134,6 +137,8 @@ public class KubernetesClusterResourceModifierActionWorker 
extends KubernetesClu
     @Inject
     protected RulesService rulesService;
     @Inject
+    protected FirewallManager firewallManager;
+    @Inject
     protected PortForwardingRulesDao portForwardingRulesDao;
     @Inject
     protected ResourceManager resourceManager;
@@ -169,6 +174,7 @@ public class KubernetesClusterResourceModifierActionWorker 
extends KubernetesClu
         final String joinIpKey = "{{ k8s_control_node.join_ip }}";
         final String clusterTokenKey = "{{ k8s_control_node.cluster.token }}";
         final String ejectIsoKey = "{{ k8s.eject.iso }}";
+
         String pubKey = "- \"" + configurationDao.getValue("ssh.publickey") + 
"\"";
         String sshKeyPair = kubernetesCluster.getKeyPair();
         if (StringUtils.isNotEmpty(sshKeyPair)) {
@@ -181,7 +187,6 @@ public class KubernetesClusterResourceModifierActionWorker 
extends KubernetesClu
         k8sNodeConfig = k8sNodeConfig.replace(joinIpKey, joinIp);
         k8sNodeConfig = k8sNodeConfig.replace(clusterTokenKey, 
KubernetesClusterUtil.generateClusterToken(kubernetesCluster));
         k8sNodeConfig = k8sNodeConfig.replace(ejectIsoKey, 
String.valueOf(ejectIso));
-
         k8sNodeConfig = updateKubeConfigWithRegistryDetails(k8sNodeConfig);
 
         return k8sNodeConfig;
@@ -522,17 +527,22 @@ public class 
KubernetesClusterResourceModifierActionWorker extends KubernetesClu
 
     protected void removePortForwardingRules(final IpAddress publicIp, final 
Network network, final Account account, final List<Long> removedVMIds) throws 
ResourceUnavailableException {
         if (!CollectionUtils.isEmpty(removedVMIds)) {
+            List<PortForwardingRuleVO> pfRules = new ArrayList<>();
+            List<PortForwardingRuleVO> revokedRules = new ArrayList<>();
             for (Long vmId : removedVMIds) {
-                List<PortForwardingRuleVO> pfRules = 
portForwardingRulesDao.listByNetwork(network.getId());
+                
pfRules.addAll(portForwardingRulesDao.listByNetwork(network.getId()));
                 for (PortForwardingRuleVO pfRule : pfRules) {
                     if (pfRule.getVirtualMachineId() == vmId) {
                         portForwardingRulesDao.remove(pfRule.getId());
+                        logger.trace("Marking PF rule {} with Revoke state", 
pfRule);
+                        pfRule.setState(FirewallRule.State.Revoke);
+                        revokedRules.add(pfRule);
                         logger.debug("The Port forwarding rule [%s] with the 
id [%s] was removed.", pfRule.getName(), pfRule.getId());
                         break;
                     }
                 }
             }
-            rulesService.applyPortForwardingRules(publicIp.getId(), account);
+            firewallManager.applyRules(revokedRules, false, true);
         }
     }
 
@@ -542,10 +552,11 @@ public class 
KubernetesClusterResourceModifierActionWorker extends KubernetesClu
         for (PortForwardingRuleVO pfRule : pfRules) {
             if (startPort <= pfRule.getSourcePortStart() && 
pfRule.getSourcePortStart() <= endPort) {
                 portForwardingRulesDao.remove(pfRule.getId());
-                logger.debug("The Port forwarding rule [{}] with the id [{}] 
was removed.", pfRule.getName(), pfRule.getId());
+                logger.debug("The Port forwarding rule [{}] with the id [{}] 
was mark as revoked.", pfRule.getName(), pfRule.getId());
+                pfRule.setState(FirewallRule.State.Revoke);
             }
         }
-        rulesService.applyPortForwardingRules(publicIp.getId(), account);
+        firewallManager.applyRules(pfRules, false, true);
     }
 
     protected void removeLoadBalancingRule(final IpAddress publicIp, final 
Network network,
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
index fb963a13044..c3b81a6ee1f 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
@@ -139,6 +139,7 @@ public class KubernetesClusterStartWorker extends 
KubernetesClusterResourceModif
         final String clusterToken = "{{ k8s_control_node.cluster.token }}";
         final String clusterInitArgsKey = "{{ 
k8s_control_node.cluster.initargs }}";
         final String ejectIsoKey = "{{ k8s.eject.iso }}";
+
         final List<String> addresses = new ArrayList<>();
         addresses.add(controlNodeIp);
         if (!serverIp.equals(controlNodeIp)) {
@@ -243,6 +244,7 @@ public class KubernetesClusterStartWorker extends 
KubernetesClusterResourceModif
         final String sshPubKey = "{{ k8s.ssh.pub.key }}";
         final String clusterHACertificateKey = "{{ 
k8s_control_node.cluster.ha.certificate.key }}";
         final String ejectIsoKey = "{{ k8s.eject.iso }}";
+
         String pubKey = "- \"" + configurationDao.getValue("ssh.publickey") + 
"\"";
         String sshKeyPair = kubernetesCluster.getKeyPair();
         if (StringUtils.isNotEmpty(sshKeyPair)) {
diff --git 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java
 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java
index 0820465a6b6..a667adda794 100644
--- 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java
+++ 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java
@@ -20,6 +20,9 @@ import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
 
 public class NsxAnswer extends Answer {
+
+    private boolean objectExists;
+
     public NsxAnswer(final Command command, final boolean success, final 
String details) {
         super(command, success, details);
     }
@@ -28,4 +31,11 @@ public class NsxAnswer extends Answer {
         super(command, e);
     }
 
+    public boolean isObjectExistent() {
+        return objectExists;
+    }
+
+    public void setObjectExists(boolean objectExisted) {
+        this.objectExists = objectExisted;
+    }
 }
diff --git 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java
 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java
index cd1d481b9f8..76815b0deeb 100644
--- 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java
+++ 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java
@@ -18,6 +18,8 @@ package org.apache.cloudstack.resource;
 
 import com.cloud.agent.IAgentControl;
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CheckHealthAnswer;
+import com.cloud.agent.api.CheckHealthCommand;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.PingCommand;
 import com.cloud.agent.api.ReadyAnswer;
@@ -102,6 +104,8 @@ public class NsxResource implements ServerResource {
     public Answer executeRequest(Command cmd) {
         if (cmd instanceof ReadyCommand) {
             return executeRequest((ReadyCommand) cmd);
+        } else if (cmd instanceof CheckHealthCommand) {
+            return executeRequest((CheckHealthCommand) cmd);
         } else if (cmd instanceof DeleteNsxTier1GatewayCommand) {
             return executeRequest((DeleteNsxTier1GatewayCommand) cmd);
         } else if (cmd instanceof DeleteNsxSegmentCommand) {
@@ -293,6 +297,10 @@ public class NsxResource implements ServerResource {
         return new ReadyAnswer(cmd);
     }
 
+    private Answer executeRequest(CheckHealthCommand cmd) {
+        return new CheckHealthAnswer(cmd, 
nsxApiClient.isNsxControllerActive());
+    }
+
     private Answer executeRequest(CreateNsxTier1GatewayCommand cmd) {
         String tier1GatewayName = 
NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), 
cmd.getZoneId(), cmd.getNetworkResourceId(), cmd.isResourceVpc());
         boolean sourceNatEnabled = cmd.isSourceNatEnabled();
@@ -385,16 +393,21 @@ public class NsxResource implements ServerResource {
                 cmd.getNetworkResourceId(), cmd.isResourceVpc());
         try {
             String privatePort = cmd.getPrivatePort();
-            String service = privatePort.contains("-") ? 
nsxApiClient.getServicePath(ruleName, privatePort, cmd.getProtocol(), null, 
null) :
-                    nsxApiClient.getNsxInfraServices(ruleName, privatePort, 
cmd.getProtocol(), null, null);
+            logger.debug("Checking if the rule {} exists on Tier 1 Gateway: 
{}", ruleName, tier1GatewayName);
             if (nsxApiClient.doesPfRuleExist(ruleName, tier1GatewayName)) {
-                logger.debug(String.format("Port forward rule for port: %s 
exits on NSX, not adding it again", privatePort));
-                return new NsxAnswer(cmd, true, null);
+                String msg = String.format("Port forward rule for port: %s 
(%s) exits on NSX, not adding it again", ruleName, privatePort);
+                logger.debug(msg);
+                NsxAnswer answer = new NsxAnswer(cmd, true, msg);
+                answer.setObjectExists(true);
+                return answer;
             }
+            String service = privatePort.contains("-") ? 
nsxApiClient.getServicePath(ruleName, privatePort, cmd.getProtocol(), null, 
null) :
+                    nsxApiClient.getNsxInfraServices(ruleName, privatePort, 
cmd.getProtocol(), null, null);
             nsxApiClient.createPortForwardingRule(ruleName, tier1GatewayName, 
cmd.getNetworkResourceName(), cmd.getPublicIp(),
                     cmd.getVmIp(), cmd.getPublicPort(), service);
         } catch (Exception e) {
-            logger.error(String.format("Failed to add NSX port forward rule %s 
for network: %s", ruleName, cmd.getNetworkResourceName()));
+            String msg = String.format("Failed to add NSX port forward rule %s 
for network: %s", ruleName, cmd.getNetworkResourceName());
+            logger.error(msg, e);
             return new NsxAnswer(cmd, new 
CloudRuntimeException(e.getMessage()));
         }
         return new NsxAnswer(cmd, true, null);
@@ -415,8 +428,9 @@ public class NsxResource implements ServerResource {
             nsxApiClient.deleteNatRule(cmd.getService(), cmd.getPrivatePort(), 
cmd.getProtocol(),
                     cmd.getNetworkResourceName(), tier1GatewayName, ruleName);
         } catch (Exception e) {
-            logger.error(String.format("Failed to add NSX static NAT rule %s 
for network: %s", ruleName, cmd.getNetworkResourceName()));
-            return new NsxAnswer(cmd, new 
CloudRuntimeException(e.getMessage()));
+            String msg = String.format("Failed to delete NSX rule %s for 
network %s: due to %s", ruleName, cmd.getNetworkResourceName(), e.getMessage());
+            logger.error(msg, e);
+            return new NsxAnswer(cmd, new CloudRuntimeException(msg));
         }
         return new NsxAnswer(cmd, true, null);
     }
diff --git 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java
 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java
index d443b0e14e7..1ba1cc0fcc3 100644
--- 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java
+++ 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java
@@ -17,7 +17,11 @@
 package org.apache.cloudstack.service;
 
 import com.cloud.network.Network;
+import com.cloud.network.nsx.NsxService;
 import com.cloud.utils.exception.CloudRuntimeException;
+import com.vmware.nsx.cluster.Status;
+import com.vmware.nsx.model.ClusterStatus;
+import com.vmware.nsx.model.ControllerClusterStatus;
 import com.vmware.nsx.model.TransportZone;
 import com.vmware.nsx.model.TransportZoneListResult;
 import com.vmware.nsx_policy.infra.DhcpRelayConfigs;
@@ -45,13 +49,13 @@ import com.vmware.nsx_policy.model.GroupListResult;
 import com.vmware.nsx_policy.model.ICMPTypeServiceEntry;
 import com.vmware.nsx_policy.model.L4PortSetServiceEntry;
 import com.vmware.nsx_policy.model.LBAppProfileListResult;
+import com.vmware.nsx_policy.model.LBIcmpMonitorProfile;
 import com.vmware.nsx_policy.model.LBMonitorProfileListResult;
 import com.vmware.nsx_policy.model.LBPool;
 import com.vmware.nsx_policy.model.LBPoolListResult;
 import com.vmware.nsx_policy.model.LBPoolMember;
 import com.vmware.nsx_policy.model.LBService;
 import com.vmware.nsx_policy.model.LBTcpMonitorProfile;
-import com.vmware.nsx_policy.model.LBUdpMonitorProfile;
 import com.vmware.nsx_policy.model.LBVirtualServer;
 import com.vmware.nsx_policy.model.LBVirtualServerListResult;
 import com.vmware.nsx_policy.model.LocaleServicesListResult;
@@ -84,6 +88,7 @@ import org.apache.cloudstack.utils.NsxControllerUtils;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.apache.commons.lang3.BooleanUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -112,6 +117,7 @@ public class NsxApiClient {
     protected Logger logger = LogManager.getLogger(getClass());
 
     // Constants
+    private static final String CLUSTER_STATUS_STABLE = "STABLE";
     private static final String TIER_1_RESOURCE_TYPE = "Tier1";
     private static final String TIER_1_LOCALE_SERVICE_ID = "default";
     private static final String SEGMENT_RESOURCE_TYPE = "Segment";
@@ -123,7 +129,7 @@ public class NsxApiClient {
     // TODO: Pass as global / zone-level setting?
     protected static final String NSX_LB_PASSIVE_MONITOR = 
"/infra/lb-monitor-profiles/default-passive-lb-monitor";
     protected static final String TCP_MONITOR_PROFILE = "LBTcpMonitorProfile";
-    protected static final String UDP_MONITOR_PROFILE = "LBUdpMonitorProfile";
+    protected static final String ICMP_MONITOR_PROFILE = 
"LBIcmpMonitorProfile";
     protected static final String NAT_ID = "USER";
 
     private enum PoolAllocation { ROUTING, LB_SMALL, LB_MEDIUM, LB_LARGE, 
LB_XLARGE }
@@ -199,6 +205,26 @@ public class NsxApiClient {
         nsxService = apiClient::createStub;
     }
 
+    public boolean isNsxControllerActive() {
+        try {
+            Status statusService = (Status) nsxService.apply(Status.class);
+            ClusterStatus clusterStatus = statusService.get();
+            if (clusterStatus == null) {
+                logger.error("Cannot get NSX Cluster Status");
+                return false;
+            }
+            ControllerClusterStatus status = 
clusterStatus.getControlClusterStatus();
+            if (status == null) {
+                logger.error("Cannot get NSX Controller Cluster Status");
+                return false;
+            }
+            return CLUSTER_STATUS_STABLE.equalsIgnoreCase(status.getStatus());
+        } catch (Error error) {
+            logger.error("Error checking NSX Controller Health: {}", 
error.getMessage());
+            return false;
+        }
+    }
+
     public void createTier1NatRule(String tier1GatewayName, String natId, 
String natRuleId,
                                    String action, String translatedIp) {
         NatRules natRulesService = (NatRules) nsxService.apply(NatRules.class);
@@ -435,7 +461,7 @@ public class NsxApiClient {
                 String t1GatewayName = getTier1GatewayName(domainId, 
accountId, zoneId, networkId, false);
                 deleteLoadBalancer(getLoadBalancerName(t1GatewayName));
             }
-            removeSegment(segmentName);
+            removeSegment(segmentName, zoneId);
             DhcpRelayConfigs dhcpRelayConfig = (DhcpRelayConfigs) 
nsxService.apply(DhcpRelayConfigs.class);
             String dhcpRelayConfigId = 
NsxControllerUtils.getNsxDhcpRelayConfigId(zoneId, domainId, accountId, vpcId, 
networkId);
             logger.debug(String.format("Removing the DHCP relay config with ID 
%s", dhcpRelayConfigId));
@@ -448,7 +474,8 @@ public class NsxApiClient {
         }
     }
 
-    protected void removeSegment(String segmentName) {
+
+    protected void removeSegment(String segmentName, long zoneId) {
         logger.debug(String.format("Removing the segment with ID %s", 
segmentName));
         Segments segmentService = (Segments) nsxService.apply(Segments.class);
         String errMsg = String.format("The segment with ID %s is not found, 
skipping removal", segmentName);
@@ -467,15 +494,16 @@ public class NsxApiClient {
         SegmentPorts segmentPortsService = (SegmentPorts) 
nsxService.apply(SegmentPorts.class);
         PolicyGroupMembersListResult segmentPortsList = 
getSegmentPortList(segmentPortsService, segmentName, enforcementPointPath);
         Long portCount = segmentPortsList.getResultCount();
-        portCount = retrySegmentDeletion(segmentPortsService, portCount, 
segmentName, enforcementPointPath);
-        logger.info("Port count: " + portCount);
+        if (portCount > 0L) {
+            portCount = retrySegmentDeletion(segmentPortsService, segmentName, 
enforcementPointPath, zoneId);
+        }
         if (portCount == 0L) {
             logger.debug(String.format("Removing the segment with ID %s", 
segmentName));
             removeGroupForSegment(segmentName);
             segmentService.delete(segmentName);
         } else {
             String msg = String.format("Cannot remove the NSX segment %s 
because there are still %s port group(s) attached to it", segmentName, 
portCount);
-            logger.debug(msg);
+            logger.error(msg);
             throw new CloudRuntimeException(msg);
         }
     }
@@ -485,13 +513,16 @@ public class NsxApiClient {
                 false, null, 50L, false, null);
     }
 
-    private Long retrySegmentDeletion(SegmentPorts segmentPortsService, Long 
portCount, String segmentName, String enforcementPointPath) {
-        int retries = 20;
+    private Long retrySegmentDeletion(SegmentPorts segmentPortsService, String 
segmentName, String enforcementPointPath, long zoneId) {
+        int retries = NsxService.NSX_API_FAILURE_RETRIES.valueIn(zoneId);
+        int waitingSecs = NsxService.NSX_API_FAILURE_INTERVAL.valueIn(zoneId);
         int count = 1;
+        Long portCount;
         do {
             try {
-                logger.info("Waiting for all port groups to be unlinked from 
the segment - Attempt: " + count++ + " Waiting for 5 secs");
-                Thread.sleep(5000);
+                logger.info("Waiting for all port groups to be unlinked from 
the segment {} - " +
+                        "Attempt: {}. Waiting for {} secs", segmentName, 
count++, waitingSecs);
+                Thread.sleep(waitingSecs * 1000L);
                 portCount = getSegmentPortList(segmentPortsService, 
segmentName, enforcementPointPath).getResultCount();
                 retries--;
             } catch (InterruptedException e) {
@@ -526,24 +557,37 @@ public class NsxApiClient {
         }
     }
 
+    protected void deletePortForwardingNatRuleService(String ruleName, String 
privatePort, String protocol) {
+        String svcName = getServiceName(ruleName, privatePort, protocol, null, 
null);
+        try {
+            Services services = (Services) nsxService.apply(Services.class);
+            com.vmware.nsx_policy.model.Service servicePFRule = 
services.get(svcName);
+            if (servicePFRule != null && !servicePFRule.getMarkedForDelete() 
&& !BooleanUtils.toBoolean(servicePFRule.getIsDefault())) {
+                services.delete(svcName);
+            }
+        } catch (Error error) {
+            String msg = String.format("Cannot find service %s associated to 
rule %s, skipping its deletion: %s",
+                    svcName, ruleName, error.getMessage());
+            logger.debug(msg);
+        }
+    }
+
     public void deleteNatRule(Network.Service service, String privatePort, 
String protocol, String networkName, String tier1GatewayName, String ruleName) {
         try {
             NatRules natService = (NatRules) nsxService.apply(NatRules.class);
-            logger.debug(String.format("Deleting NSX static NAT rule %s for 
tier-1 gateway %s (network: %s)", ruleName, tier1GatewayName, networkName));
-            // delete NAT rule
-            natService.delete(tier1GatewayName, NatId.USER.name(), ruleName);
-            if (service == Network.Service.PortForwarding) {
-                String svcName = getServiceName(ruleName, privatePort, 
protocol, null, null);
-                // Delete service
-                Services services = (Services) 
nsxService.apply(Services.class);
-                services.delete(svcName);
+            logger.debug("Deleting NSX NAT rule {} for tier-1 gateway {} 
(network: {})", ruleName, tier1GatewayName, networkName);
+            PolicyNatRule natRule = natService.get(tier1GatewayName, 
NatId.USER.name(), ruleName);
+            if (natRule != null && !natRule.getMarkedForDelete()) {
+                logger.debug("Deleting rule {} from Tier 1 Gateway {}", 
ruleName, tier1GatewayName);
+                natService.delete(tier1GatewayName, NatId.USER.name(), 
ruleName);
             }
         } catch (Error error) {
-            ApiError ae = error.getData()._convertTo(ApiError.class);
-            String msg = String.format("Failed to delete NSX Static NAT rule 
%s for tier-1 gateway %s (VPC: %s), due to %s",
-                    ruleName, tier1GatewayName, networkName, 
ae.getErrorMessage());
-            logger.error(msg);
-            throw new CloudRuntimeException(msg);
+            String msg = String.format("Cannot find NAT rule with name %s: %s, 
skipping deletion", ruleName, error.getMessage());
+            logger.debug(msg);
+        }
+
+        if (service == Network.Service.PortForwarding) {
+            deletePortForwardingNatRuleService(ruleName, privatePort, 
protocol);
         }
     }
 
@@ -577,9 +621,14 @@ public class NsxApiClient {
         try {
             NatRules natService = (NatRules) nsxService.apply(NatRules.class);
             PolicyNatRule rule = natService.get(tier1GatewayName, NAT_ID, 
ruleName);
+            logger.debug("Rule {} from Tier 1 GW {}: {}", ruleName, 
tier1GatewayName,
+                    rule == null ? "null" : rule.getId() + " " + 
rule.getPath());
             return !Objects.isNull(rule);
         } catch (Error error) {
-            logger.debug(String.format("Found a port forward rule named: %s on 
NSX", ruleName));
+            String msg = String.format("Error checking if port forwarding rule 
%s exists on Tier 1 Gateway %s: %s",
+                    ruleName, tier1GatewayName, error.getMessage());
+            Throwable throwable = error.getCause();
+            logger.error(msg, throwable);
             return false;
         }
     }
@@ -637,13 +686,10 @@ public class NsxApiClient {
                     .build();
             lbActiveMonitor.patch(lbMonitorProfileId, lbTcpMonitorProfile);
         } else if ("UDP".equals(protocol.toUpperCase(Locale.ROOT))) {
-            LBUdpMonitorProfile lbUdpMonitorProfile = new 
LBUdpMonitorProfile.Builder(UDP_MONITOR_PROFILE)
+            LBIcmpMonitorProfile icmpMonitorProfile = new 
LBIcmpMonitorProfile.Builder(ICMP_MONITOR_PROFILE)
                     .setDisplayName(lbMonitorProfileId)
-                    .setMonitorPort(Long.parseLong(port))
-                    .setSend("")
-                    .setReceive("")
                     .build();
-            lbActiveMonitor.patch(lbMonitorProfileId, lbUdpMonitorProfile);
+            lbActiveMonitor.patch(lbMonitorProfileId, icmpMonitorProfile);
         }
 
         LBMonitorProfileListResult listResult = 
listLBActiveMonitors(lbActiveMonitor);
diff --git 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java
 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java
index d09049700e5..7673e5a6038 100644
--- 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java
+++ 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java
@@ -91,6 +91,8 @@ import com.cloud.utils.Pair;
 import com.cloud.utils.component.AdapterBase;
 import com.cloud.utils.db.QueryBuilder;
 import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.NicProfile;
 import com.cloud.vm.ReservationContext;
@@ -98,7 +100,9 @@ import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachineProfile;
 import com.cloud.vm.dao.VMInstanceDao;
 import net.sf.ehcache.config.InvalidConfigurationException;
+import org.apache.cloudstack.NsxAnswer;
 import org.apache.cloudstack.StartupNsxCommand;
+import org.apache.cloudstack.api.ApiConstants;
 import 
org.apache.cloudstack.api.command.admin.internallb.ConfigureInternalLoadBalancerElementCmd;
 import 
org.apache.cloudstack.api.command.admin.internallb.CreateInternalLoadBalancerElementCmd;
 import 
org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalancerElementsCmd;
@@ -108,6 +112,8 @@ import org.apache.cloudstack.resource.NsxNetworkRule;
 import org.apache.cloudstack.resource.NsxOpObject;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.apache.cloudstack.resourcedetail.FirewallRuleDetailVO;
+import org.apache.cloudstack.resourcedetail.dao.FirewallRuleDetailsDao;
 import org.springframework.stereotype.Component;
 
 import javax.inject.Inject;
@@ -121,6 +127,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.LongFunction;
+import java.util.stream.Collectors;
 
 @Component
 public class NsxElement extends AdapterBase implements  DhcpServiceProvider, 
DnsServiceProvider, VpcProvider,
@@ -160,6 +167,8 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
     VirtualRouterProviderDao vrProviderDao;
     @Inject
     PhysicalNetworkServiceProviderDao pNtwkSvcProviderDao;
+    @Inject
+    FirewallRuleDetailsDao firewallRuleDetailsDao;
 
     protected Logger logger = LogManager.getLogger(getClass());
 
@@ -395,10 +404,18 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
         Account account = null;
         boolean forNsx = false;
         List<PhysicalNetworkVO> physicalNetworks = 
physicalNetworkDao.listByZoneAndTrafficType(zone.getId(), 
Networks.TrafficType.Guest);
-        if (CollectionUtils.isNullOrEmpty(physicalNetworks) || 
physicalNetworks.size() > 1 ) {
-            throw new InvalidConfigurationException(String.format("Desired 
number of physical networks is not present in the zone %s for traffic type %s. 
", zone.getName(), Networks.TrafficType.Guest.name()));
-        }
-        if (physicalNetworks.get(0).getIsolationMethods().contains("NSX")) {
+        if (CollectionUtils.isNullOrEmpty(physicalNetworks)) {
+            String err = String.format("Desired physical network is not 
present in the zone %s for traffic type %s. ", zone.getName(), 
Networks.TrafficType.Guest.name());
+            logger.error(err);
+            throw new InvalidConfigurationException(err);
+        }
+        List<PhysicalNetworkVO> filteredPhysicalNetworks = 
physicalNetworks.stream().filter(x -> 
x.getIsolationMethods().contains("NSX")).collect(Collectors.toList());
+        if (CollectionUtils.isNullOrEmpty(filteredPhysicalNetworks)) {
+            String err = String.format("No physical network with NSX isolation 
type for traffic type %s is present in the zone %s.", 
Networks.TrafficType.Guest.name(), zone.getName());
+            logger.error(err);
+            throw new InvalidConfigurationException(err);
+        }
+        if 
(filteredPhysicalNetworks.get(0).getIsolationMethods().contains("NSX")) {
             account = accountMgr.getAccount(vpc.getAccountId());
             forNsx = true;
         }
@@ -527,45 +544,77 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
         return false;
     }
 
+    protected synchronized boolean applyPFRulesInternal(Network network, 
List<PortForwardingRule> rules) {
+        return Transaction.execute((TransactionCallback<Boolean>) status -> {
+            boolean result = true;
+            for (PortForwardingRule rule : rules) {
+                IPAddressVO publicIp = 
ApiDBUtils.findIpAddressById(rule.getSourceIpAddressId());
+                UserVm vm = 
ApiDBUtils.findUserVmById(rule.getVirtualMachineId());
+                if (vm == null && rule.getState() != 
FirewallRule.State.Revoke) {
+                    continue;
+                }
+                NsxOpObject nsxObject = getNsxOpObject(network);
+                String publicPort = getPublicPortRange(rule);
+
+                String privatePort = getPrivatePFPortRange(rule);
+
+                NsxNetworkRule networkRule = new NsxNetworkRule.Builder()
+                        .setDomainId(nsxObject.getDomainId())
+                        .setAccountId(nsxObject.getAccountId())
+                        .setZoneId(nsxObject.getZoneId())
+                        .setNetworkResourceId(nsxObject.getNetworkResourceId())
+                        
.setNetworkResourceName(nsxObject.getNetworkResourceName())
+                        .setVpcResource(nsxObject.isVpcResource())
+                        .setVmId(Objects.nonNull(vm) ? vm.getId() : 0)
+                        .setVmIp(Objects.nonNull(vm) ? 
vm.getPrivateIpAddress() : null)
+                        .setPublicIp(publicIp.getAddress().addr())
+                        .setPrivatePort(privatePort)
+                        .setPublicPort(publicPort)
+                        .setRuleId(rule.getId())
+                        
.setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT))
+                        .build();
+                FirewallRuleDetailVO ruleDetail = 
firewallRuleDetailsDao.findDetail(rule.getId(), ApiConstants.FOR_NSX);
+                if (Arrays.asList(FirewallRule.State.Add, 
FirewallRule.State.Active).contains(rule.getState())) {
+                    if ((ruleDetail == null && FirewallRule.State.Add == 
rule.getState()) || (ruleDetail != null && 
!ruleDetail.getValue().equalsIgnoreCase("true"))) {
+                        logger.debug("Creating port forwarding rule on NSX for 
VM {} to ports {} - {}",
+                                vm.getUuid(), rule.getDestinationPortStart(), 
rule.getDestinationPortEnd());
+                        NsxAnswer answer = 
nsxService.createPortForwardRule(networkRule);
+                        boolean pfRuleResult = answer.getResult();
+                        if (pfRuleResult && !answer.isObjectExistent()) {
+                            logger.debug("Port forwarding rule {} created on 
NSX, adding detail on firewall rules details", rule.getId());
+                            if (ruleDetail == null && FirewallRule.State.Add 
== rule.getState()) {
+                                logger.debug("Adding new firewall detail for 
rule {}", rule.getId());
+                                firewallRuleDetailsDao.addDetail(rule.getId(), 
ApiConstants.FOR_NSX, "true", false);
+                            } else {
+                                logger.debug("Updating firewall detail for 
rule {}", rule.getId());
+                                ruleDetail.setValue("true");
+                                
firewallRuleDetailsDao.update(ruleDetail.getId(), ruleDetail);
+                            }
+                        }
+                        result &= pfRuleResult;
+                    }
+                } else if (rule.getState() == FirewallRule.State.Revoke) {
+                    if (ruleDetail == null || (ruleDetail != null && 
ruleDetail.getValue().equalsIgnoreCase("true"))) {
+                        boolean pfRuleResult = 
nsxService.deletePortForwardRule(networkRule);
+                        if (pfRuleResult && ruleDetail != null) {
+                            logger.debug("Updating firewall rule detail {} for 
rule {}, set to false", ruleDetail.getId(), rule.getId());
+                            ruleDetail.setValue("false");
+                            firewallRuleDetailsDao.update(ruleDetail.getId(), 
ruleDetail);
+                        }
+                        result &= pfRuleResult;
+                    }
+                }
+            }
+            return result;
+        });
+    }
+
     @Override
     public boolean applyPFRules(Network network, List<PortForwardingRule> 
rules) throws ResourceUnavailableException {
         if (!canHandle(network, Network.Service.PortForwarding)) {
             return false;
         }
-        boolean result = true;
-        for (PortForwardingRule rule : rules) {
-            IPAddressVO publicIp = 
ApiDBUtils.findIpAddressById(rule.getSourceIpAddressId());
-            UserVm vm = ApiDBUtils.findUserVmById(rule.getVirtualMachineId());
-            if (vm == null && rule.getState() != FirewallRule.State.Revoke) {
-                continue;
-            }
-            NsxOpObject nsxObject = getNsxOpObject(network);
-            String publicPort = getPublicPortRange(rule);
-
-            String privatePort = getPrivatePFPortRange(rule);
-
-            NsxNetworkRule networkRule = new NsxNetworkRule.Builder()
-                    .setDomainId(nsxObject.getDomainId())
-                    .setAccountId(nsxObject.getAccountId())
-                    .setZoneId(nsxObject.getZoneId())
-                    .setNetworkResourceId(nsxObject.getNetworkResourceId())
-                    .setNetworkResourceName(nsxObject.getNetworkResourceName())
-                    .setVpcResource(nsxObject.isVpcResource())
-                    .setVmId(Objects.nonNull(vm) ? vm.getId() : 0)
-                    .setVmIp(Objects.nonNull(vm) ? vm.getPrivateIpAddress() : 
null)
-                    .setPublicIp(publicIp.getAddress().addr())
-                    .setPrivatePort(privatePort)
-                    .setPublicPort(publicPort)
-                    .setRuleId(rule.getId())
-                    .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT))
-                    .build();
-            if (Arrays.asList(FirewallRule.State.Add, 
FirewallRule.State.Active).contains(rule.getState())) {
-                result &= nsxService.createPortForwardRule(networkRule);
-            } else if (rule.getState() == FirewallRule.State.Revoke) {
-                result &= nsxService.deletePortForwardRule(networkRule);
-            }
-        }
-        return result;
+        return applyPFRulesInternal(network, rules);
     }
 
     public Pair<VpcVO, NetworkVO> getVpcOrNetwork(Long vpcId, long networkId) {
diff --git 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java
 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java
index f8880826a3f..139d8a55e59 100644
--- 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java
+++ 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java
@@ -19,7 +19,6 @@ package org.apache.cloudstack.service;
 import com.cloud.network.IpAddress;
 import com.cloud.network.Network;
 import com.cloud.network.nsx.NsxService;
-import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.vpc.Vpc;
 import com.cloud.network.vpc.VpcVO;
@@ -37,6 +36,8 @@ import 
org.apache.cloudstack.agent.api.DeleteNsxLoadBalancerRuleCommand;
 import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand;
 import org.apache.cloudstack.agent.api.DeleteNsxNatRuleCommand;
 import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.resource.NsxNetworkRule;
 import org.apache.cloudstack.utils.NsxControllerUtils;
 import org.apache.cloudstack.utils.NsxHelper;
@@ -47,13 +48,11 @@ import javax.inject.Inject;
 import java.util.List;
 import java.util.Objects;
 
-public class NsxServiceImpl implements NsxService {
+public class NsxServiceImpl implements NsxService, Configurable {
     @Inject
     NsxControllerUtils nsxControllerUtils;
     @Inject
     VpcDao vpcDao;
-    @Inject
-    NetworkDao networkDao;
 
     protected Logger logger = LogManager.getLogger(getClass());
 
@@ -139,14 +138,13 @@ public class NsxServiceImpl implements NsxService {
         return result.getResult();
     }
 
-    public boolean createPortForwardRule(NsxNetworkRule netRule) {
+    public NsxAnswer createPortForwardRule(NsxNetworkRule netRule) {
         // TODO: if port doesn't exist in default list of services, create a 
service entry
         CreateNsxPortForwardRuleCommand createPortForwardCmd = new 
CreateNsxPortForwardRuleCommand(netRule.getDomainId(),
                 netRule.getAccountId(), netRule.getZoneId(), 
netRule.getNetworkResourceId(),
                 netRule.getNetworkResourceName(), netRule.isVpcResource(), 
netRule.getVmId(), netRule.getRuleId(),
                 netRule.getPublicIp(), netRule.getVmIp(), 
netRule.getPublicPort(), netRule.getPrivatePort(), netRule.getProtocol());
-        NsxAnswer result = 
nsxControllerUtils.sendNsxCommand(createPortForwardCmd, netRule.getZoneId());
-        return result.getResult();
+        return nsxControllerUtils.sendNsxCommand(createPortForwardCmd, 
netRule.getZoneId());
     }
 
     public boolean deletePortForwardRule(NsxNetworkRule netRule) {
@@ -190,4 +188,16 @@ public class NsxServiceImpl implements NsxService {
         NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, 
network.getDataCenterId());
         return result.getResult();
     }
+
+    @Override
+    public String getConfigComponentName() {
+        return NsxApiClient.class.getSimpleName();
+    }
+
+    @Override
+    public ConfigKey<?>[] getConfigKeys() {
+        return new ConfigKey<?>[] {
+            NSX_API_FAILURE_RETRIES, NSX_API_FAILURE_INTERVAL
+        };
+    }
 }
diff --git 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java
 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java
index e064a6b6291..f44364f34c8 100644
--- 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java
+++ 
b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxControllerUtils.java
@@ -124,6 +124,9 @@ public class NsxControllerUtils {
     }
 
     public static String getActiveMonitorProfileName(String lbServerPoolName, 
String port, String protocol) {
+        if (protocol.equalsIgnoreCase("udp")) {
+            protocol =  "ICMP";
+        }
         return lbServerPoolName + "-" + protocol + "-" + port + "-AM";
     }
 
diff --git 
a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java
 
b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java
index a0fde08ade8..fbcca86a28b 100644
--- 
a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java
+++ 
b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java
@@ -17,6 +17,9 @@
 package org.apache.cloudstack.service;
 
 import com.cloud.network.Network;
+import com.vmware.nsx.cluster.Status;
+import com.vmware.nsx.model.ClusterStatus;
+import com.vmware.nsx.model.ControllerClusterStatus;
 import com.vmware.nsx_policy.infra.domains.Groups;
 import com.vmware.nsx_policy.model.Group;
 import com.vmware.nsx_policy.model.PathExpression;
@@ -93,4 +96,16 @@ public class NsxApiClientTest {
         Assert.assertEquals(List.of(String.format("%s/%s", 
NsxApiClient.GROUPS_PATH_PREFIX, segmentName)), sourceGroups);
         Assert.assertEquals(List.of("ANY"), destinationGroups);
     }
+
+    @Test
+    public void testIsNsxControllerActive() {
+        Status statusService = Mockito.mock(Status.class);
+        Mockito.when(nsxService.apply(Status.class)).thenReturn(statusService);
+        ClusterStatus clusterStatus = Mockito.mock(ClusterStatus.class);
+        ControllerClusterStatus status = 
Mockito.mock(ControllerClusterStatus.class);
+        Mockito.when(status.getStatus()).thenReturn("stable");
+        Mockito.when(statusService.get()).thenReturn(clusterStatus);
+        
Mockito.when(clusterStatus.getControlClusterStatus()).thenReturn(status);
+        Assert.assertTrue(client.isNsxControllerActive());
+    }
 }
diff --git 
a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java
 
b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java
index ff7fa5427ee..7c44a7324fb 100644
--- 
a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java
+++ 
b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java
@@ -61,6 +61,7 @@ import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.resource.NsxNetworkRule;
+import org.apache.cloudstack.resourcedetail.dao.FirewallRuleDetailsDao;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -124,6 +125,8 @@ public class NsxElementTest {
     private VpcOfferingServiceMapDao vpcOfferingServiceMapDao;
     @Mock
     LoadBalancerVMMapDao lbVmMapDao;
+    @Mock
+    FirewallRuleDetailsDao firewallRuleDetailsDao;
 
     NsxElement nsxElement;
     ReservationContext reservationContext;
@@ -148,6 +151,7 @@ public class NsxElementTest {
         nsxElement.vmInstanceDao = vmInstanceDao;
         nsxElement.vpcDao = vpcDao;
         nsxElement.lbVmMapDao = lbVmMapDao;
+        nsxElement.firewallRuleDetailsDao = firewallRuleDetailsDao;
 
         Field field = ApiDBUtils.class.getDeclaredField("s_ipAddressDao");
         field.setAccessible(true);
diff --git 
a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java 
b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index 7926deb9065..25cbd10de0a 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -8002,7 +8002,7 @@ public class ConfigurationManagerImpl extends ManagerBase 
implements Configurati
                 BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, 
ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE,
                 VM_SERVICE_OFFERING_MAX_CPU_CORES, 
VM_SERVICE_OFFERING_MAX_RAM_SIZE, MIGRATE_VM_ACROSS_CLUSTERS,
                 ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, 
ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN,
-                ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, 
DELETE_QUERY_BATCH_SIZE
+                ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, 
DELETE_QUERY_BATCH_SIZE, AllowNonRFC1918CompliantIPs
         };
     }
 
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java 
b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index 126800e0af3..d8d7eb20057 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -1832,7 +1832,7 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
 
     private void validateNetworkCreationSupported(long zoneId, String 
zoneName, GuestType guestType) {
         NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(zoneId);
-        if (Objects.nonNull(nsxProviderVO) && List.of(GuestType.L2, 
GuestType.Shared).contains(guestType)) {
+        if (Objects.nonNull(nsxProviderVO) && GuestType.L2.equals(guestType)) {
             throw new InvalidParameterValueException(
                     String.format("Creation of %s networks is not supported in 
NSX enabled zone %s", guestType.name(), zoneName)
             );
diff --git 
a/server/src/main/java/com/cloud/network/router/VpcNetworkHelperImpl.java 
b/server/src/main/java/com/cloud/network/router/VpcNetworkHelperImpl.java
index fa2f2aba8ff..13e118349b0 100644
--- a/server/src/main/java/com/cloud/network/router/VpcNetworkHelperImpl.java
+++ b/server/src/main/java/com/cloud/network/router/VpcNetworkHelperImpl.java
@@ -134,6 +134,7 @@ public class VpcNetworkHelperImpl extends NetworkHelperImpl 
{
                 final PublicIp publicIp = PublicIp.createFromAddrAndVlan(ip, 
_vlanDao.findById(ip.getVlanId()));
                 if ((ip.getState() == IpAddress.State.Allocated  || 
ip.getState() == IpAddress.State.Allocating)
                         && vpcMgr.isIpAllocatedToVpc(ip)
+                        && Objects.nonNull(publicIp.getVlanTag())
                         && !publicVlans.contains(publicIp.getVlanTag())) {
                     logger.debug("Allocating nic for router in vlan " + 
publicIp.getVlanTag());
                     final NicProfile publicNic = new NicProfile();
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 91fceb2cbb3..d21e2bf8ca4 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -43,6 +43,9 @@ import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
 import com.cloud.configuration.ConfigurationManager;
+import com.cloud.dc.Vlan;
+import com.cloud.network.dao.NsxProviderDao;
+import com.cloud.network.element.NsxProviderVO;
 import com.cloud.configuration.ConfigurationManagerImpl;
 import com.cloud.dc.ASNumberVO;
 import com.cloud.bgp.BGPService;
@@ -282,6 +285,8 @@ public class VpcManagerImpl extends ManagerBase implements 
VpcManager, VpcProvis
     @Inject
     private VpcPrivateGatewayTransactionCallable vpcTxCallable;
     @Inject
+    private NsxProviderDao nsxProviderDao;
+    @Inject
     RoutedIpv4Manager routedIpv4Manager;
 
     private final ScheduledExecutorService _executor = 
Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker"));
@@ -3169,7 +3174,7 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
 
         logger.debug("Associating ip " + ipToAssoc + " to vpc " + vpc);
 
-        final boolean isSourceNatFinal = 
isSrcNatIpRequired(vpc.getVpcOfferingId()) && 
getExistingSourceNatInVpc(vpc.getAccountId(), vpcId) == null;
+        final boolean isSourceNatFinal = 
isSrcNatIpRequired(vpc.getVpcOfferingId()) && 
getExistingSourceNatInVpc(vpc.getAccountId(), vpcId, false) == null;
         Transaction.execute(new TransactionCallbackNoReturn() {
             @Override
             public void doInTransactionWithoutResult(final TransactionStatus 
status) {
@@ -3266,7 +3271,7 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
         return guestNetwork;
     }
 
-    protected IPAddressVO getExistingSourceNatInVpc(final long ownerId, final 
long vpcId) {
+    protected IPAddressVO getExistingSourceNatInVpc(final long ownerId, final 
long vpcId, final boolean forNsx) {
 
         final List<IPAddressVO> addrs = listPublicIpsAssignedToVpc(ownerId, 
true, vpcId);
 
@@ -3277,8 +3282,16 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
             // Account already has ip addresses
             for (final IPAddressVO addr : addrs) {
                 if (addr.isSourceNat()) {
-                    sourceNatIp = addr;
-                    return sourceNatIp;
+                    if (!forNsx) {
+                        sourceNatIp = addr;
+                    } else {
+                        if (addr.isForSystemVms()) {
+                            sourceNatIp = addr;
+                        }
+                    }
+                    if (Objects.nonNull(sourceNatIp)) {
+                        return sourceNatIp;
+                    }
                 }
             }
 
@@ -3302,17 +3315,23 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
     }
 
     @Override
-    public PublicIp assignSourceNatIpAddressToVpc(final Account owner, final 
Vpc vpc) throws InsufficientAddressCapacityException, 
ConcurrentOperationException {
+    public PublicIp assignSourceNatIpAddressToVpc(final Account owner, final 
Vpc vpc, final Long podId) throws InsufficientAddressCapacityException, 
ConcurrentOperationException {
         final long dcId = vpc.getZoneId();
+        NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(dcId);
+        boolean forNsx = nsxProvider != null;
 
-        final IPAddressVO sourceNatIp = 
getExistingSourceNatInVpc(owner.getId(), vpc.getId());
+        final IPAddressVO sourceNatIp = 
getExistingSourceNatInVpc(owner.getId(), vpc.getId(), forNsx);
 
         PublicIp ipToReturn = null;
 
         if (sourceNatIp != null) {
             ipToReturn = PublicIp.createFromAddrAndVlan(sourceNatIp, 
_vlanDao.findById(sourceNatIp.getVlanId()));
         } else {
-            ipToReturn = _ipAddrMgr.assignDedicateIpAddress(owner, null, 
vpc.getId(), dcId, true);
+            if (forNsx) {
+                ipToReturn = _ipAddrMgr.assignPublicIpAddress(dcId, podId, 
owner, Vlan.VlanType.VirtualNetwork, null, null, false, true);
+            } else {
+                ipToReturn = _ipAddrMgr.assignDedicateIpAddress(owner, null, 
vpc.getId(), dcId, true);
+            }
         }
 
         return ipToReturn;
diff --git 
a/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java
 
b/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java
index aa44f29efcd..405575c65b1 100644
--- 
a/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java
+++ 
b/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java
@@ -22,7 +22,6 @@ import java.util.Map;
 import java.util.Objects;
 
 import com.cloud.dc.DataCenter;
-import com.cloud.dc.Vlan;
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.element.NsxProviderVO;
 
@@ -132,10 +131,9 @@ public class VpcRouterDeploymentDefinition extends 
RouterDeploymentDefinition {
 
         if (isPublicNetwork) {
             if (Objects.isNull(nsxProvider)) {
-                sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc);
+                sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc, 
null);
             } else {
-                // NSX deploys VRs with Public NIC != to the source NAT, the 
source NAT IP is on the NSX Public range
-                sourceNatIp = ipAddrMgr.assignPublicIpAddress(zoneId, 
getPodId(), owner, Vlan.VlanType.VirtualNetwork, null, null, false, true);
+                sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc, 
getPodId());
                 if (vpc != null) {
                     IPAddressVO routerPublicIp = 
ipAddressDao.findByIp(sourceNatIp.getAddress().toString());
                     routerPublicIp.setVpcId(vpc.getId());
diff --git 
a/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java
 
b/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java
index a355ad21f2b..d3ab6d8904b 100644
--- 
a/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java
+++ 
b/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java
@@ -269,7 +269,7 @@ public class VpcRouterDeploymentDefinitionTest extends 
RouterDeploymentDefinitio
     public void testFindSourceNatIP() throws 
InsufficientAddressCapacityException, ConcurrentOperationException {
         // Prepare
         final PublicIp publicIp = mock(PublicIp.class);
-        when(vpcMgr.assignSourceNatIpAddressToVpc(mockOwner, 
mockVpc)).thenReturn(publicIp);
+        when(vpcMgr.assignSourceNatIpAddressToVpc(mockOwner, mockVpc, 
null)).thenReturn(publicIp);
         deployment.isPublicNetwork = true;
 
         // Execute
diff --git a/ui/src/views/network/CreateSharedNetworkForm.vue 
b/ui/src/views/network/CreateSharedNetworkForm.vue
index 4fd42370946..b0c7203f833 100644
--- a/ui/src/views/network/CreateSharedNetworkForm.vue
+++ b/ui/src/views/network/CreateSharedNetworkForm.vue
@@ -18,14 +18,7 @@
 <template>
   <a-spin :spinning="loading">
     <div class="form-layout" v-ctrl-enter="handleSubmit">
-      <div v-if="isNsxEnabled">
-        <a-alert type="warning">
-          <template #message>
-            <span v-html="$t('message.shared.network.unsupported.for.nsx')" />
-          </template>
-        </a-alert>
-      </div>
-      <div v-else class="form">
+      <div class="form">
         <a-form
           :ref="formRef"
           :model="form"
@@ -725,7 +718,7 @@ export default {
           var trafficTypes = json.listtraffictypesresponse.traffictype
           if (this.arrayHasItems(trafficTypes)) {
             for (const type of trafficTypes) {
-              if (type.traffictype === 'Guest') {
+              if (type.traffictype === 'Guest' && 
physicalNetwork.isolationmethods !== 'NSX') {
                 this.formPhysicalNetworks.push(physicalNetwork)
                 break
               }

Reply via email to