You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by bh...@apache.org on 2013/01/05 07:22:03 UTC

[1/6] git commit: CLOUDSTACK-306: Implement SRX firewall

CLOUDSTACK-306: Implement SRX firewall

Use SRX firewall filter as SRX firewall. The old security policy mechanism
cannot be used as IP based. This would enable SRX's ability to control traffic
for F5 behind it.


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

Branch: refs/heads/api_refactoring
Commit: 717f9dcd4d25e2a3ccf12598d16cc5d81fd880a9
Parents: c7563cb
Author: Sheng Yang <sh...@citrix.com>
Authored: Fri Jan 4 18:56:47 2013 -0800
Committer: Sheng Yang <sh...@citrix.com>
Committed: Fri Jan 4 19:17:50 2013 -0800

----------------------------------------------------------------------
 api/src/com/cloud/agent/api/to/FirewallRuleTO.java |    1 +
 .../com/cloud/agent/api/to/StaticNatRuleTO.java    |    5 +
 .../element/JuniperSRXExternalFirewallElement.java |    2 +-
 .../cloud/network/resource/JuniperSrxResource.java |  239 ++++++++++++++-
 .../network/juniper/firewall-filter-term-add.xml   |   25 ++
 .../juniper/firewall-filter-term-getone.xml        |   14 +
 scripts/network/juniper/template-entry.xml         |    3 +
 .../network/ExternalFirewallDeviceManager.java     |    9 +
 .../network/ExternalFirewallDeviceManagerImpl.java |  185 ++++++++++--
 9 files changed, 443 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/717f9dcd/api/src/com/cloud/agent/api/to/FirewallRuleTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java
index 0186020..8ce3def 100644
--- a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java
+++ b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java
@@ -58,6 +58,7 @@ public class FirewallRuleTO {
        this(id,null,srcIp,protocol,srcPortStart,srcPortEnd,revoked,alreadyAdded,purpose,sourceCidr,icmpType,icmpCode);
     } 
     public FirewallRuleTO(long id,String srcVlanTag, String srcIp, String protocol, Integer srcPortStart, Integer srcPortEnd, boolean revoked, boolean alreadyAdded, FirewallRule.Purpose purpose, List<String> sourceCidr,Integer icmpType,Integer icmpCode) {
+        this.id = id;
         this.srcVlanTag = srcVlanTag;
         this.srcIp = srcIp;
         this.protocol = protocol;

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/717f9dcd/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java
index fd77dd6..6f60014 100644
--- a/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java
+++ b/api/src/com/cloud/agent/api/to/StaticNatRuleTO.java
@@ -47,6 +47,11 @@ public class StaticNatRuleTO extends FirewallRuleTO{
         super(id, srcIp, protocol, srcPortStart, srcPortEnd, revoked, alreadyAdded, FirewallRule.Purpose.StaticNat, null,0,0);
         this.dstIp = dstIp;
     }
+    
+    public StaticNatRuleTO(long id,String srcVlanTag, String srcIp, Integer srcPortStart, Integer srcPortEnd, String dstIp, Integer dstPortStart, Integer dstPortEnd, String protocol, boolean revoked, boolean alreadyAdded) {
+        super(id, srcVlanTag, srcIp, protocol, srcPortStart, srcPortEnd, revoked, alreadyAdded, FirewallRule.Purpose.StaticNat, null,0,0);
+        this.dstIp = dstIp;
+    }
 
     public String getDstIp() {
         return dstIp;

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/717f9dcd/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java
index 95bc031..50c088c 100644
--- a/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java
+++ b/plugins/network-elements/juniper-srx/src/com/cloud/network/element/JuniperSRXExternalFirewallElement.java
@@ -268,7 +268,7 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan
 
         // Set capabilities for Firewall service
         Map<Capability, String> firewallCapabilities = new HashMap<Capability, String>();
-        firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp");
+        firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp");
         firewallCapabilities.put(Capability.MultipleIps, "true");
         firewallCapabilities.put(Capability.TrafficStatistics, "per public ip");
         capabilities.put(Service.Firewall, firewallCapabilities);

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/717f9dcd/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java b/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java
index ebb3de6..f823ab8 100644
--- a/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java
+++ b/plugins/network-elements/juniper-srx/src/com/cloud/network/resource/JuniperSrxResource.java
@@ -55,6 +55,7 @@ import com.cloud.agent.api.routing.IpAssocAnswer;
 import com.cloud.agent.api.routing.IpAssocCommand;
 import com.cloud.agent.api.routing.NetworkElementCommand;
 import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand;
+import com.cloud.agent.api.routing.SetFirewallRulesCommand;
 import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
 import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
 import com.cloud.agent.api.routing.VpnUsersCfgCommand;
@@ -64,6 +65,7 @@ import com.cloud.agent.api.to.IpAddressTO;
 import com.cloud.agent.api.to.PortForwardingRuleTO;
 import com.cloud.agent.api.to.StaticNatRuleTO;
 import com.cloud.host.Host;
+import com.cloud.network.rules.FirewallRule;
 import com.cloud.network.rules.FirewallRule.Purpose;
 import com.cloud.resource.ServerResource;
 import com.cloud.utils.NumbersUtil;
@@ -75,7 +77,6 @@ public class JuniperSrxResource implements ServerResource {
 
     private String _name;
     private String _zoneId;
-    private String _physicalNetworkId;
     private String _ip;
     private String _username;
     private String _password;
@@ -89,6 +90,7 @@ public class JuniperSrxResource implements ServerResource {
     private Integer _timeoutInSeconds;
     private String _publicZone;
     private String _privateZone;
+    private String _publicZoneInputFilterName;
     private String _publicInterface;
     private String _usageInterface;
     private String _privateInterface;
@@ -159,6 +161,9 @@ public class JuniperSrxResource implements ServerResource {
         ACCESS_PROFILE_ADD("access-profile-add.xml"),
         ACCESS_PROFILE_GETONE("access-profile-getone.xml"),
         ACCESS_PROFILE_GETALL("access-profile-getall.xml"),
+        FIREWALL_FILTER_TERM_ADD("firewall-filter-term-add.xml"),
+        FIREWALL_FILTER_TERM_GETONE("firewall-filter-term-getone.xml"),
+        TEMPLATE_ENTRY("template-entry.xml"),
         OPEN_CONFIGURATION("open-configuration.xml"),
         CLOSE_CONFIGURATION("close-configuration.xml"),
         COMMIT("commit.xml"), 
@@ -231,12 +236,74 @@ public class JuniperSrxResource implements ServerResource {
         }
     }	
 
+    public class FirewallFilterTerm {
+        private String name;
+        private List<String> sourceCidrs;
+        private String destIp;
+        private String portRange;
+        private String protocol;
+        private String icmpType;
+        private String icmpCode;
+        private String countName;
+        
+        private FirewallFilterTerm(String name, List<String> sourceCidrs, String destIp, String protocol, Integer startPort, Integer endPort,
+                Integer icmpType, Integer icmpCode, String countName) {
+            this.name = name;
+            this.sourceCidrs = sourceCidrs;
+            this.destIp = destIp;
+            this.protocol = protocol;
+            
+            if (protocol.equals("tcp") || protocol.equals("udp")) {
+                this.portRange = String.valueOf(startPort) + "-" + String.valueOf(endPort);
+            } else if (protocol.equals("icmp")) {
+                this.icmpType = String.valueOf(icmpType);
+                this.icmpCode = String.valueOf(icmpCode);
+            } else {
+                assert protocol.equals("any");
+            }
+            this.countName = countName;
+            
+        }
+
+        public String getName() {
+            return name;
+        }
+        
+        public List<String> getSourceCidrs() {
+            return sourceCidrs;
+        }
+        
+        public String getDestIp() {
+            return destIp;
+        }
+        
+        public String getPortRange() {
+            return portRange;
+        }
+        
+        public String getProtocol() {
+            return protocol;
+        }
+        
+        public String getIcmpType() {
+            return icmpType;
+        }
+        
+        public String getIcmpCode() {
+            return icmpCode;
+        }
+        
+        public String getCountName() {
+            return countName;
+        }
+    }	
+
     private enum SrxCommand {
         LOGIN, OPEN_CONFIGURATION, CLOSE_CONFIGURATION, COMMIT, ROLLBACK, CHECK_IF_EXISTS, CHECK_IF_IN_USE, ADD, DELETE, GET_ALL;
     }
 
     private enum Protocol {
-        tcp, udp, any;
+        tcp, udp, icmp, any;
     }
 
     private enum RuleMatchCondition {
@@ -277,6 +344,8 @@ public class JuniperSrxResource implements ServerResource {
             return execute((SetStaticNatRulesCommand) cmd);
         } else if (cmd instanceof SetPortForwardingRulesCommand) {
             return execute((SetPortForwardingRulesCommand) cmd);
+        } else if (cmd instanceof SetFirewallRulesCommand) {
+            return execute((SetFirewallRulesCommand) cmd);
         } else if (cmd instanceof ExternalNetworkResourceUsageCommand) {
             return execute((ExternalNetworkResourceUsageCommand) cmd);
         } else if (cmd instanceof RemoteAccessVpnCfgCommand) {
@@ -300,11 +369,6 @@ public class JuniperSrxResource implements ServerResource {
                 throw new ConfigurationException("Unable to find zone");
             }
 
-            _physicalNetworkId = (String) params.get("physicalNetworkId");
-            if (_physicalNetworkId == null) {
-                throw new ConfigurationException("Unable to find physical network id in the configuration parameters");
-            }
-
             _ip = (String) params.get("ip");
             if (_ip == null) {
                 throw new ConfigurationException("Unable to find IP");
@@ -325,8 +389,6 @@ public class JuniperSrxResource implements ServerResource {
                 throw new ConfigurationException("Unable to find public interface.");
             }
 
-            _usageInterface = (String) params.get("usageinterface");
-
             _privateInterface = (String) params.get("privateinterface");
             if (_privateInterface == null) {
                 throw new ConfigurationException("Unable to find private interface.");
@@ -364,6 +426,8 @@ public class JuniperSrxResource implements ServerResource {
                 throw new ConfigurationException("Unable to open a connection to the SRX.");
             }
 
+            _publicZoneInputFilterName = _publicZone;
+            
             _usageFilterVlanInput = new UsageFilter("vlan-input", null, "vlan-input");
             _usageFilterVlanOutput = new UsageFilter("vlan-output", null, "vlan-output");
             _usageFilterIPInput = new UsageFilter(_publicZone, "destination-address", "-i");
@@ -712,6 +776,50 @@ public class JuniperSrxResource implements ServerResource {
         s_logger.debug(msg);
     }
 
+
+    /* security policies */
+    private synchronized Answer execute(SetFirewallRulesCommand cmd) {
+        refreshSrxConnection();
+        return execute(cmd, _numRetries);
+    }
+    
+    private Answer execute(SetFirewallRulesCommand cmd, int numRetries) {
+        FirewallRuleTO[] rules = cmd.getRules();
+        try {
+            openConfiguration();
+
+            for (FirewallRuleTO rule : rules) {
+                int startPort = 0, endPort = 0;
+                if (rule.getSrcPortRange() != null) {
+                    startPort = rule.getSrcPortRange()[0];
+                    endPort = rule.getSrcPortRange()[1];
+                }
+                FirewallFilterTerm term = new FirewallFilterTerm(genIpIdentifier(rule.getSrcIp()) + "-" + String.valueOf(rule.getId()), rule.getSourceCidrList(), 
+                        rule.getSrcIp(), rule.getProtocol(), startPort, endPort,
+                        rule.getIcmpType(), rule.getIcmpCode(), genIpIdentifier(rule.getSrcIp()) + _usageFilterIPInput.getCounterIdentifier());
+                if (!rule.revoked()) {
+                    manageFirewallFilter(SrxCommand.ADD, term, _publicZoneInputFilterName);
+                } else {
+                    manageFirewallFilter(SrxCommand.DELETE, term, _publicZoneInputFilterName);
+                }
+            }
+                
+            commitConfiguration();
+            return new Answer(cmd);
+        } catch (ExecutionException e) {
+            s_logger.error(e);
+            closeConfiguration();
+
+            if (numRetries > 0 && refreshSrxConnection()) {
+                int numRetriesRemaining = numRetries - 1;
+                s_logger.debug("Retrying SetFirewallRulesCommand. Number of retries remaining: " + numRetriesRemaining);
+                return execute(cmd, numRetriesRemaining);
+            } else {
+                return new Answer(cmd, e);
+            }
+        }
+    }
+
     /*
      * Static NAT
      */
@@ -766,7 +874,6 @@ public class JuniperSrxResource implements ServerResource {
     private void addStaticNatRule(Long publicVlanTag, String publicIp, String privateIp, List<FirewallRuleTO> rules) throws ExecutionException {
         manageProxyArp(SrxCommand.ADD, publicVlanTag, publicIp);
         manageStaticNatRule(SrxCommand.ADD, publicIp, privateIp);
-        manageUsageFilter(SrxCommand.ADD, _usageFilterIPInput, publicIp, null, genIpFilterTermName(publicIp));		
         manageAddressBookEntry(SrxCommand.ADD, _privateZone, privateIp, null);
 
         // Add a new security policy with the current set of applications
@@ -778,7 +885,6 @@ public class JuniperSrxResource implements ServerResource {
     private void removeStaticNatRule(Long publicVlanTag, String publicIp, String privateIp) throws ExecutionException {	    
         manageStaticNatRule(SrxCommand.DELETE, publicIp, privateIp);
         manageProxyArp(SrxCommand.DELETE, publicVlanTag, publicIp);   
-        manageUsageFilter(SrxCommand.DELETE, _usageFilterIPInput, publicIp, null, genIpFilterTermName(publicIp));
 
         // Remove any existing security policy and clean up applications
         removeSecurityPolicyAndApplications(SecurityPolicyType.STATIC_NAT, privateIp);
@@ -2781,6 +2887,108 @@ public class JuniperSrxResource implements ServerResource {
         }
     }	
 
+    private String genNameValueEntry(String name, String value) {
+        String xml = SrxXml.TEMPLATE_ENTRY.getXml();
+        xml = replaceXmlValue(xml, "name", name);
+        xml = replaceXmlValue(xml, "value", value);
+        return xml;
+    }
+    
+    private String genMultipleEntries(String name, List<String> values) {
+        String result = "";
+        for (String value : values) {
+            result = result + genNameValueEntry(name, value);
+        }
+        return result;
+    }
+    
+    private String genPortRangeEntry(String protocol, String portRange) {
+        String result = "";
+        result = result + genNameValueEntry("protocol", protocol);
+        result = result + genNameValueEntry("destination-port", portRange);
+        return result;
+    }
+    
+    private String genIcmpEntries(String icmpType, String icmpCode) {
+        String result = "";
+        result = result + genNameValueEntry("protocol", "icmp");
+        if (icmpType.equals("-1")) {
+            result = result + genNameValueEntry("icmp-type", "0-255");
+        } else {
+            result = result + genNameValueEntry("icmp-type", icmpType);
+        }
+        if (icmpCode.equals("-1")) {
+            result = result + genNameValueEntry("icmp-code", "0-255");
+        } else {
+            result = result + genNameValueEntry("icmp-code", icmpCode);
+        }
+        return result;
+    }
+    
+    private boolean manageFirewallFilter(SrxCommand command, FirewallFilterTerm term, String filterName) throws ExecutionException {	    	    
+        String xml;
+
+        switch(command) {
+
+        case CHECK_IF_EXISTS:
+            xml = SrxXml.FIREWALL_FILTER_TERM_GETONE.getXml();
+            xml = setDelete(xml, false);
+            xml = replaceXmlValue(xml, "filter-name", filterName);
+            xml = replaceXmlValue(xml, "term-name", term.getName());
+            return sendRequestAndCheckResponse(command, xml, "name", term.getName());
+
+        case ADD:	
+            if (manageFirewallFilter(SrxCommand.CHECK_IF_EXISTS, term, filterName)) {
+                return true;
+            }
+
+            xml = SrxXml.FIREWALL_FILTER_TERM_ADD.getXml();
+            
+            xml = replaceXmlValue(xml, "filter-name", filterName);
+            xml = replaceXmlValue(xml, "term-name", term.getName());
+            xml = replaceXmlValue(xml, "source-address-entries", genMultipleEntries("source-address", term.getSourceCidrs()));
+            xml = replaceXmlValue(xml, "dest-ip-address", term.getDestIp());
+            
+            String protocol = term.getProtocol();
+            if (protocol.equals("tcp") || protocol.equals("udp")) {
+                xml = replaceXmlValue(xml, "protocol-options", genPortRangeEntry(protocol, term.getPortRange()));
+            } else if (protocol.equals("icmp")) {
+                xml = replaceXmlValue(xml, "protocol-options", genIcmpEntries(term.getIcmpType(), term.getIcmpCode()));
+            } else {
+                assert protocol.equals("any");
+                xml = replaceXmlValue(xml, "protocol-options", "");
+            }
+            xml = replaceXmlValue(xml, "count-name", term.getCountName());
+
+            if (!sendRequestAndCheckResponse(command, xml)) {
+                throw new ExecutionException("Failed to add firewall filter: " + term.getName());
+            } else {
+                return true;
+            }
+
+        case DELETE:
+            if (!manageFirewallFilter(SrxCommand.CHECK_IF_EXISTS, term, filterName)) {
+                return true;
+            }
+
+            xml = SrxXml.FIREWALL_FILTER_TERM_GETONE.getXml();
+            xml = setDelete(xml, true);
+            xml = replaceXmlValue(xml, "filter-name", filterName);
+            xml = replaceXmlValue(xml, "term-name", term.getName());
+
+            if (!sendRequestAndCheckResponse(command, xml)) {
+                throw new ExecutionException("Failed to delete firewall filter: " + term.getName());
+            } else {
+                return true;
+            }
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+
+        }
+    }	
+
     /*
      * Usage	
      */
@@ -2913,6 +3121,10 @@ public class JuniperSrxResource implements ServerResource {
         }	    	    
 
         UsageFilter filter = getUsageFilter(counterName);	    
+        if (filter == null) {
+            s_logger.debug("Failed to parse counter name in usage answer: " + counterName);
+            return;
+        }
         String usageAnswerKey = getUsageAnswerKey(filter, counterName);	    
         Map<String, long[]> bytesMap = getBytesMap(answer, filter, usageAnswerKey);
         updateBytesMap(bytesMap, filter, usageAnswerKey, byteCount);          
@@ -2981,6 +3193,11 @@ public class JuniperSrxResource implements ServerResource {
     }
 
     private boolean checkResponse(String xmlResponse, boolean errorKeyAndValue, String key, String value) {
+        if (xmlResponse == null) {
+            s_logger.error("Failed to communicate with SRX!");
+            return false;
+        }
+
         if (!xmlResponse.contains("authentication-response")) {
             s_logger.debug("Checking response: " + xmlResponse);
         } else {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/717f9dcd/scripts/network/juniper/firewall-filter-term-add.xml
----------------------------------------------------------------------
diff --git a/scripts/network/juniper/firewall-filter-term-add.xml b/scripts/network/juniper/firewall-filter-term-add.xml
new file mode 100644
index 0000000..4f96ed4
--- /dev/null
+++ b/scripts/network/juniper/firewall-filter-term-add.xml
@@ -0,0 +1,25 @@
+<rpc>
+<load-configuration>
+<configuration>
+<firewall>
+<filter>
+<name>%filter-name%</name>
+<term>
+<name>%term-name%</name>
+<from>
+%source-address-entries%
+<destination-address>
+<name>%dest-ip-address%</name>
+</destination-address>
+%protocol-options%
+</from>
+<then>
+<count>%count-name%</count>
+<accept/>
+</then>
+</term>
+</filter>
+</firewall>
+</configuration>
+</load-configuration>
+</rpc>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/717f9dcd/scripts/network/juniper/firewall-filter-term-getone.xml
----------------------------------------------------------------------
diff --git a/scripts/network/juniper/firewall-filter-term-getone.xml b/scripts/network/juniper/firewall-filter-term-getone.xml
new file mode 100644
index 0000000..7822909
--- /dev/null
+++ b/scripts/network/juniper/firewall-filter-term-getone.xml
@@ -0,0 +1,14 @@
+<rpc>
+<load-configuration>
+<configuration>
+<firewall>
+<filter>
+<name>%filter-name%</name>
+<term %delete%>
+<name>%term-name%</name>
+</term>
+</filter>
+</firewall>
+</configuration>
+</load-configuration>
+</rpc>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/717f9dcd/scripts/network/juniper/template-entry.xml
----------------------------------------------------------------------
diff --git a/scripts/network/juniper/template-entry.xml b/scripts/network/juniper/template-entry.xml
new file mode 100644
index 0000000..cf0cb6c
--- /dev/null
+++ b/scripts/network/juniper/template-entry.xml
@@ -0,0 +1,3 @@
+<%name%>
+<name>%value%</name>
+</%name%>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/717f9dcd/server/src/com/cloud/network/ExternalFirewallDeviceManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/ExternalFirewallDeviceManager.java b/server/src/com/cloud/network/ExternalFirewallDeviceManager.java
index f6a39d9..f758ca1 100644
--- a/server/src/com/cloud/network/ExternalFirewallDeviceManager.java
+++ b/server/src/com/cloud/network/ExternalFirewallDeviceManager.java
@@ -22,6 +22,7 @@ import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.host.Host;
 import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.PortForwardingRule;
 import com.cloud.resource.ServerResource;
 import com.cloud.utils.component.Manager;
 
@@ -94,4 +95,12 @@ public interface ExternalFirewallDeviceManager extends Manager {
      */
     public boolean manageGuestNetworkWithExternalFirewall(boolean add, Network guestConfig) throws ResourceUnavailableException, InsufficientCapacityException;
 
+    /**
+     * applies port forwarding rules
+     * @param network guest network if
+     * @param rules load balancer rules
+     * @return true if successfully applied rules
+     * @throws ResourceUnavailableException
+     */
+    public boolean applyPortForwardingRules(Network network, List<? extends PortForwardingRule> rules) throws ResourceUnavailableException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/717f9dcd/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java
index 1629dd5..4b67840 100644
--- a/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java
+++ b/server/src/com/cloud/network/ExternalFirewallDeviceManagerImpl.java
@@ -34,9 +34,11 @@ import com.cloud.agent.api.StartupExternalLoadBalancerCommand;
 import com.cloud.agent.api.routing.IpAssocCommand;
 import com.cloud.agent.api.routing.NetworkElementCommand;
 import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand;
+import com.cloud.agent.api.routing.SetFirewallRulesCommand;
 import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
 import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
 import com.cloud.agent.api.routing.VpnUsersCfgCommand;
+import com.cloud.agent.api.to.FirewallRuleTO;
 import com.cloud.agent.api.to.IpAddressTO;
 import com.cloud.agent.api.to.PortForwardingRuleTO;
 import com.cloud.agent.api.to.StaticNatRuleTO;
@@ -65,6 +67,7 @@ import com.cloud.network.Network.Capability;
 import com.cloud.network.Network.Service;
 import com.cloud.network.Networks.TrafficType;
 import com.cloud.network.dao.ExternalFirewallDeviceDao;
+import com.cloud.network.dao.FirewallRulesDao;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.InlineLoadBalancerNicMapDao;
 import com.cloud.network.dao.LoadBalancerDao;
@@ -78,14 +81,17 @@ import com.cloud.network.dao.VpnUserDao;
 import com.cloud.network.rules.FirewallRule;
 import com.cloud.network.rules.FirewallRule.Purpose;
 import com.cloud.network.rules.PortForwardingRule;
+import com.cloud.network.rules.StaticNat;
 import com.cloud.network.rules.StaticNatRule;
 import com.cloud.network.rules.dao.PortForwardingRulesDao;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.offerings.dao.NetworkOfferingDao;
 import com.cloud.resource.ResourceManager;
+import com.cloud.resource.ResourceState;
 import com.cloud.resource.ResourceStateAdapter;
 import com.cloud.resource.ServerResource;
 import com.cloud.resource.UnableDeleteHostException;
+import com.cloud.resource.ResourceStateAdapter.DeleteHostAnswer;
 import com.cloud.server.api.response.ExternalFirewallResponse;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
@@ -98,6 +104,7 @@ import com.cloud.utils.db.DB;
 import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.db.Transaction;
 import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.Ip;
 import com.cloud.utils.net.NetUtils;
 import com.cloud.utils.net.UrlUtil;
 import com.cloud.vm.Nic.ReservationStrategy;
@@ -133,6 +140,7 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
     @Inject NetworkExternalFirewallDao _networkExternalFirewallDao;
     @Inject VpnUserDao _vpnUsersDao;
     @Inject HostDetailsDao _hostDetailDao;
+    @Inject FirewallRulesDao _fwRulesDao;
 
     private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalFirewallDeviceManagerImpl.class);
     private long _defaultFwCapacity;
@@ -236,14 +244,26 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
             throw new InvalidParameterValueException("Could not find an external firewall with ID: " + hostId);
         }
 
+        DetailVO fwHostDetails = _hostDetailDao.findDetail(hostId, ApiConstants.FIREWALL_DEVICE_ID);
+        long fwDeviceId = Long.parseLong(fwHostDetails.getValue());
+
+        // check if any networks are using this balancer device
+        List<NetworkExternalFirewallVO> networks = _networkExternalFirewallDao.listByFirewallDeviceId(fwDeviceId);
+        if ((networks != null) && !networks.isEmpty()) {
+            throw new CloudRuntimeException("Delete can not be done as there are networks using the firewall device ");
+        }
+
         try {
-            if (_resourceMgr.maintain(hostId) && _resourceMgr.deleteHost(hostId, false, false)) {
-                return true;
-            } else {
-                return false;
-            }
-        } catch (AgentUnavailableException e) {
-            s_logger.debug(e);
+            // put the host in maintenance state in order for it to be deleted
+            externalFirewall.setResourceState(ResourceState.Maintenance);
+            _hostDao.update(hostId, externalFirewall);
+            _resourceMgr.deleteHost(hostId, false, false);
+
+            // delete the external load balancer entry
+            _externalFirewallDeviceDao.remove(fwDeviceId);
+            return true;
+        } catch (Exception e) {
+            s_logger.debug("Failed to delete external firewall device due to " + e.getMessage());
             return false;
         }
     }
@@ -316,6 +336,32 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
                 " to implement the network", DataCenter.class, network.getDataCenterId());
     }
 
+    @DB
+    protected boolean freeFirewallForNetwork(Network network) {
+        Transaction txn = Transaction.currentTxn();
+        GlobalLock deviceMapLock =  GlobalLock.getInternLock("NetworkFirewallDeviceMap");
+        try {
+            if (deviceMapLock.lock(120)) {
+                try {
+                    NetworkExternalFirewallVO fwDeviceForNetwork = _networkExternalFirewallDao.findByNetworkId(network.getId());
+                    if (fwDeviceForNetwork != null) {
+                        _networkExternalFirewallDao.remove(fwDeviceForNetwork.getId());
+                    }
+                } catch (Exception exception) {
+                    txn.rollback();
+                    s_logger.error("Failed to release firewall device for the network" + network.getId() + " due to " + exception.getMessage());
+                    return false;
+                } finally {
+                    deviceMapLock.unlock();
+                }
+            }
+        } finally {
+            deviceMapLock.releaseRef();
+        }
+        txn.commit();
+        return true;
+    }
+
     public String getExternalNetworkResourceGuid(long physicalNetworkId, String deviceName, String ip) {
         return physicalNetworkId + "-" + deviceName + "-" + ip;
     }
@@ -422,15 +468,21 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
         cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag));
         Answer answer = _agentMgr.easySend(externalFirewall.getId(), cmd);
 
+        List<String> reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(network.getId());
+        
         if (answer == null || !answer.getResult()) {
             String action = add ? "implement" : "shutdown";
             String answerDetails = (answer != null) ? answer.getDetails() : "answer was null";
             String msg = "External firewall was unable to " + action + " the guest network on the external firewall in zone " + zone.getName() + " due to " + answerDetails;
             s_logger.error(msg);
+            if (!add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) {
+                // If we failed the implementation as well, then just return, no complain
+                s_logger.error("Skip the shutdown of guest network on SRX because it seems we didn't implement it as well");
+                return true;
+            }
             throw new ResourceUnavailableException(msg, DataCenter.class, zoneId);
         }
 
-        List<String> reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(network.getId());
         if (add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) {
             // Insert a new NIC for this guest network to reserve the gateway address
             savePlaceholderNic(network,  network.getGateway());
@@ -447,6 +499,19 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
             }
         }
         
+        // on network shutdown, delete placeHolder nics used for the firewall device
+        if (!add) {
+            List<NicVO> guestIps = _nicDao.listByNetworkId(network.getId());
+            for (NicVO guestIp : guestIps) {
+                // only external firewall and external load balancer will create NicVO with PlaceHolder reservation strategy
+                if (guestIp.getReservationStrategy().equals(ReservationStrategy.PlaceHolder) && guestIp.getIp4Address().equals(network.getGateway())) {
+                    _nicDao.remove(guestIp.getId());
+                }
+            }
+
+            freeFirewallForNetwork(network);
+        }
+
         String action = add ? "implemented" : "shut down";
         s_logger.debug("External firewall has " + action + " the guest network for account " + account.getAccountName() + "(id = " + account.getAccountId() + ") with VLAN tag " + guestVlanTag);
 
@@ -459,6 +524,10 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
         long zoneId = network.getDataCenterId();
         DataCenterVO zone = _dcDao.findById(zoneId);
         ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network);
+        // During destroy, device reference may already been clean up, then we just return true
+        if (fwDeviceVO == null) {
+            return true;
+        }
         HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId());
 
         assert(externalFirewall != null);
@@ -468,33 +537,62 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
             return true;
         }
 
-        List<StaticNatRuleTO> staticNatRules = new ArrayList<StaticNatRuleTO>();
-        List<PortForwardingRuleTO> portForwardingRules = new ArrayList<PortForwardingRuleTO>();
+        List<FirewallRuleTO> rulesTO = new ArrayList<FirewallRuleTO>();
 
         for (FirewallRule rule : rules) {
             IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId());
-            Vlan vlan = _vlanDao.findById(sourceIp.getVlanId());
-
-            if (rule.getPurpose() == Purpose.StaticNat) {
-                StaticNatRule staticNatRule = (StaticNatRule) rule;
-                StaticNatRuleTO ruleTO = new StaticNatRuleTO(staticNatRule, vlan.getVlanTag(), sourceIp.getAddress().addr(), staticNatRule.getDestIpAddress());
-                staticNatRules.add(ruleTO);
-            } else if (rule.getPurpose() == Purpose.PortForwarding) {
-                PortForwardingRuleTO ruleTO = new PortForwardingRuleTO((PortForwardingRule) rule, vlan.getVlanTag(), sourceIp.getAddress().addr());
-                portForwardingRules.add(ruleTO);
-            }
+            FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, sourceIp.getAddress().addr());
+            rulesTO.add(ruleTO);
         }
 
-        // Apply static nat rules
-        applyStaticNatRules(staticNatRules, zone, externalFirewall.getId());
+        //Firewall rules configured for staticNAT/PF
+        sendFirewallRules(rulesTO, zone, externalFirewall.getId());
+
+        return true;
+    }
+    
+    public boolean applyStaticNatRules(Network network, List<? extends StaticNat> rules) throws ResourceUnavailableException {
+        long zoneId = network.getDataCenterId();
+        DataCenterVO zone = _dcDao.findById(zoneId);
+        ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network);
+        HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId());
+
+        assert(externalFirewall != null);
+
+        if (network.getState() == Network.State.Allocated) {
+            s_logger.debug("External firewall was asked to apply firewall rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands.");
+            return true;
+        }
 
-        // apply port forwarding rules
-        applyPortForwardingRules(portForwardingRules, zone, externalFirewall.getId());
+        List<StaticNatRuleTO> staticNatRules = new ArrayList<StaticNatRuleTO>();
+        
+        for (StaticNat rule : rules) {
+            IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId());
+            Vlan vlan = _vlanDao.findById(sourceIp.getVlanId());
 
+            StaticNatRuleTO ruleTO = new StaticNatRuleTO(0,vlan.getVlanTag(), sourceIp.getAddress().addr(), -1, -1, rule.getDestIpAddress(), -1, -1, "any", rule.isForRevoke(), false);
+            staticNatRules.add(ruleTO);
+        }
+        
+        sendStaticNatRules(staticNatRules, zone, externalFirewall.getId());
+        
         return true;
     }
+    
+    protected void sendFirewallRules(List<FirewallRuleTO> firewallRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
+        if (!firewallRules.isEmpty()) {
+        	SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(firewallRules);
+            Answer answer = _agentMgr.easySend(externalFirewallId, cmd);
+            if (answer == null || !answer.getResult()) {
+                String details = (answer != null) ? answer.getDetails() : "details unavailable";
+                String msg = "External firewall was unable to apply static nat rules to the SRX appliance in zone " + zone.getName() + " due to: " + details + ".";
+                s_logger.error(msg);
+                throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId());
+            }
+        }
+    }
 
-    protected void applyStaticNatRules(List<StaticNatRuleTO> staticNatRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
+    protected void sendStaticNatRules(List<StaticNatRuleTO> staticNatRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
         if (!staticNatRules.isEmpty()) {
             SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(staticNatRules, null);
             Answer answer = _agentMgr.easySend(externalFirewallId, cmd);
@@ -507,7 +605,7 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
         }
     }
 
-    protected void applyPortForwardingRules(List<PortForwardingRuleTO> portForwardingRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
+    protected void sendPortForwardingRules(List<PortForwardingRuleTO> portForwardingRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
         if (!portForwardingRules.isEmpty()) {
             SetPortForwardingRulesCommand cmd = new SetPortForwardingRulesCommand(portForwardingRules);
             Answer answer = _agentMgr.easySend(externalFirewallId, cmd);
@@ -648,7 +746,38 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
 
     @Override
     public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException {
-        // TODO Auto-generated method stub
-        return null;
+        if (host.getType() != com.cloud.host.Host.Type.ExternalFirewall) {
+            return null;
+        }
+        return new DeleteHostAnswer(true);
+    }
+    
+    @Override
+    public boolean applyPortForwardingRules(Network network, List<? extends PortForwardingRule> rules) throws ResourceUnavailableException {
+        // Find the external firewall in this zone
+        long zoneId = network.getDataCenterId();
+        DataCenterVO zone = _dcDao.findById(zoneId);
+        ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network);
+        HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId());
+
+        assert(externalFirewall != null);
+
+        if (network.getState() == Network.State.Allocated) {
+            s_logger.debug("External firewall was asked to apply firewall rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands.");
+            return true;
+        }
+
+        List<PortForwardingRuleTO> pfRules = new ArrayList<PortForwardingRuleTO>();
+
+        for (PortForwardingRule rule : rules) {
+            IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId());
+            Vlan vlan = _vlanDao.findById(sourceIp.getVlanId());
+
+            PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, vlan.getVlanTag(), sourceIp.getAddress().addr());
+            pfRules.add(ruleTO);
+        }
+        
+        sendPortForwardingRules(pfRules, zone, externalFirewall.getId());
+        return true;
     }
 }