NSX: Add support to add firewall rule / Network ACL
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 3a2b603..ee64caa 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -296,6 +296,7 @@
     public static final String MEMORY = "memory";
     public static final String MODE = "mode";
     public static final String NSX_MODE = "nsxmode";
+    public static final String NSX_ENABLED = "isnsxenabled";
     public static final String NAME = "name";
     public static final String METHOD_NAME = "methodname";
     public static final String NETWORK_DOMAIN = "networkdomain";
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 4e8e665..5d31adb 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
@@ -141,6 +141,10 @@
     @Param(description = "The maximum value the MTU can have on the VR's public interfaces", since = "4.18.0")
     private Integer routerPublicInterfaceMaxMtu;
 
+    @SerializedName(ApiConstants.NSX_ENABLED)
+            @Param(description = "true, if zone is NSX enabled", since = "4.20.0")
+    private boolean nsxEnabled = false;
+
     @SerializedName(ApiConstants.TYPE)
     @Param(description = "the type of the zone - core or edge", since = "4.18.0")
     String type;
@@ -368,4 +372,8 @@
     public String getType() {
         return type;
     }
+
+    public void setNsxEnabled(boolean nsxEnabled) {
+        this.nsxEnabled = nsxEnabled;
+    }
 }
diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java
index 6fb7c4e..c975e8f 100644
--- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java
+++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java
@@ -63,6 +63,9 @@
     static final String VM_USERDATA_MAX_LENGTH_STRING = "vm.userdata.max.length";
     static final ConfigKey<Integer> VM_USERDATA_MAX_LENGTH = new ConfigKey<>("Advanced", Integer.class, VM_USERDATA_MAX_LENGTH_STRING, "32768",
             "Max length of vm userdata after base64 decoding. Default is 32768 and maximum is 1048576", true);
+    public static final ConfigKey<Boolean> AllowNonRFC1918CompliantIPs = new ConfigKey<Boolean>(Boolean.class,
+            "allow.non.rfc1918.compliant.ips", "Advanced", "false",
+            "Allows non-compliant RFC 1918 IPs for Shared, Isolated networks and VPCs", true);
 
     /**
      * @param offering
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 7a2c345..ec37788 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
@@ -1736,7 +1736,7 @@
 
         //apply network ACLs
         // TODO: remove check for NSX
-        if (!offering.isForNsx() && !_networkACLMgr.applyACLToNetwork(networkId)) {
+        if (!_networkACLMgr.applyACLToNetwork(networkId)) {
             s_logger.warn("Failed to reapply network ACLs as a part of  of network id=" + networkId + " restart");
             success = false;
         }
@@ -2863,7 +2863,7 @@
 
         // Check if cidr is RFC1918 compliant if the network is Guest Isolated for IPv4
         if (cidr != null && ntwkOff.getGuestType() == Network.GuestType.Isolated && ntwkOff.getTrafficType() == TrafficType.Guest) {
-            if (!NetUtils.validateGuestCidr(cidr)) {
+            if (!ConfigurationManager.AllowNonRFC1918CompliantIPs.value() && !NetUtils.validateGuestCidr(cidr)) {
                 throw new InvalidParameterValueException("Virtual Guest Cidr " + cidr + " is not RFC 1918 or 6598 compliant");
             }
         }
@@ -4720,7 +4720,9 @@
             "Time (in seconds) to wait before shutting down a network that's not in used", false, Scope.Global, null);
     public static final ConfigKey<Integer> NetworkGcInterval = new ConfigKey<Integer>(Integer.class, "network.gc.interval", "Advanced", "600",
             "Seconds to wait before checking for networks to shutdown", true, Scope.Global, null);
-
+//    public static final ConfigKey<Boolean> AllowNonRFC1918CompliantIPs = new ConfigKey<Boolean>(Boolean.class,
+//            "allow.non.rfc1918.compliant.ips", "Advanced", "false",
+//            "Allows non-compliant RFC 1918 IPs for Shared, Isolated networks and VPCs", true);
     @Override
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey<?>[]{NetworkGcWait, NetworkGcInterval, NetworkLockTimeout,
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
index 56af161..8d5caee 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
@@ -1900,10 +1900,10 @@
         defaultKubernetesServiceNetworkOfferingProviders.put(Service.SourceNat, forNsx ? Network.Provider.Nsx : Network.Provider.VirtualRouter);
         defaultKubernetesServiceNetworkOfferingProviders.put(Service.StaticNat, forNsx ? Network.Provider.Nsx : Network.Provider.VirtualRouter);
         defaultKubernetesServiceNetworkOfferingProviders.put(Service.PortForwarding, forNsx ? Network.Provider.Nsx : Network.Provider.VirtualRouter);
-        defaultKubernetesServiceNetworkOfferingProviders.put(Service.Vpn, forNsx ? Network.Provider.Nsx : Network.Provider.VirtualRouter);
 
         if (!forNsx) {
             defaultKubernetesServiceNetworkOfferingProviders.put(Service.Gateway, Network.Provider.VirtualRouter);
+            defaultKubernetesServiceNetworkOfferingProviders.put(Service.Vpn, Network.Provider.VirtualRouter);
         }
 
         NetworkOfferingVO defaultKubernetesServiceNetworkOffering =
@@ -1914,6 +1914,9 @@
                         true, false, false, false, false,
                         false, false, false, true, true, false,
                         false, true, false, false);
+        if (forNsx) {
+            defaultKubernetesServiceNetworkOffering.setNsxMode(NetworkOffering.NsxMode.NATTED.name());
+        }
         defaultKubernetesServiceNetworkOffering.setSupportsVmAutoScaling(true);
         defaultKubernetesServiceNetworkOffering.setState(NetworkOffering.State.Enabled);
         defaultKubernetesServiceNetworkOffering = networkOfferingDao.persistDefaultNetworkOffering(defaultKubernetesServiceNetworkOffering);
diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDistributedFirewallRuleCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDistributedFirewallRuleCommand.java
new file mode 100644
index 0000000..35ce74b
--- /dev/null
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxDistributedFirewallRuleCommand.java
@@ -0,0 +1,52 @@
+package org.apache.cloudstack.agent.api;
+
+import java.util.List;
+
+public class CreateNsxDistributedFirewallRuleCommand extends NsxNetworkCommand {
+    private List<String> sourceCidrList;
+    private String protocol;
+    private String trafficType;
+    private String action;
+    public CreateNsxDistributedFirewallRuleCommand(long domainId, long accountId, long zoneId, Long networkResourceId,
+                                                   String networkResourceName, boolean isResourceVpc,
+                                                   List<String> sourceCidrList, String protocol,
+                                                   String trafficType, String action) {
+        super(domainId, accountId, zoneId, networkResourceId, networkResourceName, isResourceVpc);
+        this.sourceCidrList = sourceCidrList;
+        this.protocol = protocol;
+        this.action = action;
+        this.trafficType = trafficType;
+    }
+
+    public List<String> getSourceCidrList() {
+        return sourceCidrList;
+    }
+
+    public void setSourceCidrList(List<String> sourceCidrList) {
+        this.sourceCidrList = sourceCidrList;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public String getTrafficType() {
+        return trafficType;
+    }
+
+    public void setTrafficType(String trafficType) {
+        this.trafficType = trafficType;
+    }
+
+    public String getAction() {
+        return action;
+    }
+
+    public void setAction(String action) {
+        this.action = action;
+    }
+}
diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java
index 5d830f1..a562b1b 100644
--- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java
@@ -34,6 +34,9 @@
     private String protocol;
     private String algorithm;
     private List<NsxLoadBalancerMember> memberList;
+    private String aclAction;
+    private List<String> cidrList;
+    private String trafficType;
 
     public long getDomainId() {
         return domainId;
@@ -155,6 +158,30 @@
         this.memberList = memberList;
     }
 
+    public String getAclAction() {
+        return aclAction;
+    }
+
+    public void setAclAction(String aclAction) {
+        this.aclAction = aclAction;
+    }
+
+    public List<String> getCidrList() {
+        return cidrList;
+    }
+
+    public void setCidrList(List<String> cidrList) {
+        this.cidrList = cidrList;
+    }
+
+    public String getTrafficType() {
+        return trafficType;
+    }
+
+    public void setTrafficType(String trafficType) {
+        this.trafficType = trafficType;
+    }
+
     public static final class Builder {
         private long domainId;
         private long accountId;
@@ -172,6 +199,9 @@
         private String protocol;
         private String algorithm;
         private List<NsxLoadBalancerMember> memberList;
+        private String aclAction;
+        private List<String> cidrList;
+        private String trafficType;
 
         public Builder() {
         }
@@ -252,6 +282,21 @@
             return this;
         }
 
+        public Builder setAclAction(String aclAction) {
+            this.aclAction = aclAction;
+            return this;
+        }
+
+        public Builder setCidrList(List<String> cidrList) {
+            this.cidrList = cidrList;
+            return this;
+        }
+
+        public Builder setTrafficType(String trafficType) {
+            this.trafficType = trafficType;
+            return this;
+        }
+
         public NsxNetworkRule build() {
             NsxNetworkRule rule = new NsxNetworkRule();
             rule.setDomainId(this.domainId);
@@ -269,6 +314,9 @@
             rule.setRuleId(this.ruleId);
             rule.setAlgorithm(this.algorithm);
             rule.setMemberList(this.memberList);
+            rule.setAclAction(this.aclAction);
+            rule.setCidrList(this.cidrList);
+            rule.setTrafficType(this.trafficType);
             return rule;
         }
     }
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 7ca38bb..633b812 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
@@ -36,6 +36,7 @@
 import org.apache.cloudstack.NsxAnswer;
 import org.apache.cloudstack.StartupNsxCommand;
 import org.apache.cloudstack.agent.api.CreateNsxDhcpRelayConfigCommand;
+import org.apache.cloudstack.agent.api.CreateNsxDistributedFirewallRuleCommand;
 import org.apache.cloudstack.agent.api.CreateNsxLoadBalancerRuleCommand;
 import org.apache.cloudstack.agent.api.CreateNsxPortForwardRuleCommand;
 import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand;
@@ -123,6 +124,8 @@
             return executeRequest((CreateNsxLoadBalancerRuleCommand) cmd);
         } else if (cmd instanceof DeleteNsxLoadBalancerRuleCommand) {
             return executeRequest((DeleteNsxLoadBalancerRuleCommand) cmd);
+        } else if (cmd instanceof CreateNsxDistributedFirewallRuleCommand) {
+            return executeRequest((CreateNsxDistributedFirewallRuleCommand) cmd);
         } else {
             return Answer.createUnsupportedCommandAnswer(cmd);
         }
@@ -290,7 +293,7 @@
 
     private Answer executeRequest(CreateNsxTier1GatewayCommand cmd) {
         String name = NsxControllerUtils.getTier1GatewayName(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(), cmd.getNetworkResourceId(), cmd.isResourceVpc());
-        boolean sourceNatEnabled = cmd.isSourceNatEnabled();
+        boolean sourceNatEnabled = cmd.isSourceNatEnabled() || !cmd.isResourceVpc();
         try {
             nsxApiClient.createTier1Gateway(name, tier0Gateway, edgeCluster, sourceNatEnabled);
             return new NsxAnswer(cmd, true, "");
@@ -454,6 +457,12 @@
         return new NsxAnswer(cmd, true, null);
     }
 
+    private NsxAnswer executeRequest(CreateNsxDistributedFirewallRuleCommand cmd) {
+        String segmentName = NsxControllerUtils.getNsxSegmentId(cmd.getDomainId(), cmd.getAccountId(), cmd.getZoneId(),
+                cmd.isResourceVpc() ? cmd.getNetworkResourceId() : null, cmd.isResourceVpc() ? null : cmd.getNetworkResourceId());
+        // TODO: execute apiclient
+    }
+
     @Override
     public boolean start() {
         return true;
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 3f4203c..baf463c 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
@@ -29,6 +29,7 @@
 import com.vmware.nsx_policy.infra.Services;
 import com.vmware.nsx_policy.infra.Sites;
 import com.vmware.nsx_policy.infra.Tier1s;
+import com.vmware.nsx_policy.infra.domains.security_policies.Rules;
 import com.vmware.nsx_policy.infra.sites.EnforcementPoints;
 import com.vmware.nsx_policy.infra.tier_0s.LocaleServices;
 import com.vmware.nsx_policy.infra.tier_1s.nat.NatRules;
@@ -46,6 +47,7 @@
 import com.vmware.nsx_policy.model.LocaleServicesListResult;
 import com.vmware.nsx_policy.model.PolicyNatRule;
 import com.vmware.nsx_policy.model.PolicyNatRuleListResult;
+import com.vmware.nsx_policy.model.Rule;
 import com.vmware.nsx_policy.model.Segment;
 import com.vmware.nsx_policy.model.SegmentSubnet;
 import com.vmware.nsx_policy.model.ServiceListResult;
@@ -71,18 +73,13 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
-import static org.apache.cloudstack.utils.NsxControllerUtils.getServerPoolMemberName;
-import static org.apache.cloudstack.utils.NsxControllerUtils.getServerPoolName;
-import static org.apache.cloudstack.utils.NsxControllerUtils.getServiceName;
-import static org.apache.cloudstack.utils.NsxControllerUtils.getVirtualServerName;
-import static org.apache.cloudstack.utils.NsxControllerUtils.getServiceEntryName;
-import static org.apache.cloudstack.utils.NsxControllerUtils.getLoadBalancerName;
-import static org.apache.cloudstack.utils.NsxControllerUtils.getLoadBalancerAlgorithm;
+import static org.apache.cloudstack.utils.NsxControllerUtils.*;
 
 public class NsxApiClient {
 
@@ -133,6 +130,17 @@
         XLARGE
     }
 
+    private enum firewallActions {
+        ALLOW,
+        DROP,
+        REJECT,
+        JUMP_TO_APPLICATION
+    }
+
+    private Map<String,String> actionMap = Map.of(
+        "Allow", firewallActions.ALLOW.name(),
+    "Deny", firewallActions.DROP.name());
+
     public enum  RouteAdvertisementType { TIER1_STATIC_ROUTES, TIER1_CONNECTED, TIER1_NAT,
         TIER1_LB_VIP, TIER1_LB_SNAT, TIER1_DNS_FORWARDER_IP, TIER1_IPSEC_LOCAL_ENDPOINT
     }
@@ -699,6 +707,25 @@
         }
     }
 
+    public void createNsxFirewallRule(String policyName, String ruleName, String action, List<String> cidrList, String protocol, String trafficType) {
+        try {
+            Rules rules = (Rules) nsxService.apply(Rules.class);
+            Rule rule = new Rule.Builder()
+                    .setId(ruleName)
+                    .setDisplayName(ruleName)
+                    .setAction(actionMap.get(action))
+                    .setSourceGroups(cidrList)
+                    .build();
+            //TODO: get default domain
+            rules.patch("default", policyName, ruleName, rule);
+        } catch (Error error) {
+            ApiError ae = error.getData()._convertTo(ApiError.class);
+            String msg = String.format("Failed to create NSX infra service, due to: %s", ae.getErrorMessage());
+            LOGGER.error(msg);
+            throw new CloudRuntimeException(msg);
+        }
+    }
+
     private String getServiceById(String ruleName) {
         try {
             Services service = (Services) nsxService.apply(Services.class);
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 031c445..394d82c 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
@@ -56,6 +56,7 @@
 import com.cloud.network.element.DnsServiceProvider;
 import com.cloud.network.element.IpDeployer;
 import com.cloud.network.element.LoadBalancingServiceProvider;
+import com.cloud.network.element.NetworkACLServiceProvider;
 import com.cloud.network.element.PortForwardingServiceProvider;
 import com.cloud.network.element.StaticNatServiceProvider;
 import com.cloud.network.element.VpcProvider;
@@ -87,6 +88,7 @@
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachineProfile;
 import com.cloud.vm.dao.VMInstanceDao;
+import com.vmware.nsx_policy.infra.firewall.Rules;
 import net.sf.ehcache.config.InvalidConfigurationException;
 import org.apache.cloudstack.StartupNsxCommand;
 import org.apache.cloudstack.resource.NsxLoadBalancerMember;
@@ -107,7 +109,7 @@
 
 @Component
 public class NsxElement extends AdapterBase implements  DhcpServiceProvider, DnsServiceProvider, VpcProvider,
-        StaticNatServiceProvider, IpDeployer, PortForwardingServiceProvider,
+        StaticNatServiceProvider, IpDeployer, PortForwardingServiceProvider, NetworkACLServiceProvider,
         LoadBalancingServiceProvider, ResourceStateAdapter, Listener {
 
 
@@ -159,7 +161,14 @@
         capabilities.put(Network.Service.Lb, null);
         capabilities.put(Network.Service.PortForwarding, null);
         capabilities.put(Network.Service.NetworkACL, null);
-        capabilities.put(Network.Service.Firewall, null);
+        Map<Network.Capability, String> firewallCapabilities = new HashMap<>();
+        firewallCapabilities.put(Network.Capability.SupportedProtocols, "tcp,udp,icmp");
+        firewallCapabilities.put(Network.Capability.SupportedEgressProtocols, "tcp,udp,icmp,all");
+        firewallCapabilities.put(Network.Capability.MultipleIps, "true");
+        firewallCapabilities.put(Network.Capability.TrafficStatistics, "per public ip");
+        firewallCapabilities.put(Network.Capability.SupportedTrafficDirection, "ingress, egress");
+        capabilities.put(Network.Service.Firewall, firewallCapabilities);
+
         Map<Network.Capability, String> sourceNatCapabilities = new HashMap<>();
         sourceNatCapabilities.put(Network.Capability.RedundantRouter, "true");
         sourceNatCapabilities.put(Network.Capability.SupportedSourceNatTypes, "peraccount");
@@ -646,4 +655,16 @@
         }
         return lbMembers;
     }
+
+    @Override
+    public boolean applyNetworkACLs(Network config, List<? extends NetworkACLItem> rules) throws ResourceUnavailableException {
+        if (!canHandle(config, Network.Service.NetworkACL)) {
+            return false;
+        }
+        NsxNetworkRule networkRule = new NsxNetworkRule.Builder().build();
+        for (NetworkACLItem rule : rules) {
+            nsxService.addFirewallRule(networkRule);
+        }
+        return true;
+    }
 }
diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java
index d507d91..31eedb5 100644
--- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java
@@ -80,8 +80,9 @@
     public boolean canHandle(NetworkOffering offering, DataCenter.NetworkType networkType,
                              PhysicalNetwork physicalNetwork) {
         return networkType == DataCenter.NetworkType.Advanced && isMyTrafficType(offering.getTrafficType())
-                && isMyIsolationMethod(physicalNetwork) && networkOfferingServiceMapDao.isProviderForNetworkOffering(
-                offering.getId(), Network.Provider.Nsx);
+                && isMyIsolationMethod(physicalNetwork) && (NetworkOffering.NsxMode.ROUTED.name().equals(offering.getNsxMode())
+        || (networkOfferingServiceMapDao.isProviderForNetworkOffering(
+                offering.getId(), Network.Provider.Nsx) && NetworkOffering.NsxMode.NATTED.name().equals(offering.getNsxMode())));
     }
 
     @Override
diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java
index b9fcb53..14429ae 100644
--- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java
+++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java
@@ -28,10 +28,13 @@
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.guru.PublicNetworkGuru;
+import com.cloud.network.vpc.VpcOffering;
 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.dao.NetworkOfferingDao;
 import com.cloud.user.Account;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.NicProfile;
@@ -60,6 +63,10 @@
     private NsxControllerUtils nsxControllerUtils;
     @Inject
     private NsxService nsxService;
+    @Inject
+    private VpcOfferingDao vpcOfferingDao;
+    @Inject
+    private NetworkOfferingDao offeringDao;
 
     private static final Logger s_logger = Logger.getLogger(NsxPublicNetworkGuru.class);
 
@@ -128,7 +135,7 @@
                 long dataCenterId = vpc.getZoneId();
                 boolean isForVpc = true;
                 long resourceId = isForVpc ? vpc.getId() : network.getId();
-                Network.Service[] services = { Network.Service.SourceNat };
+                Network.Service[] services = {Network.Service.SourceNat};
                 boolean sourceNatEnabled = vpcOfferingServiceMapDao.areServicesSupportedByVpcOffering(vpc.getVpcOfferingId(), services);
 
                 s_logger.info(String.format("Creating Tier 1 Gateway for VPC %s", vpc.getName()));
@@ -139,16 +146,27 @@
                     throw new CloudRuntimeException(msg);
                 }
 
-                String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(domainId, accountId, dataCenterId, resourceId, isForVpc);
-                String translatedIp = ipAddress.getAddress().addr();
-                s_logger.debug(String.format("Creating NSX Nat Rule for Tier1 GW %s for translated IP %s", tier1GatewayName, translatedIp));
-                String natRuleId = NsxControllerUtils.getNsxNatRuleId(domainId, accountId, dataCenterId, resourceId, isForVpc);
-                CreateOrUpdateNsxTier1NatRuleCommand cmd = NsxHelper.createOrUpdateNsxNatRuleCommand(domainId, accountId, dataCenterId, tier1GatewayName, "SNAT", translatedIp, natRuleId);
-                NsxAnswer nsxAnswer = nsxControllerUtils.sendNsxCommand(cmd, dataCenterId);
-                if (!nsxAnswer.getResult()) {
-                    String msg = String.format("Could not create NSX Nat Rule on Tier1 Gateway %s for IP %s", tier1GatewayName, translatedIp);
-                    s_logger.error(msg);
-                    throw new CloudRuntimeException(msg);
+                boolean hasNatSupport = false;
+                if (vpc == null) {
+                    NetworkOffering offering = offeringDao.findById(network.getNetworkOfferingId());
+                    hasNatSupport = NetworkOffering.NsxMode.NATTED.name().equals(offering.getNsxMode());
+                } else {
+                    VpcOffering vpcOffering = vpcOfferingDao.findById(vpc.getVpcOfferingId());
+                    hasNatSupport = NetworkOffering.NsxMode.NATTED.name().equals(vpcOffering.getNsxMode());
+                }
+
+                if (hasNatSupport) {
+                    String tier1GatewayName = NsxControllerUtils.getTier1GatewayName(domainId, accountId, dataCenterId, resourceId, isForVpc);
+                    String translatedIp = ipAddress.getAddress().addr();
+                    s_logger.debug(String.format("Creating NSX Nat Rule for Tier1 GW %s for translated IP %s", tier1GatewayName, translatedIp));
+                    String natRuleId = NsxControllerUtils.getNsxNatRuleId(domainId, accountId, dataCenterId, resourceId, isForVpc);
+                    CreateOrUpdateNsxTier1NatRuleCommand cmd = NsxHelper.createOrUpdateNsxNatRuleCommand(domainId, accountId, dataCenterId, tier1GatewayName, "SNAT", translatedIp, natRuleId);
+                    NsxAnswer nsxAnswer = nsxControllerUtils.sendNsxCommand(cmd, dataCenterId);
+                    if (!nsxAnswer.getResult()) {
+                        String msg = String.format("Could not create NSX Nat Rule on Tier1 Gateway %s for IP %s", tier1GatewayName, translatedIp);
+                        s_logger.error(msg);
+                        throw new CloudRuntimeException(msg);
+                    }
                 }
             }
         }
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 6fe5285..f73910c 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
@@ -26,6 +26,7 @@
 import com.cloud.network.vpc.dao.VpcDao;
 import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.cloudstack.NsxAnswer;
+import org.apache.cloudstack.agent.api.CreateNsxDistributedFirewallRuleCommand;
 import org.apache.cloudstack.agent.api.CreateNsxLoadBalancerRuleCommand;
 import org.apache.cloudstack.agent.api.CreateNsxPortForwardRuleCommand;
 import org.apache.cloudstack.agent.api.CreateNsxStaticNatCommand;
@@ -172,4 +173,13 @@
         NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, netRule.getZoneId());
         return result.getResult();
     }
+
+    public boolean addFirewallRule(NsxNetworkRule netRule) {
+        CreateNsxDistributedFirewallRuleCommand command = new CreateNsxDistributedFirewallRuleCommand(netRule.getDomainId(),
+                netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(),
+                netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getCidrList(), netRule.getProtocol(),
+                netRule.getTrafficType(), netRule.getAclAction());
+        NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, netRule.getZoneId());
+        return result.getResult();
+    }
 }
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 ce6e799..d7d4911 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
@@ -125,6 +125,10 @@
         return tier1GatewayName + "-VM" + vmId;
     }
 
+    public static String getFirewallRuleId(String segmentName, long ruleId) {
+        return segmentName + "-R" + ruleId;
+    }
+
     public static String getLoadBalancerAlgorithm(String algorithm) {
         switch (algorithm) {
             case "leastconn":
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 50c5275..a90b40a 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
@@ -17,9 +17,12 @@
 package com.cloud.api.query.dao;
 
 import java.util.List;
+import java.util.Objects;
 
 import javax.inject.Inject;
 
+import com.cloud.network.dao.NsxProviderDao;
+import com.cloud.network.element.NsxProviderVO;
 import org.apache.cloudstack.annotation.AnnotationService;
 import org.apache.cloudstack.annotation.dao.AnnotationDao;
 import org.apache.cloudstack.api.ResponseObject.ResponseView;
@@ -53,6 +56,8 @@
     public AccountManager _accountMgr;
     @Inject
     private AnnotationDao annotationDao;
+    @Inject
+    private NsxProviderDao nsxProviderDao;
 
     protected DataCenterJoinDaoImpl() {
 
@@ -119,6 +124,11 @@
             }
         }
 
+        NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(dataCenter.getId());
+        if (Objects.nonNull(nsxProviderVO)) {
+            zoneResponse.setNsxEnabled(true);
+        }
+
         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/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index 755a239..595a7a7 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -2648,7 +2648,7 @@
             zoneName = zone.getName();
         }
 
-        if (guestCidr != null && !NetUtils.validateGuestCidr(guestCidr)) {
+        if (guestCidr != null && !AllowNonRFC1918CompliantIPs.value() &&  !NetUtils.validateGuestCidr(guestCidr)) {
             throw new InvalidParameterValueException("Please enter a valid guest cidr");
         }
 
@@ -2817,7 +2817,7 @@
         // checking the following params outside checkzoneparams method as we do
         // not use these params for updatezone
         // hence the method below is generic to check for common params
-        if (guestCidr != null && !NetUtils.validateGuestCidr(guestCidr)) {
+        if (guestCidr != null && !AllowNonRFC1918CompliantIPs.value() && !NetUtils.validateGuestCidr(guestCidr)) {
             throw new InvalidParameterValueException("Please enter a valid guest cidr");
         }
 
@@ -6563,6 +6563,9 @@
 
         offeringFinal.setForTungsten(Objects.requireNonNullElse(forTungsten, false));
         offeringFinal.setForNsx(Objects.requireNonNullElse(forNsx, false));
+        if (Boolean.TRUE.equals(forNsx)) {
+            offeringFinal.setNsxMode(mode);
+        }
 
         if (enableOffering) {
             offeringFinal.setState(NetworkOffering.State.Enabled);
@@ -7717,7 +7720,7 @@
         return new ConfigKey<?>[] {SystemVMUseLocalStorage, IOPS_MAX_READ_LENGTH, IOPS_MAX_WRITE_LENGTH,
                 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, VM_USERDATA_MAX_LENGTH, MIGRATE_VM_ACROSS_CLUSTERS,
-                ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN, ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS
+                ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN, ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, AllowNonRFC1918CompliantIPs
         };
     }
 
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index e891d93..da5c318 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -3125,7 +3125,7 @@
             if (!NetUtils.isValidIp4Cidr(guestVmCidr)) {
                 throw new InvalidParameterValueException("Invalid format of Guest VM CIDR.");
             }
-            if (!NetUtils.validateGuestCidr(guestVmCidr)) {
+            if (!ConfigurationManager.AllowNonRFC1918CompliantIPs.value() && !NetUtils.validateGuestCidr(guestVmCidr)) {
                 throw new InvalidParameterValueException("Invalid format of Guest VM CIDR. Make sure it is RFC1918 compliant. ");
             }
 
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 de94663..7e46a4c 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -40,6 +40,7 @@
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.configuration.ConfigurationManager;
 import com.cloud.network.nsx.NsxService;
 import org.apache.cloudstack.acl.ControlledEntity.ACLType;
 import org.apache.cloudstack.alert.AlertService;
@@ -1215,7 +1216,7 @@
         }
 
         // cidr has to be RFC 1918 complient
-        if (!NetUtils.validateGuestCidr(cidr)) {
+        if (!ConfigurationManager.AllowNonRFC1918CompliantIPs.value() && !NetUtils.validateGuestCidr(cidr)) {
             throw new InvalidParameterValueException("Guest Cidr " + cidr + " is not RFC1918 compliant");
         }
 
@@ -1884,7 +1885,7 @@
 
         // 2) Only Isolated networks with Source nat service enabled can be
         // added to vpc
-        if (!(guestNtwkOff.getGuestType() == GuestType.Isolated && supportedSvcs.contains(Service.SourceNat))) {
+        if (!guestNtwkOff.isForNsx() && !(guestNtwkOff.getGuestType() == GuestType.Isolated && supportedSvcs.contains(Service.SourceNat))) {
 
             throw new InvalidParameterValueException("Only network offerings of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName()
                     + " are valid for vpc ");
@@ -1895,7 +1896,7 @@
          * TODO This should have never been hardcoded like this in the first
          * place if (guestNtwkOff.getRedundantRouter()) { throw new
          * InvalidParameterValueException
-         * ("No redunant router support when network belnogs to VPC"); }
+         * ("No redundant router support when network belongs to VPC"); }
          */
 
         // 4) Conserve mode should be off
diff --git a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
index 69574b2..3490350 100644
--- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
@@ -1247,10 +1247,14 @@
         serviceProviderMap.put(Service.Dns, routerProvider);
         serviceProviderMap.put(Service.UserData, routerProvider);
         if (nsxMode == NetworkOffering.NsxMode.NATTED) {
-            serviceProviderMap.put(Service.SourceNat, Provider.Nsx);
             serviceProviderMap.put(Service.StaticNat, Provider.Nsx);
             serviceProviderMap.put(Service.PortForwarding, Provider.Nsx);
             serviceProviderMap.put(Service.Lb, Provider.Nsx);
+            if (forVpc) {
+                serviceProviderMap.put(Service.NetworkACL, Provider.Nsx);
+            } else {
+                serviceProviderMap.put(Service.Firewall, Provider.Nsx);
+            }
         }
         return serviceProviderMap;
     }