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

pearl11594 pushed a commit to branch netris-integration-upstream
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 1c2c7e3de67b0d74a6f25636389280e5e47424ce
Author: Pearl Dsilva <pearl1...@gmail.com>
AuthorDate: Tue Dec 3 19:35:38 2024 -0500

    Phase4 - Add support for Source NAT, Static NAT and Port Forwarding (#19)
    
    * Run moodifyvxlan script if broadcast domain type is Netris
    
    * Add Netris NAT offerings
    
    * Add support to add Source nat rules for Natted offering
    
    * fix api params while creating Netris source NAT rule
    
    * Add support to add and delete source nat rule on netris
    
    * Add support to create /32 NAT subnet
    
    * Add support to add and delete Static NAT rules in Netris (#23)
    
    * Add support to add and delete Static NAT rules in Netris
    
    * fix static nat creation on netris & removal of subnet on deletion of 
static nat rule
    
    * remove nat subnet after deltion of the static nat rule
    
    * add check to see if subnet already exists and add license header
    
    * Add port forwarding rules as DNAT rules in Netris (#24)
    
    * Add port forwarding rules as DNAT rules in Netris
    
    * Fixes
    
    * Allow removing DNAT rules
    
    * Fixes
    
    * Fix subnet search
    
    * Fix update SNAT only for SNAT rules
    
    * Address comments
    
    * Fix
    
    * Fix netris pom xml
    
    * Fix SNAT rule creation
    
    * Fix IP and port placements (#27)
    
    * Fix IP and port placements
    
    * fix dnat to IP for PF rules
    
    * change dnatport
    
    ---------
    
    Co-authored-by: Nicolas Vazquez <nicovazque...@gmail.com>
---
 .../com/cloud/network/SDNProviderNetworkRule.java  | 204 +++++++++++
 .../element/PortForwardingServiceProvider.java     |  28 ++
 .../com/cloud/network/netris/NetrisService.java    |   8 +
 .../java/com/cloud/network/vpc/VpcOffering.java    |   1 +
 .../java/com/cloud/offering/NetworkOffering.java   |   1 +
 .../engine/orchestration/NetworkOrchestrator.java  |  20 +-
 .../contrail/management/ContrailManagerImpl.java   |   4 +-
 plugins/network-elements/netris/pom.xml            |   2 +-
 .../agent/api/CreateOrUpdateNetrisNatCommand.java  | 149 ++++++++
 .../agent/api/DeleteNetrisNatRuleCommand.java      |  72 ++++
 .../apache/cloudstack/agent/api/NetrisCommand.java |  12 +-
 .../cloudstack/resource/NetrisNetworkRule.java     |  18 +-
 .../apache/cloudstack/resource/NetrisResource.java |  36 ++
 .../resource/NetrisResourceObjectUtils.java        |  16 +-
 .../apache/cloudstack/service/NetrisApiClient.java |  16 +
 .../cloudstack/service/NetrisApiClientImpl.java    | 395 ++++++++++++++++++++-
 .../apache/cloudstack/service/NetrisElement.java   | 196 +++++++++-
 .../cloudstack/service/NetrisGuestNetworkGuru.java |  18 +-
 .../service/NetrisPublicNetworkGuru.java           |   9 +
 .../cloudstack/service/NetrisServiceImpl.java      | 139 ++++++++
 .../resource/NetrisResourceObjectUtilsTest.java    |  12 +
 .../apache/cloudstack/resource/NsxNetworkRule.java | 354 +-----------------
 .../org/apache/cloudstack/service/NsxElement.java  | 158 ++++-----
 .../apache/cloudstack/service/NsxElementTest.java  |  42 +--
 .../com/cloud/network/SDNProviderOpObject.java     |   8 +-
 .../java/com/cloud/network/vpc/VpcManagerImpl.java |  18 +
 .../com/cloud/server/ConfigurationServerImpl.java  |   4 +
 27 files changed, 1415 insertions(+), 525 deletions(-)

diff --git a/api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java 
b/api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java
new file mode 100644
index 00000000000..15238f85bb6
--- /dev/null
+++ b/api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java
@@ -0,0 +1,204 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network;
+
+import java.util.List;
+
+public class SDNProviderNetworkRule {
+
+    private long domainId;
+    private long accountId;
+    private long zoneId;
+    private Long networkResourceId;
+    private String networkResourceName;
+    private boolean isVpcResource;
+    private long vmId;
+    private long ruleId;
+    private String publicIp;
+    private String vmIp;
+    private String publicPort;
+    private String privatePort;
+    private String protocol;
+    private String algorithm;
+    private List<String> sourceCidrList;
+    private List<String> destinationCidrList;
+    private Integer icmpCode;
+
+    private Integer icmpType;
+    private String trafficType;
+    private Network.Service service;
+
+    public long getDomainId() {
+        return domainId;
+    }
+
+    public void setDomainId(long domainId) {
+        this.domainId = domainId;
+    }
+
+    public long getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(long accountId) {
+        this.accountId = accountId;
+    }
+
+    public long getZoneId() {
+        return zoneId;
+    }
+
+    public void setZoneId(long zoneId) {
+        this.zoneId = zoneId;
+    }
+
+    public Long getNetworkResourceId() {
+        return networkResourceId;
+    }
+
+    public void setNetworkResourceId(Long networkResourceId) {
+        this.networkResourceId = networkResourceId;
+    }
+
+    public String getNetworkResourceName() {
+        return networkResourceName;
+    }
+
+    public void setNetworkResourceName(String networkResourceName) {
+        this.networkResourceName = networkResourceName;
+    }
+
+    public boolean isVpcResource() {
+        return isVpcResource;
+    }
+
+    public void setVpcResource(boolean vpcResource) {
+        isVpcResource = vpcResource;
+    }
+
+    public long getVmId() {
+        return vmId;
+    }
+
+    public void setVmId(long vmId) {
+        this.vmId = vmId;
+    }
+
+    public long getRuleId() {
+        return ruleId;
+    }
+
+    public void setRuleId(long ruleId) {
+        this.ruleId = ruleId;
+    }
+
+    public String getPublicIp() {
+        return publicIp;
+    }
+
+    public void setPublicIp(String publicIp) {
+        this.publicIp = publicIp;
+    }
+
+    public String getVmIp() {
+        return vmIp;
+    }
+
+    public void setVmIp(String vmIp) {
+        this.vmIp = vmIp;
+    }
+
+    public String getPublicPort() {
+        return publicPort;
+    }
+
+    public void setPublicPort(String publicPort) {
+        this.publicPort = publicPort;
+    }
+
+    public String getPrivatePort() {
+        return privatePort;
+    }
+
+    public void setPrivatePort(String privatePort) {
+        this.privatePort = privatePort;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    public Network.Service getService() {
+        return service;
+    }
+
+    public void setService(Network.Service service) {
+        this.service = service;
+    }
+
+    public Integer getIcmpCode() {
+        return icmpCode;
+    }
+
+    public void setIcmpCode(Integer icmpCode) {
+        this.icmpCode = icmpCode;
+    }
+
+    public Integer getIcmpType() {
+        return icmpType;
+    }
+
+    public void setIcmpType(Integer icmpType) {
+        this.icmpType = icmpType;
+    }
+
+    public List<String> getSourceCidrList() {
+        return sourceCidrList;
+    }
+
+    public void setSourceCidrList(List<String> sourceCidrList) {
+        this.sourceCidrList = sourceCidrList;
+    }
+
+    public List<String> getDestinationCidrList() {
+        return destinationCidrList;
+    }
+
+    public void setDestinationCidrList(List<String> destinationCidrList) {
+        this.destinationCidrList = destinationCidrList;
+    }
+
+    public String getTrafficType() {
+        return trafficType;
+    }
+
+    public void setTrafficType(String trafficType) {
+        this.trafficType = trafficType;
+    }
+}
diff --git 
a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java
 
b/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java
index e99bc2fd416..8dcc8b6d0a4 100644
--- 
a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java
+++ 
b/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java
@@ -17,12 +17,40 @@
 package com.cloud.network.element;
 
 import java.util.List;
+import java.util.Objects;
 
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.network.Network;
+import com.cloud.network.rules.FirewallRule;
 import com.cloud.network.rules.PortForwardingRule;
+import com.cloud.network.vpc.NetworkACLItem;
 
 public interface PortForwardingServiceProvider extends NetworkElement, 
IpDeployingRequester {
+
+    static String getPublicPortRange(PortForwardingRule rule) {
+        return Objects.equals(rule.getSourcePortStart(), 
rule.getSourcePortEnd()) ?
+                String.valueOf(rule.getSourcePortStart()) :
+                
String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd()));
+    }
+
+    static String getPrivatePFPortRange(PortForwardingRule rule) {
+        return rule.getDestinationPortStart() == rule.getDestinationPortEnd() ?
+                String.valueOf(rule.getDestinationPortStart()) :
+                
String.valueOf(rule.getDestinationPortStart()).concat("-").concat(String.valueOf(rule.getDestinationPortEnd()));
+    }
+
+    static String getPrivatePortRange(FirewallRule rule) {
+        return Objects.equals(rule.getSourcePortStart(), 
rule.getSourcePortEnd()) ?
+                String.valueOf(rule.getSourcePortStart()) :
+                
String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd()));
+    }
+
+    static String getPrivatePortRangeForACLRule(NetworkACLItem rule) {
+        return Objects.equals(rule.getSourcePortStart(), 
rule.getSourcePortEnd()) ?
+                String.valueOf(rule.getSourcePortStart()) :
+                
String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd()));
+    }
+
     /**
      * Apply rules
      * @param network
diff --git a/api/src/main/java/com/cloud/network/netris/NetrisService.java 
b/api/src/main/java/com/cloud/network/netris/NetrisService.java
index f6203874c2d..ea2f73383e0 100644
--- a/api/src/main/java/com/cloud/network/netris/NetrisService.java
+++ b/api/src/main/java/com/cloud/network/netris/NetrisService.java
@@ -16,6 +16,8 @@
 // under the License.
 package com.cloud.network.netris;
 
+import com.cloud.network.IpAddress;
+import com.cloud.network.SDNProviderNetworkRule;
 import com.cloud.network.vpc.Vpc;
 
 public interface NetrisService {
@@ -23,4 +25,10 @@ public interface NetrisService {
     boolean deleteVpcResource(long zoneId, long accountId, long domainId, Vpc 
vpc);
     boolean createVnetResource(Long zoneId, long accountId, long domainId, 
String vpcName, Long vpcId, String networkName, Long networkId, String cidr);
     boolean deleteVnetResource(long zoneId, long accountId, long domainId, 
String vpcName, Long vpcId, String networkName, Long networkId, String cidr);
+    boolean createSnatRule(long zoneId, long accountId, long domainId, String 
vpcName, long vpcId, String networkName, long networkId, boolean isForVpc, 
String vpcCidr, String sourceNatIp);
+    boolean createPortForwardingRule(long zoneId, long accountId, long 
domainId, String vpcName, long vpcId, String networkName, Long networkId, 
boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule);
+    boolean deletePortForwardingRule(long zoneId, long accountId, long 
domainId, String vpcName, Long vpcId, String networkName, Long networkId, 
boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule);
+    boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address);
+    boolean createStaticNatRule(long zoneId, long accountId, long domainId, 
String networkResourceName, Long networkResourceId, boolean isForVpc, String 
vpcCidr, String staticNatIp, String vmIp);
+    boolean deleteStaticNatRule(long zoneId, long accountId, long domainId, 
String networkResourceName, Long networkResourceId, boolean isForVpc, String 
staticNatIp);
 }
diff --git a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java 
b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java
index 77d52991130..17f49bb3652 100644
--- a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java
+++ b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java
@@ -33,6 +33,7 @@ public interface VpcOffering extends InternalIdentity, 
Identity {
     public static final String DEFAULT_VPC_NAT_NSX_OFFERING_NAME = "VPC 
offering with NSX - NAT Mode";
     public static final String DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME = "VPC 
offering with NSX - Route Mode";
     public static final String DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME = "VPC 
offering with Netris - Route Mode";
+    public static final String DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME = "VPC 
offering with Netris - NAT Mode";
 
     /**
      *
diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java 
b/api/src/main/java/com/cloud/offering/NetworkOffering.java
index 4df01bd8986..5000a4f8c62 100644
--- a/api/src/main/java/com/cloud/offering/NetworkOffering.java
+++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java
@@ -65,6 +65,7 @@ public interface NetworkOffering extends 
InfrastructureEntity, InternalIdentity,
     public static final String DEFAULT_NAT_NSX_OFFERING_FOR_VPC_WITH_ILB = 
"DefaultNATNSXNetworkOfferingForVpcWithInternalLB";
     public static final String DEFAULT_ROUTED_NSX_OFFERING_FOR_VPC = 
"DefaultRoutedNSXNetworkOfferingForVpc";
     public static final String DEFAULT_ROUTED_NETRIS_OFFERING_FOR_VPC = 
"DefaultRoutedNetrisNetworkOfferingForVpc";
+    public static final String DEFAULT_NAT_NETRIS_OFFERING_FOR_VPC = 
"DefaultNATNetrisNetworkOfferingForVpc";
     public static final String DEFAULT_NAT_NSX_OFFERING = 
"DefaultNATNSXNetworkOffering";
     public static final String DEFAULT_ROUTED_NSX_OFFERING = 
"DefaultRoutedNSXNetworkOffering";
     public final static String QuickCloudNoServices = "QuickCloudNoServices";
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 c80c4769573..47aab7ebbf0 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
@@ -561,27 +561,27 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                 if 
(_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == 
null) {
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, 
"Offering for QuickCloud with no services", TrafficType.Guest, null, true,
                             Availability.Optional, null, new 
HashMap<Network.Service, Set<Network.Provider>>(), true, 
Network.GuestType.Shared, false, null, true, null, true,
-                            false, null, false, null, true, false, false, 
false, null, null, null, true, null, null, false);
+                            false, null, false, null, true, false, false, 
false, false,null, null, null, true, null, null, false);
                 }
 
                 //#2 - SG enabled network offering
                 if 
(_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService)
 == null) {
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService,
 "Offering for Shared Security group enabled networks",
                             TrafficType.Guest, null, true, 
Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, 
Network.GuestType.Shared, false, null, true,
-                            null, true, false, null, false, null, true, false, 
false, false, null, null, null, true, null, null, false);
+                            null, true, false, null, false, null, true, false, 
false, false, false,null, null, null, true, null, null, false);
                 }
 
                 //#3 - shared network offering with no SG service
                 if 
(_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering)
 == null) {
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, 
"Offering for Shared networks", TrafficType.Guest, null, true,
                             Availability.Optional, null, 
defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, 
null, true, null, true, false, null, false,
-                            null, true, false, false, false, null,null, null, 
true, null, null, false);
+                            null, true, false, false, false, false,null,null, 
null, true, null, null, false);
                 }
 
                 if 
(_networkOfferingDao.findByUniqueName(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE)
 == null) {
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE,
 "Offering for Tungsten Shared Security group enabled networks",
                             TrafficType.Guest, null, true, 
Availability.Optional, null, 
defaultTungstenSharedSGEnabledNetworkOfferingProviders, true, 
Network.GuestType.Shared, false, null, true,
-                            null, true, false, null, false, null, true, false, 
true, false, null, null,null, true, null, null, false);
+                            null, true, false, null, false, null, true, false, 
true, false, false,null, null,null, true, null, null, false);
                     offering.setState(NetworkOffering.State.Enabled);
                     _networkOfferingDao.update(offering.getId(), offering);
                 }
@@ -591,14 +591,14 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService,
                             "Offering for Isolated networks with Source Nat 
service enabled", TrafficType.Guest, null, false, Availability.Required, null,
                             
defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, 
Network.GuestType.Isolated, false, null, true, null, false, false, null, false, 
null,
-                            true, false, false, false, null, null,null, true, 
null, null, false);
+                            true, false, false, false, false,null, null,null, 
true, null, null, false);
                 }
 
                 //#5 - default vpc offering with LB service
                 if 
(_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks)
 == null) {
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks,
                             "Offering for Isolated VPC networks with Source 
Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, 
null,
-                            defaultVPCOffProviders, true, 
Network.GuestType.Isolated, false, null, false, null, false, false, null, 
false, null, true, true, false, false, null, null, null,true, null, null, 
false);
+                            defaultVPCOffProviders, true, 
Network.GuestType.Isolated, false, null, false, null, false, false, null, 
false, null, true, true, false, false, false,null, null, null,true, null, null, 
false);
                 }
 
                 //#6 - default vpc offering with no LB service
@@ -607,14 +607,14 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                     defaultVPCOffProviders.remove(Service.Lb);
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB,
                             "Offering for Isolated VPC networks with Source 
Nat service enabled and LB service disabled", TrafficType.Guest, null, false, 
Availability.Optional,
-                            null, defaultVPCOffProviders, true, 
Network.GuestType.Isolated, false, null, false, null, false, false, null, 
false, null, true, true, false, false, null, null, null,true, null, null, 
false);
+                            null, defaultVPCOffProviders, true, 
Network.GuestType.Isolated, false, null, false, null, false, false, null, 
false, null, true, true, false, false, false,null, null, null,true, null, null, 
false);
                 }
 
                 //#7 - isolated offering with source nat disabled
                 if 
(_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering)
 == null) {
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering,
 "Offering for Isolated networks with no Source Nat service",
                             TrafficType.Guest, null, true, 
Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, 
Network.GuestType.Isolated, false, null,
-                            true, null, true, false, null, false, null, true, 
false, false, false, null, null, null, true, null, null, false);
+                            true, null, true, false, null, false, null, true, 
false, false, false, false,null, null, null, true, null, null, false);
                 }
 
                 //#8 - network offering with internal lb service
@@ -636,7 +636,7 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                 if 
(_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB)
 == null) {
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB,
                             "Offering for Isolated VPC networks with Internal 
Lb support", TrafficType.Guest, null, false, Availability.Optional, null, 
internalLbOffProviders,
-                            true, Network.GuestType.Isolated, false, null, 
false, null, false, false, null, false, null, true, true, false, false, null, 
null, null, true, null, null, false);
+                            true, Network.GuestType.Isolated, false, null, 
false, null, false, false, null, false, null, true, true, false, false, 
false,null, null, null, true, null, null, false);
                     offering.setInternalLb(true);
                     offering.setPublicLb(false);
                     _networkOfferingDao.update(offering.getId(), offering);
@@ -667,7 +667,7 @@ public class NetworkOrchestrator extends ManagerBase 
implements NetworkOrchestra
                 if 
(_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering)
 == null) {
                     offering = 
_configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering,
                             "Offering for Shared networks with Elastic IP and 
Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, 
null,
-                            netscalerServiceProviders, true, 
Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, 
null, false, null, true, false, false, false, null, null, null, true, null, 
null, false);
+                            netscalerServiceProviders, true, 
Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, 
null, false, null, true, false, false, false,false, null, null, null, true, 
null, null, false);
                     offering.setDedicatedLB(false);
                     _networkOfferingDao.update(offering.getId(), offering);
                 }
diff --git 
a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java
 
b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java
index 6da2e216ff8..622886e6d83 100644
--- 
a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java
+++ 
b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java
@@ -217,7 +217,7 @@ public class ContrailManagerImpl extends ManagerBase 
implements ContrailManager
         ConfigurationManager configMgr = (ConfigurationManager) _configService;
         NetworkOfferingVO voffer = 
configMgr.createNetworkOffering(offeringName, offeringDisplayText,
                 TrafficType.Public, null, true, Availability.Optional, null, 
serviceProviderMap, true,
-                Network.GuestType.Shared, false, null, false, null, true, 
false, null, true, null, false, false, false, false, null, null, null, true, 
null, null, false);
+                Network.GuestType.Shared, false, null, false, null, true, 
false, null, true, null, false, false, false, false, false,null, null, null, 
true, null, null, false);
         long id = voffer.getId();
         _networkOfferingDao.update(id, voffer);
         return _networkOfferingDao.findById(id);
@@ -252,7 +252,7 @@ public class ContrailManagerImpl extends ManagerBase 
implements ContrailManager
         ConfigurationManager configMgr = (ConfigurationManager)_configService;
         NetworkOfferingVO voffer =
                 configMgr.createNetworkOffering(offeringName, 
offeringDisplayText, TrafficType.Guest, null, false, Availability.Optional, 
null, serviceProviderMap, true,
-                        Network.GuestType.Isolated, false, null, false, null, 
false, true, null, true, null, false, 
offeringName.equals(vpcRouterOfferingName), false, false, null,  null, null, 
true, null, null, false);
+                        Network.GuestType.Isolated, false, null, false, null, 
false, true, null, true, null, false, 
offeringName.equals(vpcRouterOfferingName), false, false, false,null,  null, 
null, true, null, null, false);
         if (offeringName.equals(vpcRouterOfferingName)) {
             voffer.setInternalLb(true);
         }
diff --git a/plugins/network-elements/netris/pom.xml 
b/plugins/network-elements/netris/pom.xml
index 21aeadec935..a50013ee351 100644
--- a/plugins/network-elements/netris/pom.xml
+++ b/plugins/network-elements/netris/pom.xml
@@ -26,7 +26,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.20.0.0-SNAPSHOT</version>
+        <version>4.20.0.0</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java
new file mode 100644
index 00000000000..5e0546a8256
--- /dev/null
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java
@@ -0,0 +1,149 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.agent.api;
+
+public class CreateOrUpdateNetrisNatCommand extends NetrisCommand {
+    private String vpcName;
+    private Long vpcId;
+    private String vpcCidr;
+    private String natRuleName;
+    private String natIp;
+    private String natRuleType;
+
+    // Parameters for DNAT
+    private String protocol;
+    private String sourceAddress;
+    private String sourcePort;
+    private String destinationAddress;
+    private String destinationPort;
+    private String state;
+
+    // Parameters for SNAT (Static NAT)
+    private String vmIp;
+
+
+    public CreateOrUpdateNetrisNatCommand(long zoneId, Long accountId, Long 
domainId, String vpcName, Long vpcId, String vNetName, Long networkId, boolean 
isVpc, String vpcCidr) {
+        super(zoneId, accountId, domainId, vNetName, networkId, isVpc);
+        this.vpcName = vpcName;
+        this.vpcId = vpcId;
+        this.vpcCidr = vpcCidr;
+    }
+
+    public String getVpcName() {
+        return vpcName;
+    }
+
+    public Long getVpcId() {
+        return vpcId;
+    }
+
+    public String getNatIp() {
+        return natIp;
+    }
+
+    public void setNatRuleName(String natRuleName) {
+        this.natRuleName = natRuleName;
+    }
+
+    public String getNatRuleName() {
+        return natRuleName;
+    }
+
+    public String getVpcCidr() {
+        return vpcCidr;
+    }
+
+    public void setNatIp(String natIp) {
+        this.natIp = natIp;
+    }
+
+    public String getVmIp() {
+        return vmIp;
+    }
+
+    public void setVmIp(String vmIp) {
+        this.vmIp = vmIp;
+    }
+
+    public String getNatRuleType() {
+        return natRuleType;
+    }
+
+    public void setNatRuleType(String natRuleType) {
+        this.natRuleType = natRuleType;
+    }
+
+    public void setVpcName(String vpcName) {
+        this.vpcName = vpcName;
+    }
+
+    public void setVpcId(Long vpcId) {
+        this.vpcId = vpcId;
+    }
+
+    public void setVpcCidr(String vpcCidr) {
+        this.vpcCidr = vpcCidr;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public String getSourceAddress() {
+        return sourceAddress;
+    }
+
+    public void setSourceAddress(String sourceAddress) {
+        this.sourceAddress = sourceAddress;
+    }
+
+    public String getSourcePort() {
+        return sourcePort;
+    }
+
+    public void setSourcePort(String sourcePort) {
+        this.sourcePort = sourcePort;
+    }
+
+    public String getDestinationAddress() {
+        return destinationAddress;
+    }
+
+    public void setDestinationAddress(String destinationAddress) {
+        this.destinationAddress = destinationAddress;
+    }
+
+    public String getDestinationPort() {
+        return destinationPort;
+    }
+
+    public void setDestinationPort(String destinationPort) {
+        this.destinationPort = destinationPort;
+    }
+
+    public String getState() {
+        return state;
+    }
+
+    public void setState(String state) {
+        this.state = state;
+    }
+}
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java
new file mode 100644
index 00000000000..b01b2f45192
--- /dev/null
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.agent.api;
+
+public class DeleteNetrisNatRuleCommand extends NetrisCommand {
+
+    private String vpcName;
+    private Long vpcId;
+    private String natRuleType;
+    private String natRuleName;
+    private String natIp;
+
+    public DeleteNetrisNatRuleCommand(long zoneId, Long accountId, Long 
domainId, String vpcName, Long vpcId, String vNetName, Long networkId, boolean 
isVpc) {
+        super(zoneId, accountId, domainId, vNetName, networkId, isVpc);
+        this.vpcName = vpcName;
+        this.vpcId = vpcId;
+    }
+
+    public String getVpcName() {
+        return vpcName;
+    }
+
+    public void setVpcName(String vpcName) {
+        this.vpcName = vpcName;
+    }
+
+    public Long getVpcId() {
+        return vpcId;
+    }
+
+    public void setVpcId(Long vpcId) {
+        this.vpcId = vpcId;
+    }
+
+    public String getNatRuleType() {
+        return natRuleType;
+    }
+
+    public void setNatRuleType(String natRuleType) {
+        this.natRuleType = natRuleType;
+    }
+
+    public String getNatRuleName() {
+        return natRuleName;
+    }
+
+    public void setNatRuleName(String natRuleName) {
+        this.natRuleName = natRuleName;
+    }
+
+    public String getNatIp() {
+        return natIp;
+    }
+
+    public void setNatIp(String natIp) {
+        this.natIp = natIp;
+    }
+}
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java
index 463001452c1..ceb33ea24ed 100644
--- 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java
@@ -22,11 +22,11 @@ public class NetrisCommand extends Command {
     private final long zoneId;
     private final Long accountId;
     private final Long domainId;
-    private final String name;
-    private final long id;
+    private String name;
+    private final Long id;
     private final boolean isVpc;
 
-    public NetrisCommand(long zoneId, Long accountId, Long domainId, String 
name, long id, boolean isVpc) {
+    public NetrisCommand(long zoneId, Long accountId, Long domainId, String 
name, Long id, boolean isVpc) {
         this.zoneId = zoneId;
         this.accountId = accountId;
         this.domainId = domainId;
@@ -40,7 +40,11 @@ public class NetrisCommand extends Command {
         return name;
     }
 
-    public long getId() {
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Long getId() {
         return id;
     }
 
diff --git 
a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisNetworkRule.java
similarity index 59%
copy from 
api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java
copy to 
plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisNetworkRule.java
index e99bc2fd416..2f4eadd443d 100644
--- 
a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisNetworkRule.java
@@ -14,21 +14,9 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-package com.cloud.network.element;
+package org.apache.cloudstack.resource;
 
-import java.util.List;
+import com.cloud.network.SDNProviderNetworkRule;
 
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.network.Network;
-import com.cloud.network.rules.PortForwardingRule;
-
-public interface PortForwardingServiceProvider extends NetworkElement, 
IpDeployingRequester {
-    /**
-     * Apply rules
-     * @param network
-     * @param rules
-     * @return
-     * @throws ResourceUnavailableException
-     */
-    boolean applyPFRules(Network network, List<PortForwardingRule> rules) 
throws ResourceUnavailableException;
+public class NetrisNetworkRule extends SDNProviderNetworkRule {
 }
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java
index dc922aef963..6f5e01b6392 100644
--- 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java
@@ -30,6 +30,8 @@ import com.cloud.resource.ServerResource;
 import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand;
 import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
+import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand;
+import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand;
 import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
 import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
 import org.apache.cloudstack.agent.api.NetrisAnswer;
@@ -97,6 +99,10 @@ public class NetrisResource implements ServerResource {
           return executeRequest((DeleteNetrisVnetCommand) cmd);
         } else if (cmd instanceof SetupNetrisPublicRangeCommand) {
             return executeRequest((SetupNetrisPublicRangeCommand) cmd);
+        } else if (cmd instanceof DeleteNetrisNatRuleCommand) {
+            return executeRequest((DeleteNetrisNatRuleCommand) cmd);
+        } else if (cmd instanceof CreateOrUpdateNetrisNatCommand) {
+          return executeRequest((CreateOrUpdateNetrisNatCommand) cmd);
         } else {
             return Answer.createUnsupportedCommandAnswer(cmd);
         }
@@ -261,6 +267,36 @@ public class NetrisResource implements ServerResource {
         return new NetrisAnswer(cmd, true, "OK");
     }
 
+    private Answer executeRequest(CreateOrUpdateNetrisNatCommand cmd) {
+        String natRuleType = cmd.getNatRuleType();
+        if ("SNAT".equals(natRuleType)) {
+            boolean result = netrisApiClient.createOrUpdateSNATRule(cmd);
+            if (!result) {
+                return new NetrisAnswer(cmd, false, String.format("Failed to 
create SNAT rule on Netris for network %s", cmd.getName()));
+            }
+        } else if ("DNAT".equals(natRuleType)) {
+            boolean result = netrisApiClient.createOrUpdateDNATRule(cmd);
+            if (!result) {
+                return new NetrisAnswer(cmd, false, String.format("Failed to 
create DNAT rule on Netris for network %s", cmd.getName()));
+            }
+        } else if ("STATICNAT".equals(natRuleType)) {
+            boolean result = netrisApiClient.createStaticNatRule(cmd);
+            if (!result) {
+                return new NetrisAnswer(cmd, false, String.format("Failed to 
create SNAT rule on Netris for network %s", cmd.getName()));
+            }
+        }
+
+        return new NetrisAnswer(cmd, true, "OK");
+    }
+
+    private Answer executeRequest(DeleteNetrisNatRuleCommand cmd) {
+        boolean result = netrisApiClient.deleteNatRule(cmd);
+        if (!result) {
+            return new NetrisAnswer(cmd, false, String.format("Netris NAT 
rule: %s deletion failed", cmd.getNatRuleName()));
+        }
+        return new NetrisAnswer(cmd, true, "OK");
+    }
+
     @Override
     public boolean start() {
         return true;
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java
index 5b19aa43199..fd6851696c8 100644
--- 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java
@@ -22,14 +22,14 @@ import org.apache.commons.lang3.ArrayUtils;
 public class NetrisResourceObjectUtils {
 
     public enum NetrisObjectType {
-        VPC, IPAM_ALLOCATION, IPAM_SUBNET, VNET
+        VPC, IPAM_ALLOCATION, IPAM_SUBNET, VNET, SNAT, STATICNAT, DNAT
     }
 
     public static String retrieveNetrisResourceObjectName(NetrisCommand cmd, 
NetrisObjectType netrisObjectType, String... suffixes) {
         long zoneId = cmd.getZoneId();
         Long accountId = cmd.getAccountId();
         Long domainId = cmd.getDomainId();
-        long objectId = cmd.getId();
+        Long objectId = cmd.getId();
         String objectName = cmd.getName();
         boolean isVpc = cmd.isVpc();
         boolean isZoneLevel = accountId == null && domainId == null;
@@ -60,6 +60,18 @@ public class NetrisResourceObjectUtils {
                     stringBuilder.append(String.format("-N%s", objectId));
                 }
                 break;
+            case SNAT:
+                stringBuilder.append(String.format("%s%s-%s", prefix, 
suffixes[0], "SNAT"));
+                suffixes = new String[0];
+                break;
+            case STATICNAT:
+                stringBuilder.append(String.format("%s%s-%s", prefix, 
suffixes[0], "STATICNAT"));
+                suffixes = new String[0];
+                break;
+            case DNAT:
+                stringBuilder.append(String.format("%s%s-%s", prefix, 
suffixes[0], "DNAT"));
+                suffixes = ArrayUtils.subarray(suffixes, 1, suffixes.length);
+                break;
             case VNET:
                break;
             default:
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java
index 0a00583df52..cf214bb4664 100644
--- 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java
@@ -22,6 +22,8 @@ import io.netris.model.VPCListing;
 import io.netris.model.response.TenantResponse;
 import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand;
 import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
+import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand;
+import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand;
 import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
 import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
 import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
@@ -48,8 +50,18 @@ public interface NetrisApiClient {
      */
     boolean deleteVpc(DeleteNetrisVpcCommand cmd);
 
+    /**
+     * Creation of a VPC network tier creates the following Netris resources:
+     * - Creates a Netris IPAM Subnet for the specified network tier's CIDR
+     * - Creates a Netris vNet
+     */
     boolean createVnet(CreateNetrisVnetCommand cmd);
 
+    /**
+     * Deletion of a VPC network tier deletes the following Netris resources:
+     * - Deletes the Netris IPAM Subnet for the specified network tier's CIDR
+     * - Deletes the Netris vNet
+     */
     boolean deleteVnet(DeleteNetrisVnetCommand cmd);
 
     /**
@@ -58,4 +70,8 @@ public interface NetrisApiClient {
      * - Check the IPAM subnet for NAT purpose for the range start-end. In 
case it doesn't exist, create it
      */
     boolean setupZoneLevelPublicRange(SetupNetrisPublicRangeCommand cmd);
+    boolean createOrUpdateSNATRule(CreateOrUpdateNetrisNatCommand cmd);
+    boolean createOrUpdateDNATRule(CreateOrUpdateNetrisNatCommand cmd);
+    boolean createStaticNatRule(CreateOrUpdateNetrisNatCommand cmd);
+    boolean deleteNatRule(DeleteNetrisNatRuleCommand cmd);
 }
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java
index 2bf9b172608..51de34552a5 100644
--- 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java
@@ -25,6 +25,7 @@ import io.netris.api.v1.AuthenticationApi;
 import io.netris.api.v1.SitesApi;
 import io.netris.api.v1.TenantsApi;
 import io.netris.api.v2.IpamApi;
+import io.netris.api.v2.NatApi;
 import io.netris.api.v2.VNetApi;
 import io.netris.api.v2.VpcApi;
 import io.netris.model.AllocationBody;
@@ -32,6 +33,8 @@ import io.netris.model.AllocationBodyVpc;
 import io.netris.model.FilterBySites;
 import io.netris.model.FilterByVpc;
 import io.netris.model.GetSiteBody;
+import io.netris.model.InlineResponse20015;
+import io.netris.model.InlineResponse20016;
 import io.netris.model.InlineResponse2004;
 import io.netris.model.InlineResponse2004Data;
 import io.netris.model.IpTree;
@@ -39,6 +42,12 @@ import io.netris.model.IpTreeAllocation;
 import io.netris.model.IpTreeAllocationTenant;
 import io.netris.model.IpTreeSubnet;
 import io.netris.model.IpTreeSubnetSites;
+import io.netris.model.NatBodySiteSite;
+import io.netris.model.NatBodyVpcVpc;
+import io.netris.model.NatGetBody;
+import io.netris.model.NatPostBody;
+import io.netris.model.NatPutBody;
+import io.netris.model.NatResponseGetOk;
 import io.netris.model.SitesResponseOK;
 import io.netris.model.SubnetBody;
 import io.netris.model.SubnetResBody;
@@ -62,13 +71,16 @@ import io.netris.model.VnetsBody;
 import io.netris.model.response.AuthResponse;
 import io.netris.model.response.TenantResponse;
 import io.netris.model.response.TenantsResponse;
+import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand;
 import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand;
 import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
+import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand;
 import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
 import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
 import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
 import org.apache.cloudstack.resource.NetrisResourceObjectUtils;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -245,8 +257,50 @@ public class NetrisApiClientImpl implements 
NetrisApiClient {
         return createdIpamAllocation != null;
     }
 
+    @Override
+    public boolean deleteNatRule(DeleteNetrisNatRuleCommand cmd) {
+        try {
+            String suffix = getNetrisVpcNameSuffix(cmd.getVpcId(), 
cmd.getVpcName(), cmd.getId(), cmd.getName(), cmd.isVpc());
+            String vpcName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix);
+            VPCListing vpcResource = getVpcByNameAndTenant(vpcName);
+            if (vpcResource == null) {
+                logger.error("Could not find the Netris VPC resource with name 
{} and tenant ID {}", vpcName, tenantId);
+                return false;
+            }
+            String natRuleName = cmd.getNatRuleName();
+            NatGetBody existingNatRule = netrisNatRuleExists(natRuleName);
+            boolean ruleExists = Objects.nonNull(existingNatRule);
+            if (ruleExists) {
+                deleteNatRule(natRuleName, existingNatRule.getId(), 
vpcResource.getName());
+                if (cmd.getNatRuleType().equals("STATICNAT")) {
+                    deleteNatSubnet(vpcResource.getId(), cmd.getNatIp());
+                }
+            }
+        } catch (Exception e) {
+            throw new CloudRuntimeException("Error deleting Netris NAT Rule", 
e);
+        }
+        return true;
+    }
+
+    private void deleteNatSubnet(Integer netrisVpcId, String natIp) {
+        FilterByVpc vpcFilter = new FilterByVpc();
+        vpcFilter.add(netrisVpcId);
+        String netrisSubnetName = natIp + "/32";
+        deleteSubnetInternal(vpcFilter, null, netrisSubnetName);
+    }
+
+    public void deleteNatRule(String natRuleName, Integer snatRuleId, String 
netrisVpcName) {
+        logger.debug("Deleting NAT rule on Netris: {} for VPC {}", 
natRuleName, netrisVpcName);
+        try {
+            NatApi natApi = apiClient.getApiStubForMethod(NatApi.class);
+            natApi.apiV2NatIdDelete(snatRuleId);
+        } catch (ApiException e) {
+            logAndThrowException(String.format("Failed to delete NAT rule: %s 
for VPC: %s", natRuleName, netrisVpcName), e);
+        }
+    }
+
     private void deleteVpcIpamAllocationInternal(VPCListing vpcResource, 
String vpcCidr) {
-        logger.debug(String.format("Deleting Netris VPC IPAM Allocation %s for 
VPC %s", vpcCidr, vpcResource.getName()));
+        logger.debug("Deleting Netris VPC IPAM Allocation {} for VPC {}", 
vpcCidr, vpcResource.getName());
         try {
             VpcApi vpcApi = apiClient.getApiStubForMethod(VpcApi.class);
             VPCResponseResourceOK vpcResourcesResponse = 
vpcApi.apiV2VpcVpcIdResourcesGet(vpcResource.getId());
@@ -300,12 +354,20 @@ public class NetrisApiClientImpl implements 
NetrisApiClient {
 
     @Override
     public boolean deleteVpc(DeleteNetrisVpcCommand cmd) {
+        String suffix = String.valueOf(cmd.getId());
         String vpcName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.VPC);
         VPCListing vpcResource = getVpcByNameAndTenant(vpcName);
         if (vpcResource == null) {
-            logger.error(String.format("Could not find the Netris VPC resource 
with name %s and tenant ID %s", vpcName, tenantId));
+            logger.error("Could not find the Netris VPC resource with name {} 
and tenant ID {}", vpcName, tenantId);
             return false;
         }
+        String snatRuleName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.SNAT, suffix);
+        NatGetBody existingNatRule = netrisNatRuleExists(snatRuleName);
+        boolean ruleExists = Objects.nonNull(existingNatRule);
+        if (ruleExists) {
+            deleteNatRule(snatRuleName, existingNatRule.getId(), 
vpcResource.getName());
+        }
+
         String vpcCidr = cmd.getCidr();
         deleteVpcIpamAllocationInternal(vpcResource, vpcCidr);
         VPCResponseObjectOK response = deleteVpcInternal(vpcResource);
@@ -424,7 +486,9 @@ public class NetrisApiClientImpl implements NetrisApiClient 
{
         filterByVpc.add(vpc.getId());
         SubnetResBody subnetResBody = ipamApi.apiV2IpamSubnetsGet(filterByVpc);
         List<IpTreeSubnet> exactSubnetList = subnetResBody.getData().stream()
-                .filter(x -> x.getAllocationID().equals(ipamAllocationId) && 
x.getPrefix().equals(exactCidr) && x.getPurpose() == purpose)
+                .filter(x -> ipamAllocationId != null ?
+                        x.getAllocationID().equals(ipamAllocationId) && 
x.getPrefix().equals(exactCidr) && x.getPurpose() == purpose :
+                        x.getPrefix().equals(exactCidr) && x.getPurpose() == 
purpose)
                 .collect(Collectors.toList());
         return CollectionUtils.isEmpty(exactSubnetList) ? null : 
exactSubnetList.get(0);
     }
@@ -460,6 +524,288 @@ public class NetrisApiClientImpl implements 
NetrisApiClient {
         return true;
     }
 
+    private boolean 
createOrUpdateNatRuleInternal(CreateOrUpdateNetrisNatCommand cmd) {
+        String ruleName = cmd.getNatRuleName();
+        long vpcId = cmd.getVpcId();
+        Long networkId = cmd.getId();
+        String networkName = cmd.getName();
+        String vpcName = cmd.getVpcName();
+        String vpcCidr = cmd.getVpcCidr();
+        boolean isVpc = cmd.isVpc();
+        NatPostBody.ActionEnum action = 
getNatActionFromRuleType(cmd.getNatRuleType());
+        NatPostBody.ProtocolEnum protocol = 
getProtocolFromString(cmd.getProtocol());
+        NatPostBody.StateEnum state = getStateFromString(cmd.getState());
+
+        String vNetName = isVpc ?
+                String.format("V%s-N%s-%s", vpcId, networkId, networkName) :
+                String.format("N%s-%s", networkId, networkName);
+        String vpcSuffix = getNetrisVpcNameSuffix(vpcId, vpcName, networkId, 
networkName, isVpc);
+        String netrisVpcName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.VPC, vpcSuffix);
+        VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName);
+        if (vpcResource == null) {
+            logger.error("Could not find the Netris VPC resource with name {} 
and tenant ID {}", netrisVpcName, tenantId);
+            return false;
+        }
+
+        String targetIpSubnet = null;
+        if (NatPostBody.ActionEnum.SNAT == action) {
+            targetIpSubnet = cmd.getNatIp() + "/32";
+        } else if (NatPostBody.ActionEnum.DNAT == action) {
+            targetIpSubnet = cmd.getDestinationAddress() + "/32";
+        }
+
+        if (StringUtils.isNotBlank(targetIpSubnet) && 
existsDestinationSubnet(targetIpSubnet)) {
+            logger.debug(String.format("Creating subnet with NAT purpose for 
%s", targetIpSubnet));
+            createNatSubnet(targetIpSubnet, vpcResource.getId());
+        }
+
+        NatGetBody existingNatRule = netrisNatRuleExists(ruleName);
+        boolean ruleExists = Objects.nonNull(existingNatRule);
+        if (!ruleExists) {
+            String destinationAddress = action == NatPostBody.ActionEnum.SNAT 
? "0.0.0.0/0" : cmd.getDestinationAddress() + "/32";
+            String destinationPort = cmd.getDestinationPort();
+            String sourceAddress = action == NatPostBody.ActionEnum.SNAT ? 
vpcCidr : "0.0.0.0/0";
+            String sourcePort = "1-65535";
+            String snatToIp = action == NatPostBody.ActionEnum.SNAT ? 
targetIpSubnet : null;
+            String dnatToIp = action == NatPostBody.ActionEnum.DNAT ? 
cmd.getSourceAddress() + "/32" : null;
+            String dnatToPort = action == NatPostBody.ActionEnum.DNAT ? 
cmd.getSourcePort() : null;
+            return createNatRuleInternal(ruleName, action, protocol, state, 
destinationAddress, destinationPort,
+                    sourceAddress, sourcePort, snatToIp, dnatToIp, dnatToPort, 
netrisVpcName, networkName, vNetName);
+        } else if (NatPostBody.ActionEnum.SNAT == action) {
+            return updateSnatRuleInternal(ruleName, targetIpSubnet, 
netrisVpcName, networkName, vNetName, existingNatRule.getId(), vpcCidr);
+        }
+        return true;
+    }
+
+    private NatPostBody.StateEnum getStateFromString(String state) {
+        return NatPostBody.StateEnum.fromValue(state);
+    }
+
+    private NatPostBody.ActionEnum getNatActionFromRuleType(String 
natRuleType) {
+        return NatPostBody.ActionEnum.fromValue(natRuleType);
+    }
+
+    @Override
+    public boolean createOrUpdateSNATRule(CreateOrUpdateNetrisNatCommand cmd) {
+        return createOrUpdateNatRuleInternal(cmd);
+    }
+
+    private boolean existsDestinationSubnet(String destinationSubnet) {
+        try {
+            FilterByVpc vpcFilter = new FilterByVpc();
+            vpcFilter.add(getSystemVpc().getId());
+            List<IpTreeSubnet> targetSubnetList = getSubnet(vpcFilter, 
destinationSubnet);
+            return targetSubnetList != null;
+        } catch (ApiException e) {
+            logAndThrowException(String.format("Error checking if subnet %s 
exists: %s", destinationSubnet, e.getMessage()), e);
+            return false;
+        }
+    }
+
+    @Override
+    public boolean createStaticNatRule(CreateOrUpdateNetrisNatCommand cmd) {
+        String staticNatRuleName = cmd.getNatRuleName();
+        String natIP = cmd.getNatIp() + "/32";
+        String vmIp = cmd.getVmIp() + "/32";
+        String vpcName = cmd.getVpcName();
+        String vpcCidr = cmd.getVpcCidr();
+        Long vpcId = cmd.getVpcId();
+        Long networkId = cmd.getId();
+        String networkName = cmd.getName();
+        boolean isVpc = cmd.isVpc();
+
+        try {
+            String vpcSuffix = getNetrisVpcNameSuffix(vpcId, vpcName, 
networkId, networkName, isVpc);
+            String netrisVpcName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.VPC, vpcSuffix);
+            VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName);
+            if (vpcResource == null) {
+                logger.error("Could not find the Netris VPC resource with name 
{} and tenant ID {}", netrisVpcName, tenantId);
+                return false;
+            }
+            // Create a /32 subnet for the DNAT IP
+            createNatSubnet(natIP, vpcResource.getId());
+            NatApi natApi = apiClient.getApiStubForMethod(NatApi.class);
+            NatPostBody natBody = new NatPostBody();
+            natBody.setAction(NatPostBody.ActionEnum.DNAT);
+            natBody.setDestinationAddress(natIP);
+            natBody.setName(staticNatRuleName);
+            natBody.setProtocol(NatPostBody.ProtocolEnum.ALL);
+            natBody.setState(NatPostBody.StateEnum.ENABLED);
+            natBody.setComment(String.format("Static NAT rule for %s", 
netrisVpcName));
+
+            NatBodySiteSite site = new NatBodySiteSite();
+            site.setId(siteId);
+            site.setName(siteName);
+            natBody.setSite(site);
+            natBody.setSourceAddress("0.0.0.0/0");
+            natBody.setDnatToIP(vmIp);
+
+            NatBodyVpcVpc vpc = new NatBodyVpcVpc();
+            vpc.setId(vpcResource.getId());
+            vpc.setName(vpcResource.getName());
+            natBody.setVpc(vpc);
+
+            InlineResponse20015 natResponse = natApi.apiV2NatPost(natBody);
+            if (natResponse == null || !natResponse.isIsSuccess()) {
+                String reason = natResponse == null ? "Empty response" : 
"Operation failed on Netris";
+                logger.debug("The Netris static NAT (DNAT) rule creation 
failed for netris VPC - {}: {}", netrisVpcName, reason);
+                throw new CloudRuntimeException(reason);
+            }
+        } catch (ApiException e) {
+            logAndThrowException(String.format("Failed to create Static NAT 
(DNAT) rule for network : %s", Objects.nonNull(vpcName) ? vpcName : 
networkName), e);
+        }
+        return true;
+    }
+
+    private void createNatSubnet(String natIp, Integer netrisVpcId) {
+        try {
+            FilterByVpc vpcFilter = new FilterByVpc();
+            vpcFilter.add(netrisVpcId);
+            String netrisSubnetName = natIp;
+            List<IpTreeSubnet> matchedSubnets = getSubnet(vpcFilter, 
netrisSubnetName);
+            if (matchedSubnets.isEmpty()) {
+                VPCListing systemVpc = getSystemVpc();
+                createIpamSubnetInternal(natIp, natIp, 
SubnetBody.PurposeEnum.NAT, systemVpc);
+                return;
+            }
+            logger.debug("NAT subnet: {} already exists", natIp);
+        } catch (ApiException e) {
+            throw new CloudRuntimeException(String.format("Failed to create 
subnet for %s with NAT purpose", natIp));
+        }
+    }
+
+    private NatPostBody.ProtocolEnum getProtocolFromString(String protocol) {
+        return NatPostBody.ProtocolEnum.fromValue(protocol);
+    }
+
+    private NatPostBody createNatRulePostBody(String ruleName, 
NatPostBody.ActionEnum action, NatPostBody.ProtocolEnum protocol, 
NatPostBody.StateEnum state,
+                                              String destinationAddress, 
String destinationPort,
+                                              String sourceAddress, String 
sourcePort,
+                                              String dnatToIp, String 
dnatToPort,
+                                              String netrisVpcName, String 
snatIP, String comment) {
+        NatPostBody natBody = new NatPostBody();
+        natBody.setAction(action);
+        natBody.setName(ruleName);
+        natBody.setProtocol(protocol);
+        natBody.setState(state);
+        if (StringUtils.isNotBlank(comment)) {
+            natBody.setComment(comment);
+        }
+
+        natBody.setDestinationAddress(destinationAddress);
+        if (StringUtils.isNotBlank(destinationPort)) {
+            natBody.setDestinationPort(destinationPort);
+        }
+
+        if (StringUtils.isNotBlank(sourceAddress)) {
+            natBody.setSourceAddress(sourceAddress);
+        }
+        if (StringUtils.isNotBlank(sourcePort)) {
+            natBody.setSourcePort(sourcePort);
+        }
+
+        NatBodySiteSite site = new NatBodySiteSite();
+        site.setId(siteId);
+        site.setName(siteName);
+        natBody.setSite(site);
+
+        if (StringUtils.isNotBlank(snatIP)) {
+            natBody.setSourceAddress(snatIP);
+            natBody.setSnatToIP(snatIP);
+        }
+
+        if (StringUtils.isNotBlank(dnatToIp)) {
+            natBody.setDnatToIP(dnatToIp);
+        }
+        if (StringUtils.isNotBlank(dnatToPort)) {
+            natBody.setDnatToPort(Integer.valueOf(dnatToPort));
+        }
+
+        NatBodyVpcVpc vpc = new NatBodyVpcVpc();
+        VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName);
+        if (vpcResource == null) {
+            logger.error("Could not find the Netris VPC resource with name {} 
and tenant ID {}", netrisVpcName, tenantId);
+            return null;
+        }
+        vpc.setId(vpcResource.getId());
+        vpc.setName(vpcResource.getName());
+        natBody.setVpc(vpc);
+        return natBody;
+    }
+
+    @Override
+    public boolean createOrUpdateDNATRule(CreateOrUpdateNetrisNatCommand cmd) {
+        return createOrUpdateNatRuleInternal(cmd);
+    }
+
+    private boolean createNatRuleInternal(String ruleName, 
NatPostBody.ActionEnum action, NatPostBody.ProtocolEnum protocol, 
NatPostBody.StateEnum state,
+                                          String destinationAddress, String 
destinationPort, String sourceAddress, String sourcePort,
+                                          String sNatToIp, String dNatToIp, 
String dNatToPort,
+                                          String netrisVpcName, String 
networkName, String vNetName) {
+        try {
+            NatApi natApi = apiClient.getApiStubForMethod(NatApi.class);
+            String comment = String.format("NAT rule for %s with action %s", 
netrisVpcName, action.name());
+            NatPostBody natBody = createNatRulePostBody(ruleName, action, 
protocol, state,
+                    destinationAddress, destinationPort, sourceAddress, 
sourcePort,
+                    dNatToIp, dNatToPort, netrisVpcName, sNatToIp, comment);
+            if (natBody == null) {
+                return false;
+            }
+            InlineResponse20015 natResponse = natApi.apiV2NatPost(natBody);
+            if (natResponse == null || !natResponse.isIsSuccess()) {
+                String reason = natResponse == null ? "Empty response" : 
"Operation failed on Netris";
+                logger.debug("The Netris NAT rule {} creation failed for 
network(vNet) - {}({}): {}", action.name(), networkName, vNetName, reason);
+                throw new CloudRuntimeException(reason);
+            }
+        } catch (ApiException e) {
+            logAndThrowException(String.format("Failed to create NAT rule %s 
for network(vNet): %s(%s)", action.name(), networkName, vNetName), e);
+        }
+        return true;
+    }
+
+    private void updateNatRequest(NatPostBody natBody) {
+
+    }
+
+    private boolean updateSnatRuleInternal(String snatRuleName, String snatIP, 
String netrisVpcName, String networkName,
+                                           String vNetName, Integer 
netisSnatId, String vpcCidr) {
+        try {
+            NatApi natApi = apiClient.getApiStubForMethod(NatApi.class);
+            NatPutBody natBody = new NatPutBody();
+            natBody.setAction(NatPutBody.ActionEnum.SNAT);
+            natBody.setDestinationAddress("0.0.0.0/0");
+            natBody.setName(snatRuleName);
+            natBody.setProtocol(NatPutBody.ProtocolEnum.ALL);
+
+            NatBodySiteSite site = new NatBodySiteSite();
+            site.setId(siteId);
+            site.setName(siteName);
+            natBody.setSite(site);
+            natBody.setSourceAddress(vpcCidr);
+            natBody.setSnatToIP(snatIP);
+
+            NatBodyVpcVpc vpc = new NatBodyVpcVpc();
+            VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName);
+            if (vpcResource == null) {
+                logger.error("Could not find the Netris VPC resource with name 
{} and tenant ID {}", netrisVpcName, tenantId);
+                return false;
+            }
+            vpc.setId(vpcResource.getId());
+            vpc.setName(vpcResource.getName());
+            natBody.setVpc(vpc);
+
+            InlineResponse20016 natUpdateResponse = 
natApi.apiV2NatIdPut(natBody, netisSnatId);
+            if (natUpdateResponse == null || !natUpdateResponse.isIsSuccess()) 
{
+                String reason = natUpdateResponse == null ? "Empty response" : 
"Operation failed on Netris";
+                logger.debug("Update of Netris SNAT rule failed for 
network(vNet) - {}({}): {}", networkName, vNetName, reason);
+                throw new CloudRuntimeException(reason);
+            }
+        } catch (ApiException e) {
+            logAndThrowException(String.format("Failed to create SNAT rule for 
network(vNet): %s(%s)", networkName, vNetName), e);
+        }
+        return true;
+    }
+
     private void deleteVnetInternal(VPCListing associatedVpc, FilterBySites 
siteFilter, FilterByVpc vpcFilter, String netrisVnetName, String vNetName) {
         try {
             VNetApi vNetApi = apiClient.getApiStubForMethod(VNetApi.class);
@@ -483,21 +829,35 @@ public class NetrisApiClientImpl implements 
NetrisApiClient {
         }
     }
 
-    private void deleteSubnetInternal(FilterByVpc vpcFilter, String 
netrisVnetName, String netrisSubnetName) {
+    private List<IpTreeSubnet> getSubnet(FilterByVpc vpcFilter, String 
netrisSubnetName) {
         try {
-            logger.debug("Deleting Netris VPC IPAM Subnet {} for vNet: {}", 
netrisSubnetName, netrisVnetName);
             IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
             SubnetResBody subnetsResponse = 
ipamApi.apiV2IpamSubnetsGet(vpcFilter);
             List<IpTreeSubnet> subnets = subnetsResponse.getData();
-            List<IpTreeSubnet> matchedSubnets = subnets.stream().filter(subnet 
-> subnet.getName().equals(netrisSubnetName)).collect(Collectors.toList());
+            return subnets.stream().filter(subnet -> 
subnet.getName().equals(netrisSubnetName)).collect(Collectors.toList());
+        } catch (ApiException e) {
+            logAndThrowException(String.format("Failed to get IPAM subnet: 
%s", netrisSubnetName), e);
+        }
+        return new ArrayList<>();
+    }
+
+    private void deleteSubnetInternal(FilterByVpc vpcFilter, String 
netrisVnetName, String netrisSubnetName) {
+        try {
+            String logString = "";
+            if (Objects.nonNull(netrisVnetName)) {
+                logString = String.format("for vNet: %s ", netrisVnetName);
+            }
+            logger.debug("Deleting Netris VPC IPAM Subnet {} {}", 
netrisSubnetName, logString);
+            IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
+            List<IpTreeSubnet> matchedSubnets = getSubnet(vpcFilter, 
netrisSubnetName);
             if (CollectionUtils.isEmpty(matchedSubnets)) {
-                logger.debug("IPAM subnet: {} for the given vNet: {} appears 
to already be deleted on Netris", netrisSubnetName, netrisVnetName);
+                logger.debug("IPAM subnet: {} {} appears to already be deleted 
on Netris", netrisSubnetName, logString);
                 return;
             }
 
             ipamApi.apiV2IpamTypeIdDelete("subnet", 
matchedSubnets.get(0).getId().intValue());
         } catch (ApiException e) {
-            logAndThrowException(String.format("Failed to delete vNet: %s", 
netrisVnetName), e);
+            logAndThrowException(String.format("Failed to delete subnet: %s", 
netrisSubnetName), e);
         }
     }
 
@@ -607,4 +967,23 @@ public class NetrisApiClientImpl implements 
NetrisApiClient {
         }
         return suffix;
     }
+
+    private NatGetBody netrisNatRuleExists(String netrisNatRule) {
+        try {
+            NatApi natApi = apiClient.getApiStubForMethod(NatApi.class);
+            //NatResponseGetOk response = natApi.apiV2NatGet(null, 
Arrays.asList(new BigDecimal(vpcId)));
+            NatResponseGetOk response = natApi.apiV2NatGet(null, null);
+            if (Objects.isNull(response) || !response.isIsSuccess()) {
+                throw new CloudRuntimeException("Failed to list Netris NAT 
rules");
+            }
+            List<NatGetBody> data = response.getData().stream().filter(natData 
-> natData.getName().equals(netrisNatRule)).collect(Collectors.toList());
+            if (data.isEmpty()) {
+                return null;
+            }
+            return data.get(0);
+
+        } catch (ApiException e) {
+            throw new CloudRuntimeException("Failed to list Netris NAT rules");
+        }
+    }
 }
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java
index 9a29a410862..eb74e6f7080 100644
--- 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java
@@ -23,6 +23,7 @@ import com.cloud.agent.api.AgentControlCommand;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.StartupCommand;
+import com.cloud.api.ApiDBUtils;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.deploy.DeployDestination;
@@ -39,15 +40,25 @@ import com.cloud.network.IpAddress;
 import com.cloud.network.Network;
 import com.cloud.network.NetworkModel;
 import com.cloud.network.PhysicalNetworkServiceProvider;
+import com.cloud.network.PublicIpAddress;
+import com.cloud.network.SDNProviderOpObject;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.element.DhcpServiceProvider;
 import com.cloud.network.element.DnsServiceProvider;
+import com.cloud.network.element.IpDeployer;
 import com.cloud.network.element.NetworkACLServiceProvider;
+import com.cloud.network.element.PortForwardingServiceProvider;
+import com.cloud.network.element.StaticNatServiceProvider;
 import com.cloud.network.element.VirtualRouterElement;
 import com.cloud.network.element.VpcProvider;
 import com.cloud.network.netris.NetrisService;
+import com.cloud.network.rules.FirewallRule;
 import com.cloud.network.rules.LoadBalancerContainer;
+import com.cloud.network.rules.PortForwardingRule;
+import com.cloud.network.rules.StaticNat;
 import com.cloud.network.vpc.NetworkACLItem;
 import com.cloud.network.vpc.PrivateGateway;
 import com.cloud.network.vpc.StaticRouteProfile;
@@ -61,27 +72,39 @@ import com.cloud.resource.ServerResource;
 import com.cloud.resource.UnableDeleteHostException;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.Pair;
 import com.cloud.utils.component.AdapterBase;
+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;
+import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.VMInstanceDao;
 import org.apache.cloudstack.StartupNetrisCommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.resource.NetrisNetworkRule;
+import org.apache.cloudstack.resourcedetail.FirewallRuleDetailVO;
+import org.apache.cloudstack.resourcedetail.dao.FirewallRuleDetailsDao;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.springframework.stereotype.Component;
 
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
 @Component
 public class NetrisElement extends AdapterBase implements DhcpServiceProvider, 
DnsServiceProvider, VpcProvider,
-        NetworkACLServiceProvider, ResourceStateAdapter, Listener {
+        StaticNatServiceProvider, IpDeployer, PortForwardingServiceProvider, 
NetworkACLServiceProvider, ResourceStateAdapter, Listener {
 
     @Inject
     NetworkModel networkModel;
@@ -101,6 +124,12 @@ public class NetrisElement extends AdapterBase implements 
DhcpServiceProvider, D
     private DomainDao domainDao;
     @Inject
     private VpcDao vpcDao;
+    @Inject
+    private FirewallRuleDetailsDao firewallRuleDetailsDao;
+    @Inject
+    private IPAddressDao ipAddressDao;
+    @Inject
+    private VMInstanceDao vmInstanceDao;
 
     protected Logger logger = LogManager.getLogger(getClass());
 
@@ -257,6 +286,11 @@ public class NetrisElement extends AdapterBase implements 
DhcpServiceProvider, D
         return capabilities;
     }
 
+    @Override
+    public boolean applyIps(Network network, List<? extends PublicIpAddress> 
ipAddress, Set<Network.Service> services) throws ResourceUnavailableException {
+        return true;
+    }
+
     @Override
     public Network.Provider getProvider() {
         return Network.Provider.Netris;
@@ -398,4 +432,164 @@ public class NetrisElement extends AdapterBase implements 
DhcpServiceProvider, D
     public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, 
List<? extends NetworkACLItem> networkACLItems) {
         return false;
     }
+
+    @Override
+    public IpDeployer getIpDeployer(Network network) {
+        return this;
+    }
+
+    @Override
+    public boolean applyPFRules(Network network, List<PortForwardingRule> 
rules) throws ResourceUnavailableException {
+        if (!canHandle(network, Network.Service.PortForwarding)) {
+            return false;
+        }
+        return applyPFRulesInternal(network, rules);
+    }
+
+    private boolean addOrRemovePFRuleOnNetris(UserVm vm, PortForwardingRule 
rule, NetrisNetworkRule networkRule, SDNProviderOpObject netrisObject, boolean 
create) {
+        logger.debug("{} port forwarding rule on Netris for VM {} to ports {} 
- {}",
+                create ? "Creating" : "Deleting", vm.getUuid(), 
rule.getDestinationPortStart(), rule.getDestinationPortEnd());
+        Long vpcId = netrisObject.getVpcVO() != null ? 
netrisObject.getVpcVO().getId() : null;
+        String vpcName = netrisObject.getVpcVO() != null ? 
netrisObject.getVpcVO().getName() : null;
+        Long networkId = netrisObject.getNetworkVO() != null ? 
netrisObject.getNetworkVO().getId() : null;
+        String networkName = netrisObject.getNetworkVO() != null ? 
netrisObject.getNetworkVO().getName() : null;
+        String vpcCidr = netrisObject.getVpcVO() != null ? 
netrisObject.getVpcVO().getCidr() : null;
+
+        return create ?
+                
netrisService.createPortForwardingRule(networkRule.getZoneId(), 
networkRule.getAccountId(), networkRule.getDomainId(),
+                        vpcName, vpcId, networkName, networkId, 
netrisObject.isVpcResource(), vpcCidr, networkRule) :
+                
netrisService.deletePortForwardingRule(networkRule.getZoneId(), 
networkRule.getAccountId(), networkRule.getDomainId(),
+                        vpcName, vpcId, networkName, networkId, 
netrisObject.isVpcResource(), vpcCidr, networkRule);
+    }
+
+    private 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;
+                }
+                SDNProviderOpObject netrisObject = getNetrisOpObject(network);
+                String publicPort = 
PortForwardingServiceProvider.getPublicPortRange(rule);
+                String privatePort = 
PortForwardingServiceProvider.getPrivatePFPortRange(rule);
+                FirewallRuleDetailVO ruleDetail = 
firewallRuleDetailsDao.findDetail(rule.getId(), ApiConstants.NETRIS_DETAIL_KEY);
+
+                NetrisNetworkRule networkRule = new NetrisNetworkRule();
+                networkRule.setDomainId(netrisObject.getDomainId());
+                networkRule.setAccountId(netrisObject.getAccountId());
+                networkRule.setZoneId(netrisObject.getZoneId());
+                
networkRule.setNetworkResourceId(netrisObject.getNetworkResourceId());
+                
networkRule.setNetworkResourceName(netrisObject.getNetworkResourceName());
+                networkRule.setVpcResource(netrisObject.isVpcResource());
+                networkRule.setVmId(Objects.nonNull(vm) ? vm.getId() : 0);
+                networkRule.setVmIp(Objects.nonNull(vm) ? 
vm.getPrivateIpAddress() : null);
+                networkRule.setPublicIp(publicIp.getAddress().addr());
+                networkRule.setPrivatePort(privatePort);
+                networkRule.setPublicPort(publicPort);
+                networkRule.setRuleId(rule.getId());
+                
networkRule.setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT));
+
+                if (Arrays.asList(FirewallRule.State.Add, 
FirewallRule.State.Active).contains(rule.getState())) {
+                    boolean pfRuleResult = addOrRemovePFRuleOnNetris(vm, rule, 
networkRule, netrisObject, true);
+                    if (pfRuleResult) {
+                        logger.debug("Port forwarding rule {} created on 
Netris, 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.NETRIS_DETAIL_KEY, "true", false);
+                        } else if (ruleDetail != null) {
+                            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) {
+                    boolean pfRuleResult = addOrRemovePFRuleOnNetris(vm, rule, 
networkRule, netrisObject, false);
+                    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;
+        });
+    }
+
+    private SDNProviderOpObject getNetrisOpObject(Network network) {
+        Pair<VpcVO, NetworkVO> vpcOrNetwork = 
getVpcOrNetwork(network.getVpcId(), network.getId());
+        VpcVO vpc = vpcOrNetwork.first();
+        NetworkVO networkVO = vpcOrNetwork.second();
+        long domainId = getResourceId("domain", vpc, networkVO);
+        long accountId = getResourceId("account", vpc, networkVO);
+        long zoneId = getResourceId("zone", vpc, networkVO);
+
+        return new SDNProviderOpObject.Builder()
+                .vpcVO(vpc)
+                .networkVO(networkVO)
+                .domainId(domainId)
+                .accountId(accountId)
+                .zoneId(zoneId)
+                .build();
+    }
+
+    public boolean applyStaticNats(Network config, List<? extends StaticNat> 
rules) throws ResourceUnavailableException {
+        for(StaticNat staticNat : rules) {
+            long sourceIpAddressId = staticNat.getSourceIpAddressId();
+            IPAddressVO ipAddressVO = 
ipAddressDao.findByIdIncludingRemoved(sourceIpAddressId);
+            VMInstanceVO vm = 
vmInstanceDao.findByIdIncludingRemoved(ipAddressVO.getAssociatedWithVmId());
+            // floating ip is released when nic was deleted
+            if (vm == null || 
networkModel.getNicInNetworkIncludingRemoved(vm.getId(), config.getId()) == 
null) {
+                continue;
+            }
+            Pair<VpcVO, NetworkVO> vpcOrNetwork = 
getVpcOrNetwork(config.getVpcId(), config.getId());
+            VpcVO vpc = vpcOrNetwork.first();
+            NetworkVO network = vpcOrNetwork.second();
+            Long networkResourceId = Objects.nonNull(vpc) ? vpc.getId() : 
network.getId();
+            String networkResourceName = Objects.nonNull(vpc) ? vpc.getName() 
: network.getName();
+            boolean isVpcResource = Objects.nonNull(vpc);
+            if (!staticNat.isForRevoke()) {
+                return 
netrisService.createStaticNatRule(config.getDataCenterId(), 
config.getAccountId(), config.getDomainId(),
+                       networkResourceName, networkResourceId, isVpcResource, 
vpc.getCidr(),
+                        ipAddressVO.getAddress().addr(), 
staticNat.getDestIpAddress());
+            } else {
+                return 
netrisService.deleteStaticNatRule(config.getDataCenterId(), 
config.getAccountId(), config.getDomainId(),
+                        networkResourceName, networkResourceId, isVpcResource, 
ipAddressVO.getAddress().addr());
+            }
+        }
+        return false;
+    }
+
+    public Pair<VpcVO, NetworkVO> getVpcOrNetwork(Long vpcId, long networkId) {
+        VpcVO vpc = null;
+        NetworkVO network = null;
+        if (Objects.nonNull(vpcId)) {
+            vpc = vpcDao.findById(vpcId);
+            if (Objects.isNull(vpc)) {
+                throw new CloudRuntimeException(String.format("Failed to find 
VPC with id: %s", vpcId));
+            }
+        } else {
+            network = networkDao.findById(networkId);
+            if (Objects.isNull(network)) {
+                throw new CloudRuntimeException(String.format("Failed to find 
network with id: %s", networkId));
+            }
+        }
+        return new Pair<>(vpc, network);
+    }
+
+    private long getResourceId(String resource, VpcVO vpc, NetworkVO network) {
+        switch (resource) {
+            case "domain":
+                return Objects.nonNull(vpc) ? vpc.getDomainId() : 
network.getDomainId();
+            case "account":
+                return Objects.nonNull(vpc) ? vpc.getAccountId() : 
network.getAccountId();
+            case "zone":
+                return Objects.nonNull(vpc) ? vpc.getZoneId() : 
network.getDataCenterId();
+            default:
+                return 0;
+        }
+    }
 }
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java
index 2a4891eb28c..8fa07f17d40 100644
--- 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java
@@ -28,8 +28,10 @@ import 
com.cloud.exception.InsufficientVirtualNetworkCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.network.Network;
 import com.cloud.network.NetworkMigrationResponder;
+import com.cloud.network.NetworkModel;
 import com.cloud.network.Networks;
 import com.cloud.network.PhysicalNetwork;
+import com.cloud.network.PublicIpAddress;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.dao.PhysicalNetworkVO;
 import com.cloud.network.guru.GuestNetworkGuru;
@@ -57,6 +59,8 @@ public class NetrisGuestNetworkGuru  extends GuestNetworkGuru 
implements Network
 
     @Inject
     private NetrisService netrisService;
+    @Inject
+    NetworkModel networkModel;
 
     public NetrisGuestNetworkGuru() {
         super();
@@ -236,6 +240,18 @@ public class NetrisGuestNetworkGuru  extends 
GuestNetworkGuru implements Network
 
         if (isNull(network.getVpcId()) && 
networkOfferingVO.getNetworkMode().equals(NetworkOffering.NetworkMode.NATTED)) {
             // Netris Natted mode
+            long domainId = domain.getId();
+            long accountId = account.getId();
+            long dataCenterId = zone.getId();
+            long resourceId = network.getId();
+            PublicIpAddress ipAddress = 
networkModel.getSourceNatIpAddressForGuestNetwork(account, network);
+            String snatIP = ipAddress.getAddress().addr();
+            boolean result = netrisService.createSnatRule(dataCenterId, 
accountId, domainId, vpc.getName(), vpc.getId(), network.getName(), resourceId, 
nonNull(network.getVpcId()), vpc.getCidr(), snatIP);
+            if (!result) {
+                String msg = String.format("Could not create Netris Nat Rule 
for IP %s", snatIP);
+                logger.error(msg);
+                throw new CloudRuntimeException(msg);
+            }
         }
 
         return nicProfile;
@@ -277,7 +293,7 @@ public class NetrisGuestNetworkGuru  extends 
GuestNetworkGuru implements Network
             vpcName = vpc.getName();
             vpcId = vpc.getId();
         } else {
-            logger.debug(String.format("Creating a Tier 1 Gateway for the 
network %s before creating the NSX segment", networkVO.getName()));
+            logger.debug(String.format("Creating IPAM Allocation before 
creating IPAM Subnet", networkVO.getName()));
             long networkOfferingId = networkVO.getNetworkOfferingId();
             NetworkOfferingVO networkOfferingVO = 
networkOfferingDao.findById(networkOfferingId);
             boolean isSourceNatSupported = 
!NetworkOffering.NetworkMode.ROUTED.equals(networkOfferingVO.getNetworkMode()) 
&&
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java
index 11db60a5aca..f1cc49b7125 100644
--- 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java
@@ -128,6 +128,15 @@ public class NetrisPublicNetworkGuru extends 
PublicNetworkGuru {
                 if (!hasNatSupport) {
                     return nic;
                 }
+
+                String snatIP = ipAddress.getAddress().addr();
+                result = netrisService.createSnatRule(dataCenterId, accountId, 
domainId, vpc.getName(), vpc.getId(), network.getName(), network.getId(), 
isForVpc, vpc.getCidr(), snatIP);
+                if (!result) {
+                    String msg = String.format("Could not create Netris Nat 
Rule for IP %s", snatIP);
+                    logger.error(msg);
+                    throw new CloudRuntimeException(msg);
+                }
+
             }
         }
         return nic;
diff --git 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java
 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java
index d679eae258d..b1e00f771cd 100644
--- 
a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java
+++ 
b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java
@@ -19,25 +19,32 @@ package org.apache.cloudstack.service;
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
 import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.network.IpAddress;
 import com.cloud.network.Networks;
+import com.cloud.network.SDNProviderNetworkRule;
 import com.cloud.network.dao.NetrisProviderDao;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.element.NetrisProviderVO;
 import com.cloud.network.netris.NetrisService;
 import com.cloud.network.vpc.Vpc;
+import io.netris.model.NatPostBody;
 import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand;
 import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
+import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand;
+import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand;
 import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
 import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
 import org.apache.cloudstack.agent.api.NetrisAnswer;
 import org.apache.cloudstack.agent.api.NetrisCommand;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.cloudstack.resource.NetrisResourceObjectUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
 import javax.inject.Inject;
+import java.util.Locale;
 import java.util.Objects;
 
 public class NetrisServiceImpl implements NetrisService, Configurable {
@@ -110,4 +117,136 @@ public class NetrisServiceImpl implements NetrisService, 
Configurable {
         NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
         return answer.getResult();
     }
+
+    @Override
+    public boolean createSnatRule(long zoneId, long accountId, long domainId, 
String vpcName, long vpcId, String networkName, long networkId, boolean 
isForVpc, String vpcCidr, String snatIP) {
+        CreateOrUpdateNetrisNatCommand cmd = new 
CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, 
networkName, networkId, isForVpc, vpcCidr);
+        cmd.setNatIp(snatIP);
+        cmd.setNatRuleType("SNAT");
+        String suffix;
+        if (isForVpc) {
+            suffix = String.valueOf(vpcId); // D1-A1-Z1-V25-SNAT
+        } else {
+            suffix = String.valueOf(networkId); // D1-A1-Z1-N25-SNAT
+        }
+        cmd.setProtocol(NatPostBody.ProtocolEnum.ALL.getValue());
+        cmd.setState(NatPostBody.StateEnum.ENABLED.getValue());
+        String snatRuleName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.SNAT, suffix);
+        cmd.setNatRuleName(snatRuleName);
+        NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
+        return answer.getResult();
+    }
+
+    @Override
+    public boolean createPortForwardingRule(long zoneId, long accountId, long 
domainId, String vpcName, long vpcId, String networkName,
+                                            Long networkId, boolean isForVpc, 
String vpcCidr, SDNProviderNetworkRule networkRule) {
+        CreateOrUpdateNetrisNatCommand cmd = new 
CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId,
+                networkName, networkId, isForVpc, vpcCidr);
+        cmd.setProtocol(networkRule.getProtocol().toLowerCase(Locale.ROOT));
+        cmd.setDestinationAddress(networkRule.getPublicIp());
+        cmd.setDestinationPort(networkRule.getPublicPort());
+        cmd.setSourceAddress(networkRule.getVmIp());
+        cmd.setSourcePort(networkRule.getPrivatePort());
+        cmd.setState(NatPostBody.StateEnum.ENABLED.getValue());
+        String ruleName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.DNAT,
+                String.valueOf(vpcId), String.format("R%s", 
networkRule.getRuleId()));
+        cmd.setNatRuleName(ruleName);
+        cmd.setNatRuleType("DNAT");
+
+        NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
+        return answer.getResult();
+    }
+
+    @Override
+    public boolean deletePortForwardingRule(long zoneId, long accountId, long 
domainId, String vpcName, Long vpcId, String networkName, Long networkId, 
boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule) {
+        DeleteNetrisNatRuleCommand cmd = new 
DeleteNetrisNatRuleCommand(zoneId, accountId, domainId, vpcName, vpcId, 
networkName, networkId, isForVpc);
+        String ruleName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.DNAT,
+                String.valueOf(vpcId), String.format("R%s", 
networkRule.getRuleId()));
+        cmd.setNatRuleType("DNAT");
+        cmd.setNatRuleName(ruleName);
+        NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
+        return answer.getResult();
+    }
+
+    @Override
+    public boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address) {
+        if (vpc == null || address == null) {
+            return false;
+        }
+        long accountId = vpc.getAccountId();
+        long domainId = vpc.getDomainId();
+        long zoneId = vpc.getZoneId();
+        long vpcId = vpc.getId();
+        String vpcName = vpc.getName();
+
+        logger.debug("Updating the source NAT IP for Netris VPC {} to IP: {}", 
vpc.getName(), address.getAddress().addr());
+
+        CreateOrUpdateNetrisNatCommand cmd = new 
CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, 
null, null, true, address.getAddress().addr());
+        cmd.setNatRuleType("SNAT");
+        String snatRuleName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.SNAT, String.valueOf(vpcId));
+        cmd.setNatRuleName(snatRuleName);
+        NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
+        if (!answer.getResult()) {
+            logger.error("Could not update the source NAT IP address for VPC 
{}: {}", vpc.getName(), answer.getDetails());
+            return false;
+        }
+        return answer.getResult();
+    }
+
+    @Override
+    public boolean createStaticNatRule(long zoneId, long accountId, long 
domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, 
String vpcCidr, String staticNatIp, String vmIp) {
+        String vpcName = null;
+        String networkName = null;
+        Long vpcId = null;
+        Long networkId = null;
+        if (isForVpc) {
+            vpcName = networkResourceName;
+            vpcId = networkResourceId;
+        } else {
+            networkName = networkResourceName;
+            networkId = networkResourceId;
+        }
+        CreateOrUpdateNetrisNatCommand cmd = new 
CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, 
networkName, networkId, isForVpc, vpcCidr);
+        cmd.setNatRuleType("STATICNAT");
+        cmd.setNatIp(staticNatIp);
+        cmd.setVmIp(vmIp);
+        String suffix = getResourceSuffix(vpcId, networkId, isForVpc);
+        String dnatRuleName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.STATICNAT, suffix);
+        cmd.setNatRuleName(dnatRuleName);
+        NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
+        return answer.getResult();
+    }
+
+    @Override
+    public boolean deleteStaticNatRule(long zoneId, long accountId, long 
domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, 
String staticNatIp) {
+        String vpcName = null;
+        String networkName = null;
+        Long vpcId = null;
+        Long networkId = null;
+        if (isForVpc) {
+            vpcName = networkResourceName;
+            vpcId = networkResourceId;
+        } else {
+            networkName = networkResourceName;
+            networkId = networkResourceId;
+        }
+        DeleteNetrisNatRuleCommand cmd = new 
DeleteNetrisNatRuleCommand(zoneId, accountId, domainId, vpcName, vpcId, 
networkName, networkId, isForVpc);
+        String suffix = getResourceSuffix(vpcId, networkId, isForVpc);
+        String dnatRuleName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.STATICNAT, suffix);
+        cmd.setNatRuleName(dnatRuleName);
+        cmd.setNatRuleType("STATICNAT");
+        cmd.setNatIp(staticNatIp);
+        NetrisAnswer answer = sendNetrisCommand(cmd, zoneId);
+        return answer.getResult();
+    }
+
+    private String getResourceSuffix(Long vpcId, Long networkId, boolean 
isForVpc) {
+        String suffix;
+        if (isForVpc) {
+            suffix = String.valueOf(vpcId); // D1-A1-Z1-V25-STATICNAT or 
D1-A1-Z1-V25-SNAT
+        } else {
+            suffix = String.valueOf(networkId); // D1-A1-Z1-N25-STATICNAT or 
D1-A1-Z1-N25-SNAT
+        }
+        return suffix;
+    }
 }
diff --git 
a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java
 
b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java
index 11b4af48fed..e7d223672e4 100644
--- 
a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java
+++ 
b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java
@@ -17,6 +17,7 @@
 package org.apache.cloudstack.resource;
 
 import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
+import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand;
 import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
 import org.junit.Assert;
 import org.junit.Test;
@@ -54,4 +55,15 @@ public class NetrisResourceObjectUtilsTest {
         String expectedNetrisVpcName = String.format("D%s-A%s-Z%s-V%s-%s", 
domainId, accountId, zoneId, vpcId, vpcName);
         Assert.assertEquals(expectedNetrisVpcName, netrisVpcName);
     }
+
+    @Test
+    public void testSuffixesForDNAT() {
+        CreateOrUpdateNetrisNatCommand cmd = new 
CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, 
vpcName, null, true, vpcCidr);
+        cmd.setNatRuleType("DNAT");
+        long ruleId = 23L;
+        String ruleName = 
NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, 
NetrisResourceObjectUtils.NetrisObjectType.DNAT,
+                String.valueOf(vpcId), String.format("R%s", ruleId));
+        String expectedNetrisRuleName = 
String.format("D%s-A%s-Z%s-V%s-DNAT-R%s", domainId, accountId, zoneId, vpcId, 
ruleId);
+        Assert.assertEquals(expectedNetrisRuleName, ruleName);
+    }
 }
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 c11141db9d4..153143b6d18 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
@@ -16,151 +16,18 @@
 // under the License.
 package org.apache.cloudstack.resource;
 
-import com.cloud.network.Network;
+import com.cloud.network.SDNProviderNetworkRule;
 
 import java.util.List;
 
-public class NsxNetworkRule {
+public class NsxNetworkRule extends SDNProviderNetworkRule {
 
     public enum NsxRuleAction {
         ALLOW, DROP
     }
 
-    private long domainId;
-    private long accountId;
-    private long zoneId;
-    private Long networkResourceId;
-    private String networkResourceName;
-    private boolean isVpcResource;
-    private long vmId;
-    private long ruleId;
-    private String publicIp;
-    private String vmIp;
-    private String publicPort;
-    private String privatePort;
-    private String protocol;
-    private String algorithm;
     private List<NsxLoadBalancerMember> memberList;
     private NsxRuleAction aclAction;
-    private List<String> sourceCidrList;
-    private List<String> destinationCidrList;
-    private Integer icmpCode;
-
-    private Integer icmpType;
-    private String trafficType;
-    private Network.Service service;
-
-    public long getDomainId() {
-        return domainId;
-    }
-
-    public void setDomainId(long domainId) {
-        this.domainId = domainId;
-    }
-
-    public long getAccountId() {
-        return accountId;
-    }
-
-    public void setAccountId(long accountId) {
-        this.accountId = accountId;
-    }
-
-    public long getZoneId() {
-        return zoneId;
-    }
-
-    public void setZoneId(long zoneId) {
-        this.zoneId = zoneId;
-    }
-
-    public Long getNetworkResourceId() {
-        return networkResourceId;
-    }
-
-    public void setNetworkResourceId(Long networkResourceId) {
-        this.networkResourceId = networkResourceId;
-    }
-
-    public String getNetworkResourceName() {
-        return networkResourceName;
-    }
-
-    public void setNetworkResourceName(String networkResourceName) {
-        this.networkResourceName = networkResourceName;
-    }
-
-    public boolean isVpcResource() {
-        return isVpcResource;
-    }
-
-    public void setVpcResource(boolean vpcResource) {
-        isVpcResource = vpcResource;
-    }
-
-    public long getVmId() {
-        return vmId;
-    }
-
-    public void setVmId(long vmId) {
-        this.vmId = vmId;
-    }
-
-    public long getRuleId() {
-        return ruleId;
-    }
-
-    public void setRuleId(long ruleId) {
-        this.ruleId = ruleId;
-    }
-
-    public String getPublicIp() {
-        return publicIp;
-    }
-
-    public void setPublicIp(String publicIp) {
-        this.publicIp = publicIp;
-    }
-
-    public String getVmIp() {
-        return vmIp;
-    }
-
-    public void setVmIp(String vmIp) {
-        this.vmIp = vmIp;
-    }
-
-    public String getPublicPort() {
-        return publicPort;
-    }
-
-    public void setPublicPort(String publicPort) {
-        this.publicPort = publicPort;
-    }
-
-    public String getPrivatePort() {
-        return privatePort;
-    }
-
-    public void setPrivatePort(String privatePort) {
-        this.privatePort = privatePort;
-    }
-
-    public String getProtocol() {
-        return protocol;
-    }
-
-    public void setProtocol(String protocol) {
-        this.protocol = protocol;
-    }
-
-    public void setAlgorithm(String algorithm) {
-        this.algorithm = algorithm;
-    }
-
-    public String getAlgorithm() {
-        return algorithm;
-    }
 
     public List<NsxLoadBalancerMember> getMemberList() {
         return memberList;
@@ -177,221 +44,4 @@ public class NsxNetworkRule {
     public void setAclAction(NsxRuleAction aclAction) {
         this.aclAction = aclAction;
     }
-
-    public Network.Service getService() {
-        return service;
-    }
-
-    public void setService(Network.Service service) {
-        this.service = service;
-    }
-
-    public Integer getIcmpCode() {
-        return icmpCode;
-    }
-
-    public void setIcmpCode(Integer icmpCode) {
-        this.icmpCode = icmpCode;
-    }
-
-    public Integer getIcmpType() {
-        return icmpType;
-    }
-
-    public void setIcmpType(Integer icmpType) {
-        this.icmpType = icmpType;
-    }
-
-    public List<String> getSourceCidrList() {
-        return sourceCidrList;
-    }
-
-    public void setSourceCidrList(List<String> sourceCidrList) {
-        this.sourceCidrList = sourceCidrList;
-    }
-
-    public List<String> getDestinationCidrList() {
-        return destinationCidrList;
-    }
-
-    public void setDestinationCidrList(List<String> destinationCidrList) {
-        this.destinationCidrList = destinationCidrList;
-    }
-
-    public String getTrafficType() {
-        return trafficType;
-    }
-
-    public void setTrafficType(String trafficType) {
-        this.trafficType = trafficType;
-    }
-
-    public static final class Builder {
-        private long domainId;
-        private long accountId;
-        private long zoneId;
-        private Long networkResourceId;
-        private String networkResourceName;
-        private boolean isVpcResource;
-        private long vmId;
-
-        private long ruleId;
-        private String publicIp;
-        private String vmIp;
-        private String publicPort;
-        private String privatePort;
-        private String protocol;
-        private String algorithm;
-        private List<NsxLoadBalancerMember> memberList;
-        private NsxRuleAction aclAction;
-        private List<String> sourceCidrList;
-        private List<String> destinationidrList;
-        private String trafficType;
-        private Integer icmpType;
-        private Integer icmpCode;
-        private Network.Service service;
-
-        public Builder() {
-            // Default constructor
-        }
-
-        public Builder setDomainId(long domainId) {
-            this.domainId = domainId;
-            return this;
-        }
-
-        public Builder setAccountId(long accountId) {
-            this.accountId = accountId;
-            return this;
-        }
-
-        public Builder setZoneId(long zoneId) {
-            this.zoneId = zoneId;
-            return this;
-        }
-
-        public Builder setNetworkResourceId(Long networkResourceId) {
-            this.networkResourceId = networkResourceId;
-            return this;
-        }
-
-        public Builder setNetworkResourceName(String networkResourceName) {
-            this.networkResourceName = networkResourceName;
-            return this;
-        }
-
-        public Builder setVpcResource(boolean isVpcResource) {
-            this.isVpcResource = isVpcResource;
-            return this;
-        }
-
-
-        public Builder setVmId(long vmId) {
-            this.vmId = vmId;
-            return this;
-        }
-
-        public Builder setRuleId(long ruleId) {
-            this.ruleId = ruleId;
-            return this;
-        }
-
-        public Builder setPublicIp(String publicIp) {
-            this.publicIp = publicIp;
-            return this;
-        }
-
-        public Builder setVmIp(String vmIp) {
-            this.vmIp = vmIp;
-            return this;
-        }
-
-        public Builder setPublicPort(String publicPort) {
-            this.publicPort = publicPort;
-            return this;
-        }
-
-        public Builder setPrivatePort(String privatePort) {
-            this.privatePort = privatePort;
-            return this;
-        }
-
-        public Builder setProtocol(String protocol) {
-            this.protocol = protocol;
-            return this;
-        }
-
-        public Builder setAlgorithm(String algorithm) {
-            this.algorithm = algorithm;
-            return this;
-        }
-
-        public Builder setMemberList(List<NsxLoadBalancerMember> memberList) {
-            this.memberList = memberList;
-            return this;
-        }
-
-
-        public Builder setAclAction(NsxRuleAction aclAction) {
-            this.aclAction = aclAction;
-            return this;
-        }
-
-        public Builder setTrafficType(String trafficType) {
-            this.trafficType = trafficType;
-            return this;
-        }
-
-        public Builder setIcmpType(Integer icmpType) {
-            this.icmpType = icmpType;
-            return this;
-        }
-
-        public Builder setIcmpCode(Integer icmpCode) {
-            this.icmpCode = icmpCode;
-            return this;
-        }
-
-        public Builder setSourceCidrList(List<String> sourceCidrList) {
-            this.sourceCidrList = sourceCidrList;
-            return this;
-        }
-
-        public Builder setDestinationCidrList(List<String> 
destinationCidrList) {
-            this.destinationidrList = destinationCidrList;
-            return this;
-        }
-
-        public Builder setService(Network.Service service) {
-            this.service = service;
-            return this;
-        }
-
-        public NsxNetworkRule build() {
-            NsxNetworkRule rule = new NsxNetworkRule();
-            rule.setDomainId(this.domainId);
-            rule.setAccountId(this.accountId);
-            rule.setZoneId(this.zoneId);
-            rule.setNetworkResourceId(this.networkResourceId);
-            rule.setNetworkResourceName(this.networkResourceName);
-            rule.setVpcResource(this.isVpcResource);
-            rule.setVmId(this.vmId);
-            rule.setVmIp(this.vmIp);
-            rule.setPublicIp(this.publicIp);
-            rule.setPublicPort(this.publicPort);
-            rule.setPrivatePort(this.privatePort);
-            rule.setProtocol(this.protocol);
-            rule.setRuleId(this.ruleId);
-            rule.setAlgorithm(this.algorithm);
-            rule.setMemberList(this.memberList);
-            rule.setAclAction(this.aclAction);
-            rule.setIcmpType(this.icmpType);
-            rule.setIcmpCode(this.icmpCode);
-            rule.setSourceCidrList(this.sourceCidrList);
-            rule.setDestinationCidrList(this.destinationidrList);
-            rule.setTrafficType(this.trafficType);
-            rule.setService(service);
-            return rule;
-        }
-    }
 }
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 e1b37a8d653..95cd948358a 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
@@ -109,7 +109,7 @@ import 
org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalanc
 import 
org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
 import org.apache.cloudstack.resource.NsxLoadBalancerMember;
 import org.apache.cloudstack.resource.NsxNetworkRule;
-import org.apache.cloudstack.resource.NsxOpObject;
+import com.cloud.network.SDNProviderOpObject;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.cloudstack.resourcedetail.FirewallRuleDetailVO;
@@ -552,26 +552,26 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
                 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();
+                SDNProviderOpObject nsxObject = getNsxOpObject(network);
+                String publicPort = 
PortForwardingServiceProvider.getPublicPortRange(rule);
+
+                String privatePort = 
PortForwardingServiceProvider.getPrivatePFPortRange(rule);
+
+                NsxNetworkRule networkRule = new NsxNetworkRule();
+                networkRule.setDomainId(nsxObject.getDomainId());
+                networkRule.setAccountId(nsxObject.getAccountId());
+                networkRule.setZoneId(nsxObject.getZoneId());
+                
networkRule.setNetworkResourceId(nsxObject.getNetworkResourceId());
+                
networkRule.setNetworkResourceName(nsxObject.getNetworkResourceName());
+                networkRule.setVpcResource(nsxObject.isVpcResource());
+                networkRule.setVmId(Objects.nonNull(vm) ? vm.getId() : 0);
+                networkRule.setVmIp(Objects.nonNull(vm) ? 
vm.getPrivateIpAddress() : null);
+                networkRule.setPublicIp(publicIp.getAddress().addr());
+                networkRule.setPrivatePort(privatePort);
+                networkRule.setPublicPort(publicPort);
+                networkRule.setRuleId(rule.getId());
+                
networkRule.setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT));
+
                 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"))) {
@@ -633,30 +633,6 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
         return new Pair<>(vpc, network);
     }
 
-    private static String getPublicPortRange(PortForwardingRule rule) {
-        return Objects.equals(rule.getSourcePortStart(), 
rule.getSourcePortEnd()) ?
-                String.valueOf(rule.getSourcePortStart()) :
-                
String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd()));
-    }
-
-    private static String getPrivatePFPortRange(PortForwardingRule rule) {
-        return rule.getDestinationPortStart() == rule.getDestinationPortEnd() ?
-                String.valueOf(rule.getDestinationPortStart()) :
-                
String.valueOf(rule.getDestinationPortStart()).concat("-").concat(String.valueOf(rule.getDestinationPortEnd()));
-    }
-
-    private static String getPrivatePortRange(FirewallRule rule) {
-        return Objects.equals(rule.getSourcePortStart(), 
rule.getSourcePortEnd()) ?
-                String.valueOf(rule.getSourcePortStart()) :
-                
String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd()));
-    }
-
-    private static String getPrivatePortRangeForACLRule(NetworkACLItem rule) {
-        return Objects.equals(rule.getSourcePortStart(), 
rule.getSourcePortEnd()) ?
-                String.valueOf(rule.getSourcePortStart()) :
-                
String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd()));
-    }
-
     private long getResourceId(String resource, VpcVO vpc, NetworkVO network) {
         switch (resource) {
             case "domain":
@@ -670,7 +646,7 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
         }
     }
 
-    private NsxOpObject getNsxOpObject(Network network) {
+    private SDNProviderOpObject getNsxOpObject(Network network) {
         Pair<VpcVO, NetworkVO> vpcOrNetwork = 
getVpcOrNetwork(network.getVpcId(), network.getId());
         VpcVO vpc = vpcOrNetwork.first();
         NetworkVO networkVO = vpcOrNetwork.second();
@@ -678,7 +654,7 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
         long accountId = getResourceId("account", vpc, networkVO);
         long zoneId = getResourceId("zone", vpc, networkVO);
 
-        return new NsxOpObject.Builder()
+        return new SDNProviderOpObject.Builder()
                 .vpcVO(vpc)
                 .networkVO(networkVO)
                 .domainId(domainId)
@@ -693,25 +669,24 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
         for (LoadBalancingRule loadBalancingRule : rules) {
             IPAddressVO publicIp = 
ipAddressDao.findByIpAndDcId(network.getDataCenterId(),
                     loadBalancingRule.getSourceIp().addr());
-            NsxOpObject nsxObject = getNsxOpObject(network);
+            SDNProviderOpObject nsxObject = getNsxOpObject(network);
 
             List<NsxLoadBalancerMember> lbMembers = 
getLoadBalancerMembers(loadBalancingRule);
-            NsxNetworkRule networkRule = new NsxNetworkRule.Builder()
-                    .setDomainId(nsxObject.getDomainId())
-                    .setAccountId(nsxObject.getAccountId())
-                    .setZoneId(nsxObject.getZoneId())
-                    .setNetworkResourceId(nsxObject.getNetworkResourceId())
-                    .setNetworkResourceName(nsxObject.getNetworkResourceName())
-                    .setVpcResource(nsxObject.isVpcResource())
-                    .setMemberList(lbMembers)
-                    .setPublicIp(LoadBalancerContainer.Scheme.Public == 
loadBalancingRule.getScheme() ?
-                            publicIp.getAddress().addr() : 
loadBalancingRule.getSourceIp().addr())
-                    
.setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart()))
-                    
.setPrivatePort(String.valueOf(loadBalancingRule.getDefaultPortStart()))
-                    .setRuleId(loadBalancingRule.getId())
-                    
.setProtocol(loadBalancingRule.getLbProtocol().toUpperCase(Locale.ROOT))
-                    .setAlgorithm(loadBalancingRule.getAlgorithm())
-                    .build();
+            NsxNetworkRule networkRule = new NsxNetworkRule();
+            networkRule.setDomainId(nsxObject.getDomainId());
+            networkRule.setAccountId(nsxObject.getAccountId());
+            networkRule.setZoneId(nsxObject.getZoneId());
+            networkRule.setNetworkResourceId(nsxObject.getNetworkResourceId());
+            
networkRule.setNetworkResourceName(nsxObject.getNetworkResourceName());
+            networkRule.setVpcResource(nsxObject.isVpcResource());
+            networkRule.setPublicIp(LoadBalancerContainer.Scheme.Public == 
loadBalancingRule.getScheme() ?
+                            publicIp.getAddress().addr() : 
loadBalancingRule.getSourceIp().addr());
+            
networkRule.setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart()));
+            
networkRule.setPrivatePort(String.valueOf(loadBalancingRule.getDefaultPortStart()));
+            networkRule.setRuleId(loadBalancingRule.getId());
+            
networkRule.setProtocol(loadBalancingRule.getLbProtocol().toUpperCase(Locale.ROOT));
+            networkRule.setAlgorithm(loadBalancingRule.getAlgorithm());
+            networkRule.setMemberList(lbMembers);
             if (Arrays.asList(FirewallRule.State.Add, 
FirewallRule.State.Active).contains(loadBalancingRule.getState())) {
                 result &= nsxService.createLbRule(networkRule);
             } else if (loadBalancingRule.getState() == 
FirewallRule.State.Revoke) {
@@ -756,7 +731,7 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
         List<NsxNetworkRule> nsxDelNetworkRules = new ArrayList<>();
         boolean success = true;
         for (NetworkACLItem rule : rules) {
-            String privatePort = getPrivatePortRangeForACLRule(rule);
+            String privatePort = 
PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule);
             NsxNetworkRule networkRule = getNsxNetworkRuleForAcl(rule, 
privatePort);
             if (Arrays.asList(NetworkACLItem.State.Active, 
NetworkACLItem.State.Add).contains(rule.getState())) {
                 success = success && nsxService.addFirewallRules(network, 
List.of(networkRule));
@@ -778,7 +753,7 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
     public boolean reorderAclRules(Vpc vpc, List<? extends Network> networks, 
List<? extends NetworkACLItem> networkACLItems) {
         List<NsxNetworkRule> aclRulesList = new ArrayList<>();
         for (NetworkACLItem rule : networkACLItems) {
-            String privatePort = getPrivatePortRangeForACLRule(rule);
+            String privatePort = 
PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule);
             aclRulesList.add(getNsxNetworkRuleForAcl(rule, privatePort));
         }
         for (Network network: networks) {
@@ -794,18 +769,18 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
     }
 
     private NsxNetworkRule getNsxNetworkRuleForAcl(NetworkACLItem rule, String 
privatePort) {
-        return new NsxNetworkRule.Builder()
-                .setRuleId(rule.getId())
-                .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? 
transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY"))
-                .setAclAction(transformActionValue(rule.getAction()))
-                .setTrafficType(rule.getTrafficType().toString())
-                .setProtocol(rule.getProtocol().toUpperCase())
-                .setPublicPort(String.valueOf(rule.getSourcePortStart()))
-                .setPrivatePort(privatePort)
-                .setIcmpCode(rule.getIcmpCode())
-                .setIcmpType(rule.getIcmpType())
-                .setService(Network.Service.NetworkACL)
-                .build();
+        NsxNetworkRule nsxNetworkRule = new NsxNetworkRule();
+        nsxNetworkRule.setRuleId(rule.getId());
+        
nsxNetworkRule.setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? 
transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY"));
+        nsxNetworkRule.setTrafficType(rule.getTrafficType().toString());
+        nsxNetworkRule.setProtocol(rule.getProtocol().toUpperCase());
+        
nsxNetworkRule.setPublicPort(String.valueOf(rule.getSourcePortStart()));
+        nsxNetworkRule.setPrivatePort(privatePort);
+        nsxNetworkRule.setIcmpCode(rule.getIcmpCode());
+        nsxNetworkRule.setIcmpType(rule.getIcmpType());
+        nsxNetworkRule.setService(Network.Service.NetworkACL);
+        nsxNetworkRule.setAclAction(transformActionValue(rule.getAction()));
+        return nsxNetworkRule;
     }
         @Override
     public boolean applyFWRules(Network network, List<? extends FirewallRule> 
rules) throws ResourceUnavailableException {
@@ -816,20 +791,19 @@ public class NsxElement extends AdapterBase implements  
DhcpServiceProvider, Dns
         List<NsxNetworkRule> nsxAddNetworkRules = new ArrayList<>();
         List<NsxNetworkRule> nsxDelNetworkRules = new ArrayList<>();
         for (FirewallRule rule : rules) {
-            NsxNetworkRule networkRule = new NsxNetworkRule.Builder()
-                    .setRuleId(rule.getId())
-                    .setAclAction(NsxNetworkRule.NsxRuleAction.ALLOW)
-                    
.setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ?
-                            transformCidrListValues(rule.getSourceCidrList()) 
: List.of("ANY"))
-                    
.setDestinationCidrList(Objects.nonNull(rule.getDestinationCidrList()) ?
-                            
transformCidrListValues(rule.getDestinationCidrList()) : List.of("ANY"))
-                    .setIcmpCode(rule.getIcmpCode())
-                    .setIcmpType(rule.getIcmpType())
-                    .setPrivatePort(getPrivatePortRange(rule))
-                    .setTrafficType(rule.getTrafficType().toString())
-                    .setService(Network.Service.Firewall)
-                    .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT))
-                    .build();
+            NsxNetworkRule networkRule = new NsxNetworkRule();
+            networkRule.setRuleId(rule.getId());
+            
networkRule.setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ?
+                        transformCidrListValues(rule.getSourceCidrList()) : 
List.of("ANY"));
+            
networkRule.setDestinationCidrList(Objects.nonNull(rule.getDestinationCidrList())
 ?
+                        transformCidrListValues(rule.getDestinationCidrList()) 
: List.of("ANY"));
+            networkRule.setIcmpCode(rule.getIcmpCode());
+            networkRule.setIcmpType(rule.getIcmpType());
+            
networkRule.setPrivatePort(PortForwardingServiceProvider.getPrivatePortRange(rule));
+            networkRule.setTrafficType(rule.getTrafficType().toString());
+            networkRule.setService(Network.Service.Firewall);
+            
networkRule.setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT));
+            networkRule.setAclAction(NsxNetworkRule.NsxRuleAction.ALLOW);
             if (rule.getState() == FirewallRule.State.Add) {
                 nsxAddNetworkRules.add(networkRule);
             } else if (rule.getState() == FirewallRule.State.Revoke) {
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 7c44a7324fb..a807155a2dc 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
@@ -36,6 +36,7 @@ import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.dao.PhysicalNetworkDao;
 import com.cloud.network.dao.PhysicalNetworkVO;
+import com.cloud.network.element.PortForwardingServiceProvider;
 import com.cloud.network.lb.LoadBalancingRule;
 import com.cloud.network.rules.FirewallRule;
 import com.cloud.network.rules.FirewallRuleVO;
@@ -72,7 +73,6 @@ import org.mockito.junit.MockitoJUnitRunner;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.util.List;
 
 import static org.junit.Assert.assertTrue;
@@ -307,84 +307,60 @@ public class NsxElementTest {
         assertNotNull(vpcNetworkPair.second());
     }
 
-    private Method getPublicPortRangeMethod() throws NoSuchMethodException {
-        Method method = 
NsxElement.class.getDeclaredMethod("getPublicPortRange", 
PortForwardingRule.class);
-        method.setAccessible(true);
-        return method;
-    }
-
-    private Method getPrivatePFPortRangeMethod() throws NoSuchMethodException {
-        Method method = 
NsxElement.class.getDeclaredMethod("getPrivatePFPortRange", 
PortForwardingRule.class);
-        method.setAccessible(true);
-        return method;
-    }
-
-    private Method getPrivatePortRangeMethod() throws NoSuchMethodException {
-        Method method = 
NsxElement.class.getDeclaredMethod("getPrivatePortRange", FirewallRule.class);
-        method.setAccessible(true);
-        return method;
-    }
-
-    private Method getPrivatePortRangeForACLRuleMethod() throws 
NoSuchMethodException {
-        Method method = 
NsxElement.class.getDeclaredMethod("getPrivatePortRangeForACLRule", 
NetworkACLItem.class);
-        method.setAccessible(true);
-        return method;
-    }
-
     @Test
     public void testGetPublicPortRangeWhenStartAndEndPortNumbersAreDifferent() 
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException 
{
         PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 90, 
new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L,
                 5L, 2L, 15L);
-        assertEquals("80-90", getPublicPortRangeMethod().invoke(null, rule));
+        assertEquals("80-90", 
PortForwardingServiceProvider.getPublicPortRange(rule));
     }
 
     @Test
     public void testGetPublicPortRangeWhenStartAndEndPortNumbersAreSame() 
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException 
{
         PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 80, 
new Ip("172.30.10.11"), 8080, 8080, "tcp", 12L,
                 5L, 2L, 15L);
-        assertEquals("80", getPublicPortRangeMethod().invoke(null, rule));
+        assertEquals("80", 
PortForwardingServiceProvider.getPublicPortRange(rule));
     }
 
     @Test
     public void 
testGetPrivatePFPortRangeWhenStartAndEndPortNumbersAreDifferent() throws 
NoSuchMethodException, InvocationTargetException, IllegalAccessException {
         PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 90, 
new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L,
                 5L, 2L, 15L);
-        assertEquals("8080-8090", getPrivatePFPortRangeMethod().invoke(null, 
rule));
+        assertEquals("8080-8090", 
PortForwardingServiceProvider.getPrivatePFPortRange(rule));
     }
 
     @Test
     public void testGetPrivatePFPortRangeWhenStartAndEndPortNumbersAreSame() 
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException 
{
         PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 80, 
new Ip("172.30.10.11"), 8080, 8080, "tcp", 12L,
                 5L, 2L, 15L);
-        assertEquals("8080", getPrivatePFPortRangeMethod().invoke(null, rule));
+        assertEquals("8080", 
PortForwardingServiceProvider.getPrivatePFPortRange(rule));
     }
 
     @Test
     public void testGetPrivatePortRangeWhenStartAndEndPortNumbersAreSame() 
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException 
{
         FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 80, "tcp", 23L, 
5L, 2L,
         FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), null, null, 
null, null, FirewallRule.TrafficType.Egress, 
FirewallRule.FirewallRuleType.User);
-        assertEquals("80", getPrivatePortRangeMethod().invoke(null, rule));
+        assertEquals("80", 
PortForwardingServiceProvider.getPrivatePortRange(rule));
     }
 
     @Test
     public void 
testGetPrivatePortRangeWhenStartAndEndPortNumbersAreDifferent() throws 
NoSuchMethodException, InvocationTargetException, IllegalAccessException {
         FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 90, "tcp", 23L, 
5L, 2L,
                 FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), 
null, null, null, null, FirewallRule.TrafficType.Egress, 
FirewallRule.FirewallRuleType.User);
-        assertEquals("80-90", getPrivatePortRangeMethod().invoke(null, rule));
+        assertEquals("80-90", 
PortForwardingServiceProvider.getPrivatePortRange(rule));
     }
 
     @Test
     public void 
testGetPrivatePortRangeForACLWhenStartAndEndPortNumbersAreSame() throws 
NoSuchMethodException, InvocationTargetException, IllegalAccessException {
         NetworkACLItem rule = new NetworkACLItemVO(80, 80, "udp", 10L, 
List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, 
NetworkACLItem.Action.Allow,
         2, null);
-        assertEquals("80", getPrivatePortRangeForACLRuleMethod().invoke(null, 
rule));
+        assertEquals("80", 
PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule));
     }
 
     @Test
     public void 
testGetPrivatePortRangeForACLWhenStartAndEndPortNumbersAreDifferent() throws 
NoSuchMethodException, InvocationTargetException, IllegalAccessException {
         NetworkACLItem rule = new NetworkACLItemVO(80, 90, "udp", 10L, 
List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, 
NetworkACLItem.Action.Allow,
                 2, null);
-        assertEquals("80-90", 
getPrivatePortRangeForACLRuleMethod().invoke(null, rule));
+        assertEquals("80-90", 
PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule));
     }
 
     @Test
diff --git 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java
 b/server/src/main/java/com/cloud/network/SDNProviderOpObject.java
similarity index 94%
rename from 
plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java
rename to server/src/main/java/com/cloud/network/SDNProviderOpObject.java
index bb411249b88..902e47545e9 100644
--- 
a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java
+++ b/server/src/main/java/com/cloud/network/SDNProviderOpObject.java
@@ -14,14 +14,14 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-package org.apache.cloudstack.resource;
+package com.cloud.network;
 
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.vpc.VpcVO;
 
 import java.util.Objects;
 
-public class NsxOpObject {
+public class SDNProviderOpObject {
     VpcVO vpcVO;
     NetworkVO networkVO;
     long accountId;
@@ -116,8 +116,8 @@ public class NsxOpObject {
             return this;
         }
 
-        public NsxOpObject build() {
-            NsxOpObject object = new NsxOpObject();
+        public SDNProviderOpObject build() {
+            SDNProviderOpObject object = new SDNProviderOpObject();
             object.setVpcVO(this.vpcVO);
             object.setNetworkVO(this.networkVO);
             object.setDomainId(this.domainId);
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 64abcff84ef..2012f77e338 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -454,6 +454,24 @@ public class VpcManagerImpl extends ManagerBase implements 
VpcManager, VpcProvis
                             State.Enabled, null, false, false, false, 
NetworkOffering.NetworkMode.ROUTED, null, false);
 
                 }
+
+                // configure default vpc offering with Netris as network 
service provider in NAT mode
+                if 
(_vpcOffDao.findByUniqueName(VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME) 
== null) {
+                    logger.debug(String.format("Creating default VPC offering 
for Netris network service provider %s in NAT mode", 
VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME));
+                    final Map<Service, Set<Provider>> svcProviderMap = new 
HashMap<>();
+                    final Set<Provider> defaultProviders = 
Set.of(Provider.Netris);
+                    for (final Service svc : getSupportedServices()) {
+                        if (List.of(Service.UserData, Service.Dhcp, 
Service.Dns).contains(svc)) {
+                            final Set<Provider> userDataProvider = 
Set.of(Provider.VPCVirtualRouter);
+                            svcProviderMap.put(svc, userDataProvider);
+                        } else {
+                            svcProviderMap.put(svc, defaultProviders);
+                        }
+                    }
+                    
createVpcOffering(VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, 
VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, svcProviderMap, false,
+                            State.Enabled, null, false, false, false, 
NetworkOffering.NetworkMode.NATTED, null, false);
+
+                }
             }
         });
 
diff --git a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java 
b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
index 67a9b61c214..8ff0e70ec72 100644
--- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java
@@ -1220,6 +1220,10 @@ public class ConfigurationServerImpl extends ManagerBase 
implements Configuratio
                 // Offering #14 - network offering for Netris provider for 
VPCs - ROUTED mode
                 
createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_ROUTED_NETRIS_OFFERING_FOR_VPC,
 "Offering for Netris enabled networks on VPCs - ROUTED mode",
                         NetworkOffering.NetworkMode.ROUTED, true, true, 
Provider.Netris);
+
+                // Offering #15 - network offering for Netris provider for 
VPCs - NATTED mode
+                
createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_NAT_NETRIS_OFFERING_FOR_VPC,
 "Offering for Netris enabled networks on VPCs - NAT mode",
+                        NetworkOffering.NetworkMode.NATTED, true, true, 
Provider.Netris);
             }
         });
     }


Reply via email to