You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by hu...@apache.org on 2012/10/12 14:15:51 UTC

[3/16] git commit: Implement the portforwarding code in the resource

Implement the portforwarding code in the resource

Fix a small naming typo

Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/ab8ba3d6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/ab8ba3d6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/ab8ba3d6

Branch: refs/heads/master
Commit: ab8ba3d61d9d380452bc789b39046a6321cd2187
Parents: 553a720
Author: Hugo Trippaers <ht...@schubergphilis.com>
Authored: Fri Oct 12 11:57:27 2012 +0200
Committer: Hugo Trippaers <ht...@schubergphilis.com>
Committed: Fri Oct 12 11:57:27 2012 +0200

----------------------------------------------------------------------
 .../ConfigurePublicIpsOnLogicalRouterAnswer.java   |   14 +
 .../ConfigurePublicIpsOnLogicalRouterCommand.java  |   50 ++++
 .../network/dao/NiciraNvpRouterMappingDao.java     |    2 +-
 .../network/dao/NiciraNvpRouterMappingDaoImpl.java |    2 +-
 .../cloud/network/element/NiciraNvpElement.java    |   49 +++-
 .../src/com/cloud/network/nicira/NiciraNvpApi.java |   15 +
 .../cloud/network/resource/NiciraNvpResource.java  |  203 ++++++++++++++-
 7 files changed, 310 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/ab8ba3d6/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/ConfigurePublicIpsOnLogicalRouterAnswer.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/ConfigurePublicIpsOnLogicalRouterAnswer.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/ConfigurePublicIpsOnLogicalRouterAnswer.java
new file mode 100644
index 0000000..d0749ed
--- /dev/null
+++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/ConfigurePublicIpsOnLogicalRouterAnswer.java
@@ -0,0 +1,14 @@
+package com.cloud.agent.api;
+
+public class ConfigurePublicIpsOnLogicalRouterAnswer extends Answer {
+
+	public ConfigurePublicIpsOnLogicalRouterAnswer(Command command,
+			boolean success, String details) {
+		super(command, success, details);
+	}
+
+	public ConfigurePublicIpsOnLogicalRouterAnswer(Command command, Exception e) {
+		super(command, e);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/ab8ba3d6/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/ConfigurePublicIpsOnLogicalRouterCommand.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/ConfigurePublicIpsOnLogicalRouterCommand.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/ConfigurePublicIpsOnLogicalRouterCommand.java
new file mode 100644
index 0000000..8c7c8d7
--- /dev/null
+++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/ConfigurePublicIpsOnLogicalRouterCommand.java
@@ -0,0 +1,50 @@
+package com.cloud.agent.api;
+
+import java.util.List;
+
+public class ConfigurePublicIpsOnLogicalRouterCommand extends Command {
+	
+	private String logicalRouterUuid;
+	private String l3GatewayServiceUuid;
+	private List<String> publicCidrs;
+	
+	public ConfigurePublicIpsOnLogicalRouterCommand(String logicalRouterUuid,
+			String l3GatewayServiceUuid,
+			List<String> publicCidrs) {
+		super();
+		this.logicalRouterUuid = logicalRouterUuid;
+		this.publicCidrs = publicCidrs;
+		this.l3GatewayServiceUuid = l3GatewayServiceUuid;
+	}
+
+	public String getLogicalRouterUuid() {
+		return logicalRouterUuid;
+	}
+
+	public void setLogicalRouterUuid(String logicalRouterUuid) {
+		this.logicalRouterUuid = logicalRouterUuid;
+	}
+	
+	public String getL3GatewayServiceUuid() {
+		return l3GatewayServiceUuid;
+	}
+
+	public void setL3GatewayServiceUuid(String l3GatewayServiceUuid) {
+		this.l3GatewayServiceUuid = l3GatewayServiceUuid;
+	}
+
+	public List<String> getPublicCidrs() {
+		return publicCidrs;
+	}
+
+	public void setPublicCidrs(List<String> publicCidrs) {
+		this.publicCidrs = publicCidrs;
+	}
+
+	@Override
+	public boolean executeInSequence() {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/ab8ba3d6/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDao.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDao.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDao.java
index 6fae52e..bb3454a 100644
--- a/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDao.java
+++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDao.java
@@ -5,5 +5,5 @@ import com.cloud.utils.db.GenericDao;
 
 public interface NiciraNvpRouterMappingDao extends GenericDao<NiciraNvpRouterMappingVO, Long> {
 
-	public NiciraNvpRouterMappingVO findByNetworkIdI(long id);
+	public NiciraNvpRouterMappingVO findByNetworkId(long id);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/ab8ba3d6/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDaoImpl.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDaoImpl.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDaoImpl.java
index 303b760..1edcc03 100644
--- a/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDaoImpl.java
+++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpRouterMappingDaoImpl.java
@@ -20,7 +20,7 @@ public class NiciraNvpRouterMappingDaoImpl extends GenericDaoBase<NiciraNvpRoute
 	}
 	
 	@Override
-	public NiciraNvpRouterMappingVO findByNetworkIdI(long id) {
+	public NiciraNvpRouterMappingVO findByNetworkId(long id) {
 		SearchCriteria<NiciraNvpRouterMappingVO> sc = networkSearch.create();
 		sc.setParameters("network_id", id);
 		return findOneBy(sc);

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/ab8ba3d6/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java
index 487a64d..71f8454 100644
--- a/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java
+++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java
@@ -49,6 +49,8 @@ import org.apache.log4j.Logger;
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.ConfigurePortForwardingRulesOnLogicalRouterAnswer;
 import com.cloud.agent.api.ConfigurePortForwardingRulesOnLogicalRouterCommand;
+import com.cloud.agent.api.ConfigurePublicIpsOnLogicalRouterAnswer;
+import com.cloud.agent.api.ConfigurePublicIpsOnLogicalRouterCommand;
 import com.cloud.agent.api.ConfigureStaticNatRulesOnLogicalRouterAnswer;
 import com.cloud.agent.api.ConfigureStaticNatRulesOnLogicalRouterCommand;
 import com.cloud.agent.api.CreateLogicalRouterAnswer;
@@ -469,7 +471,7 @@ public class NiciraNvpElement extends AdapterBase implements
 			// Deleting the LogicalRouter will also take care of all provisioned
 			// nat rules.
 			NiciraNvpRouterMappingVO routermapping = _niciraNvpRouterMappingDao
-					.findByNetworkIdI(network.getId());
+					.findByNetworkId(network.getId());
 			if (routermapping == null) {
 				s_logger.warn("No logical router uuid found for network "
 						+ network.getDisplayText());
@@ -834,13 +836,40 @@ public class NiciraNvpElement extends AdapterBase implements
 	public boolean applyIps(Network network,
 			List<? extends PublicIpAddress> ipAddress, Set<Service> services)
 			throws ResourceUnavailableException {
-		s_logger.debug("Entering applyIps"); // TODO Remove this line
-		
-		// The Nicira Nvp L3 Gateway doesn't need the addresses configured on
-		// the router interface. Only configure the CIDR and individual ip
-		// addresses become available when DNAT rules are created for them.
-		// The cidr setup is done during implementation of the logical router
-		// in the function implement 
+		if (services.contains(Service.SourceNat)) {
+			// Only if we need to provide SourceNat we need to configure the logical router
+			// SourceNat is required for StaticNat and PortForwarding
+			List<NiciraNvpDeviceVO> devices = _niciraNvpDao
+					.listByPhysicalNetwork(network.getPhysicalNetworkId());
+			if (devices.isEmpty()) {
+				s_logger.error("No NiciraNvp Controller on physical network "
+						+ network.getPhysicalNetworkId());
+				return false;
+			}
+			NiciraNvpDeviceVO niciraNvpDevice = devices.get(0);
+			HostVO niciraNvpHost = _hostDao.findById(niciraNvpDevice.getHostId());
+			_hostDao.loadDetails(niciraNvpHost);
+	        	
+			NiciraNvpRouterMappingVO routermapping = _niciraNvpRouterMappingDao
+					.findByNetworkId(network.getId());
+			if (routermapping == null) {
+				s_logger.error("No logical router uuid found for network "
+						+ network.getDisplayText());
+				return false;
+			}
+	
+			List<String> cidrs = new ArrayList<String>();
+			for (PublicIpAddress ip : ipAddress) {
+				cidrs.add(ip.getAddress().addr() + "/" + NetUtils.getCidrSize(ip.getNetmask()));
+			}
+			ConfigurePublicIpsOnLogicalRouterCommand cmd = new ConfigurePublicIpsOnLogicalRouterCommand(routermapping.getLogicalRouterUuid(), 
+					niciraNvpHost.getDetail("l3gatewayserviceuuid"), cidrs);
+			ConfigurePublicIpsOnLogicalRouterAnswer answer = (ConfigurePublicIpsOnLogicalRouterAnswer) _agentMgr.easySend(niciraNvpHost.getId(), cmd);
+			return answer.getResult();
+		}
+		else {
+			s_logger.debug("No need to provision ip addresses as we are not providing L3 services.");
+		}
 		
 		return true;
 	}
@@ -867,7 +896,7 @@ public class NiciraNvpElement extends AdapterBase implements
 		HostVO niciraNvpHost = _hostDao.findById(niciraNvpDevice.getHostId());
         	
 		NiciraNvpRouterMappingVO routermapping = _niciraNvpRouterMappingDao
-				.findByNetworkIdI(network.getId());
+				.findByNetworkId(network.getId());
 		if (routermapping == null) {
 			s_logger.error("No logical router uuid found for network "
 					+ network.getDisplayText());
@@ -915,7 +944,7 @@ public class NiciraNvpElement extends AdapterBase implements
 		HostVO niciraNvpHost = _hostDao.findById(niciraNvpDevice.getHostId());
         	
 		NiciraNvpRouterMappingVO routermapping = _niciraNvpRouterMappingDao
-				.findByNetworkIdI(network.getId());
+				.findByNetworkId(network.getId());
 		if (routermapping == null) {
 			s_logger.error("No logical router uuid found for network "
 					+ network.getDisplayText());

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/ab8ba3d6/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApi.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApi.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApi.java
index 77feb0f..a714e57 100644
--- a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApi.java
+++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApi.java
@@ -237,6 +237,12 @@ public class NiciraNvpApi {
     	
     	executeDeleteObject(uri);
     }
+
+    public void modifyLogicalRouterPort(String logicalRouterUuid, LogicalRouterPort logicalRouterPort) throws NiciraNvpApiException {
+    	String uri = "/ws.v1/lrouter/" + logicalRouterUuid + "/lport/" +  logicalRouterPort.getUuid();
+    	
+    	executeUpdateObject(logicalRouterPort, uri, Collections.<String,String>emptyMap());
+    }
     
     public void modifyLogicalRouterPortAttachment(String logicalRouterUuid, String logicalRouterPortUuid, Attachment attachment) throws NiciraNvpApiException {
         String uri = "/ws.v1/lrouter/" + logicalRouterUuid + "/lport/" + logicalRouterPortUuid + "/attachment";
@@ -298,6 +304,15 @@ public class NiciraNvpApi {
     	return executeRetrieveObject(new TypeToken<NiciraNvpList<NatRule>>(){}.getType(), uri, params);
     }
     
+    public NiciraNvpList<LogicalRouterPort> findLogicalRouterPortByGatewayServiceUuid(String logicalRouterUuid, String l3GatewayServiceUuid) throws NiciraNvpApiException {
+    	String uri = "/ws.v1/lrouter/" + logicalRouterUuid + "/lport";
+    	Map<String,String> params = new HashMap<String,String>();
+    	params.put("fields", "*");
+    	params.put("attachment_gwsvc_uuid", l3GatewayServiceUuid);
+    	
+    	return executeRetrieveObject(new TypeToken<NiciraNvpList<LogicalRouterPort>>(){}.getType(), uri, params);
+    }
+    
     private <T> void executeUpdateObject(T newObject, String uri, Map<String,String> parameters) throws NiciraNvpApiException {
         String url;
         try {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/ab8ba3d6/plugins/network-elements/nicira-nvp/src/com/cloud/network/resource/NiciraNvpResource.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/resource/NiciraNvpResource.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/resource/NiciraNvpResource.java
index 83a889f..5f445fa 100644
--- a/plugins/network-elements/nicira-nvp/src/com/cloud/network/resource/NiciraNvpResource.java
+++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/resource/NiciraNvpResource.java
@@ -29,6 +29,8 @@ import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.ConfigurePortForwardingRulesOnLogicalRouterAnswer;
 import com.cloud.agent.api.ConfigurePortForwardingRulesOnLogicalRouterCommand;
+import com.cloud.agent.api.ConfigurePublicIpsOnLogicalRouterAnswer;
+import com.cloud.agent.api.ConfigurePublicIpsOnLogicalRouterCommand;
 import com.cloud.agent.api.ConfigureStaticNatRulesOnLogicalRouterAnswer;
 import com.cloud.agent.api.ConfigureStaticNatRulesOnLogicalRouterCommand;
 import com.cloud.agent.api.CreateLogicalRouterAnswer;
@@ -54,6 +56,7 @@ import com.cloud.agent.api.StartupCommand;
 import com.cloud.agent.api.StartupNiciraNvpCommand;
 import com.cloud.agent.api.UpdateLogicalSwitchPortAnswer;
 import com.cloud.agent.api.UpdateLogicalSwitchPortCommand;
+import com.cloud.agent.api.to.PortForwardingRuleTO;
 import com.cloud.agent.api.to.StaticNatRuleTO;
 import com.cloud.host.Host;
 import com.cloud.host.Host.Type;
@@ -230,7 +233,10 @@ public class NiciraNvpResource implements ServerResource {
         }
         else if (cmd instanceof ConfigurePortForwardingRulesOnLogicalRouterCommand) {
         	return executeRequest((ConfigurePortForwardingRulesOnLogicalRouterCommand) cmd, numRetries);
-        }        
+        }       
+        else if (cmd instanceof ConfigurePublicIpsOnLogicalRouterCommand) {
+        	return executeRequest((ConfigurePublicIpsOnLogicalRouterCommand) cmd, numRetries);
+        }
         s_logger.debug("Received unsupported command " + cmd.toString());
         return Answer.createUnsupportedCommandAnswer(cmd);
     }
@@ -483,9 +489,30 @@ public class NiciraNvpResource implements ServerResource {
         }
     }
     
+    private Answer executeRequest(ConfigurePublicIpsOnLogicalRouterCommand cmd, int numRetries) {
+    	try {
+    		NiciraNvpList<LogicalRouterPort> ports = _niciraNvpApi.findLogicalRouterPortByGatewayServiceUuid(cmd.getLogicalRouterUuid(), cmd.getL3GatewayServiceUuid());
+    		if (ports.getResultCount() != 1) {
+    			return new ConfigurePublicIpsOnLogicalRouterAnswer(cmd, false, "No logical router ports found, unable to set ip addresses");
+    		}
+    		LogicalRouterPort lrp = ports.getResults().get(0);
+    		lrp.setIpAddresses(cmd.getPublicCidrs());
+    		_niciraNvpApi.modifyLogicalRouterPort(cmd.getLogicalRouterUuid(), lrp);
+    		
+    		return new ConfigurePublicIpsOnLogicalRouterAnswer(cmd, true, "Logical Router deleted (uuid " + cmd.getLogicalRouterUuid() + ")");
+        } catch (NiciraNvpApiException e) {
+        	if (numRetries > 0) {
+        		return retry(cmd, --numRetries);
+        	} 
+        	else {
+        		return new ConfigurePublicIpsOnLogicalRouterAnswer(cmd, e);
+        	}
+        }
+    	
+    }
+    
     private Answer executeRequest(ConfigureStaticNatRulesOnLogicalRouterCommand cmd, int numRetries) {
     	try {
-    		LogicalRouterConfig lrc = _niciraNvpApi.findOneLogicalRouterByUuid(cmd.getLogicalRouterUuid());
     		NiciraNvpList<NatRule> existingRules = _niciraNvpApi.findNatRulesByLogicalRouterUuid(cmd.getLogicalRouterUuid());
     		// Rules of the game (also known as assumptions-that-will-make-stuff-break-later-on)
     		// A SourceNat rule with a match other than a /32 cidr is assumed to be the "main" SourceNat rule
@@ -493,7 +520,6 @@ public class NiciraNvpResource implements ServerResource {
     		
     		for (StaticNatRuleTO rule : cmd.getRules()) {
     			// Find if a DestinationNat rule exists for this rule
-    			boolean found = false;
 				String insideIp = rule.getDstIp();
 				String insideCidr = rule.getDstIp() + "/32";
 				String outsideIp = rule.getSrcIp();
@@ -605,10 +631,7 @@ public class NiciraNvpResource implements ServerResource {
 					newDnatRule.setToDestinationIpAddressMin(insideIp);
 					newDnatRule.setToDestinationIpAddressMax(insideIp);
 					newDnatRule = (DestinationNatRule) _niciraNvpApi.createLogicalRouterNatRule(cmd.getLogicalRouterUuid(), newDnatRule);
-					s_logger.debug("Created " + newDnatRule.getType() + " rule " 
-							+ newDnatRule.getUuid() + ", " 
-							+ newDnatRule.getMatch().getDestinationIpAddresses() 
-							+ " -> " + newDnatRule.getToDestinationIpAddressMin());
+					s_logger.debug("Created " + natRuleToString(newDnatRule));
 
 					// create matching snat rule
 					m = new Match();
@@ -618,10 +641,7 @@ public class NiciraNvpResource implements ServerResource {
 					newSnatRule.setToSourceIpAddressMin(outsideIp);
 					newSnatRule.setToSourceIpAddressMax(outsideIp);
 					newSnatRule = (SourceNatRule) _niciraNvpApi.createLogicalRouterNatRule(cmd.getLogicalRouterUuid(), newSnatRule);
-					s_logger.debug("Created " + newSnatRule.getType() + " rule " 
-							+ newSnatRule.getUuid() + ", " 
-							+ newSnatRule.getMatch().getSourceIpAddresses() + " -> " 
-							+ newSnatRule.getToSourceIpAddressMin());
+					s_logger.debug("Created " + natRuleToString(newSnatRule));
 					
 				}
     		}
@@ -639,8 +659,120 @@ public class NiciraNvpResource implements ServerResource {
 
     private Answer executeRequest(ConfigurePortForwardingRulesOnLogicalRouterCommand cmd, int numRetries) {
     	try {
-    		LogicalRouterConfig lrc = _niciraNvpApi.findOneLogicalRouterByUuid(cmd.getLogicalRouterUuid());
-    		//FIXME implement!
+    		NiciraNvpList<NatRule> existingRules = _niciraNvpApi.findNatRulesByLogicalRouterUuid(cmd.getLogicalRouterUuid());
+    		// Rules of the game (also known as assumptions-that-will-make-stuff-break-later-on)
+    		// A SourceNat rule with a match other than a /32 cidr is assumed to be the "main" SourceNat rule
+    		// Any other SourceNat rule should have a corresponding DestinationNat rule
+    		
+    		for (PortForwardingRuleTO rule : cmd.getRules()) {
+    			if (rule.isAlreadyAdded()) {
+    				// Don't need to do anything
+    				continue;
+    			}
+    			
+    			// Find if a DestinationNat rule exists for this rule
+				String insideIp = rule.getDstIp();
+				String insideCidr = rule.getDstIp() + "/32";
+				String outsideIp = rule.getSrcIp();
+				String outsideCidr = rule.getSrcIp() + "/32";
+				
+				NatRule incoming = null;
+				NatRule outgoing = null;
+
+				for (NatRule storedRule : existingRules.getResults()) {
+    				if ("SourceNatRule".equals(storedRule.getType())) {
+    					if (outsideIp.equals(storedRule.getToSourceIpAddressMin()) && 
+    							outsideIp.equals(storedRule.getToSourceIpAddressMax()) &&
+    							storedRule.getToSourcePortMin() == rule.getSrcPortRange()[0] &&
+    							storedRule.getToSourcePortMax() == rule.getSrcPortRange()[1]) {
+        					// The outgoing rule exists
+        					outgoing = storedRule;
+        				}    					
+    				}
+    				else if ("DestinationNatRule".equals(storedRule.getType())) {
+    					if (insideIp.equals(storedRule.getToDestinationIpAddressMin()) && 
+    							insideIp.equals(storedRule.getToDestinationIpAddressMax()) &&
+    							storedRule.getToDestinationPort() == rule.getDstPortRange()[0]) {
+        					// The incoming rule exists
+        					incoming = storedRule;
+        				}    					
+    				}
+				}
+				if (incoming != null && outgoing != null) {
+					if (insideIp.equals(incoming.getToDestinationIpAddressMin())) {
+						if (rule.revoked()) {
+							s_logger.debug("Deleting incoming rule " + incoming.getUuid());
+							_niciraNvpApi.deleteLogicalRouterNatRule(cmd.getLogicalRouterUuid(), incoming.getUuid());
+							
+							s_logger.debug("Deleting outgoing rule " + outgoing.getUuid());
+							_niciraNvpApi.deleteLogicalRouterNatRule(cmd.getLogicalRouterUuid(), outgoing.getUuid());
+						}
+					}
+					else {
+						s_logger.debug("Updating outgoing rule " + outgoing.getUuid());
+						outgoing.setToDestinationIpAddressMin(insideIp);
+						outgoing.setToDestinationIpAddressMax(insideIp);
+						outgoing.setToDestinationPort(rule.getDstPortRange()[0]);
+						_niciraNvpApi.modifyLogicalRouterNatRule(cmd.getLogicalRouterUuid(), outgoing);
+
+						s_logger.debug("Updating incoming rule " + outgoing.getUuid());
+						incoming.setToSourceIpAddressMin(insideIp);
+						incoming.setToSourceIpAddressMax(insideIp);
+						incoming.setToSourcePortMin(rule.getSrcPortRange()[0]);
+						incoming.setToSourcePortMax(rule.getSrcPortRange()[1]);
+						_niciraNvpApi.modifyLogicalRouterNatRule(cmd.getLogicalRouterUuid(), incoming);
+						break;
+					}
+				}
+				else {
+					if (rule.revoked()) {
+						s_logger.warn("Tried deleting a rule that does not exist, " + 
+								rule.getSrcIp() + " -> " + rule.getDstIp());
+						break;
+					}
+					
+					// api createLogicalRouterNatRule
+					// create the dnat rule
+					Match m = new Match();
+					m.setDestinationIpAddresses(outsideCidr);
+					if ("tcp".equals(rule.getProtocol())) {
+						m.setProtocol(6);
+					}
+					else if ("udp".equals(rule.getProtocol())) {
+						m.setProtocol(17);
+					}
+					m.setDestinationPortMin(rule.getSrcPortRange()[0]);
+					m.setDestinationPortMax(rule.getSrcPortRange()[1]);
+					DestinationNatRule newDnatRule = new DestinationNatRule();
+					newDnatRule.setMatch(m);
+					newDnatRule.setToDestinationIpAddressMin(insideIp);
+					newDnatRule.setToDestinationIpAddressMax(insideIp);
+					newDnatRule.setToDestinationPort(rule.getDstPortRange()[0]);
+					newDnatRule = (DestinationNatRule) _niciraNvpApi.createLogicalRouterNatRule(cmd.getLogicalRouterUuid(), newDnatRule);
+					s_logger.debug("Created " + natRuleToString(newDnatRule));
+					
+					// create matching snat rule
+					m = new Match();
+					m.setSourceIpAddresses(insideIp + "/32");
+					if ("tcp".equals(rule.getProtocol())) {
+						m.setProtocol(6);
+					}
+					else if ("udp".equals(rule.getProtocol())) {
+						m.setProtocol(17);
+					}
+					m.setSourcePortMin(rule.getDstPortRange()[0]);
+					m.setSourcePortMax(rule.getDstPortRange()[1]);
+					SourceNatRule newSnatRule = new SourceNatRule();
+					newSnatRule.setMatch(m);
+					newSnatRule.setToSourceIpAddressMin(outsideIp);
+					newSnatRule.setToSourceIpAddressMax(outsideIp);
+					newSnatRule.setToSourcePortMin(rule.getSrcPortRange()[0]);
+					newSnatRule.setToSourcePortMax(rule.getSrcPortRange()[1]);
+					newSnatRule = (SourceNatRule) _niciraNvpApi.createLogicalRouterNatRule(cmd.getLogicalRouterUuid(), newSnatRule);
+					s_logger.debug("Created " + natRuleToString(newSnatRule));
+					
+				}
+    		}
     		return new ConfigurePortForwardingRulesOnLogicalRouterAnswer(cmd, true, cmd.getRules().size() +" PortForwarding rules applied");
         } catch (NiciraNvpApiException e) {
         	if (numRetries > 0) {
@@ -667,4 +799,49 @@ public class NiciraNvpResource implements ServerResource {
         return executeRequest(cmd, numRetriesRemaining);
     }
     
+    private String natRuleToString(NatRule rule) {
+    	
+		StringBuilder natRuleStr = new StringBuilder();
+		natRuleStr.append("Rule ");
+		natRuleStr.append(rule.getUuid());
+		natRuleStr.append(" (");
+		natRuleStr.append(rule.getType());
+		natRuleStr.append(") :");
+		Match m = rule.getMatch();
+		natRuleStr.append("match (");
+		natRuleStr.append(m.getProtocol());
+		natRuleStr.append(" ");
+		natRuleStr.append(m.getSourceIpAddresses());
+		natRuleStr.append(" [");
+		natRuleStr.append(m.getSource_port_min());
+		natRuleStr.append("-");
+		natRuleStr.append(m.getSourcePortMax());
+		natRuleStr.append(" ] -> ");
+		natRuleStr.append(m.getDestinationIpAddresses());
+		natRuleStr.append(" [");
+		natRuleStr.append(m.getDestinationPortMin());
+		natRuleStr.append("-");
+		natRuleStr.append(m.getDestinationPortMax());
+		natRuleStr.append(" ]) -->");
+		if ("SourceNatRule".equals(rule.getType())) {
+			natRuleStr.append(rule.getToSourceIpAddressMin());
+			natRuleStr.append("-");
+			natRuleStr.append(rule.getToSourceIpAddressMax());
+			natRuleStr.append(" [");
+			natRuleStr.append(rule.getToSourcePortMin());
+			natRuleStr.append("-");
+			natRuleStr.append(rule.getToSourcePortMax());
+			natRuleStr.append(" ])");
+		}
+		else {
+			natRuleStr.append(rule.getToDestinationIpAddressMin());
+			natRuleStr.append("-");
+			natRuleStr.append(rule.getToDestinationIpAddressMax());
+			natRuleStr.append(" [");
+			natRuleStr.append(rule.getToDestinationPort());
+			natRuleStr.append(" ])");
+		}
+		return natRuleStr.toString();
+    }    	
+    
 }