diff --git a/src/main/java/net/floodlightcontroller/firewall/Firewall.java b/src/main/java/net/floodlightcontroller/firewall/Firewall.java
index 3ddb58a6b233535b42504a794e409aa5aed05d19..a8d869fecca2664ab272edef5be9f55684a38046 100644
--- a/src/main/java/net/floodlightcontroller/firewall/Firewall.java
+++ b/src/main/java/net/floodlightcontroller/firewall/Firewall.java
@@ -160,7 +160,7 @@ public class Firewall implements IFirewallService, IOFMessageListener, IFloodlig
                 // most error checking done with ClassCastException
                 try {
                     // first, snag the required entries, for debugging info
-                	r.ruleid = (String)row.get(COLUMN_RULEID);
+                	r.ruleid = Integer.parseInt((String)row.get(COLUMN_RULEID));
                     r.switchid = Long.parseLong((String)row.get(COLUMN_SWITCHID));
                     
                     for (String key : row.keySet()) {
@@ -209,13 +209,7 @@ public class Firewall implements IFirewallService, IOFMessageListener, IFloodlig
                         }
                     }
                 } catch (ClassCastException e) {
-                    if (!r.ruleid.equals(""))
-                        logger.error(
-                                "skipping rule {} with bad data : "
-                                        + e.getMessage(), r.ruleid);
-                    else
-                        logger.error("skipping rule with bad data: {} :: {} ",
-                                e.getMessage(), e.getStackTrace());
+                    logger.error("skipping rule {} with bad data : " + e.getMessage(), r.ruleid);
                 }
                 l.add(r);
             }
@@ -331,7 +325,7 @@ public class Firewall implements IFirewallService, IOFMessageListener, IFloodlig
 	
 	@Override
 	public void addRule(FirewallRule rule) {
-		rule.ruleid = UUID.randomUUID().toString();
+		rule.ruleid = rule.genID();
 		this.rules.add(rule);
 		// now re-sort the rules
 	    Collections.sort(this.rules);
@@ -358,16 +352,16 @@ public class Firewall implements IFirewallService, IOFMessageListener, IFloodlig
 	    entry.put(COLUMN_WILDCARD_DST_IP, Boolean.toString(rule.wildcard_dst_ip));
 	    entry.put(COLUMN_PRIORITY, Integer.toString(rule.priority));
 	    entry.put(COLUMN_IS_DENYRULE, Boolean.toString(rule.is_denyrule));
-	    storageSource.insertRowAsync(TABLE_NAME, entry);
+	    storageSource.insertRow(TABLE_NAME, entry);
 	}
 	
 	@Override
-	public void deleteRule(String ruleid) {
+	public void deleteRule(int ruleid) {
 		boolean found = false;
 		Iterator<FirewallRule> iter = this.rules.iterator();
 		while (iter.hasNext()) {
 			FirewallRule r = iter.next();
-			if (r.ruleid.equalsIgnoreCase(ruleid)) {
+			if (r.ruleid == ruleid) {
 				// found the rule, now remove it
 				iter.remove();
 				found = true;
@@ -379,7 +373,7 @@ public class Firewall implements IFirewallService, IOFMessageListener, IFloodlig
 			Collections.sort(this.rules);
 		}
 		// delete from database
-		storageSource.deleteRowAsync(TABLE_NAME, ruleid);
+		storageSource.deleteRow(TABLE_NAME, ruleid);
 	}
 	
 	protected List<Object> matchWithRule(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
@@ -558,8 +552,12 @@ public class Firewall implements IFirewallService, IOFMessageListener, IFloodlig
 	public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
 		Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
 		
+		// TODO - add a check for a case where L2 is broadcast and L3 is unicast, i.e. malformed packet, deny it
+		
 		if (eth.getEtherType() == Ethernet.TYPE_ARP || eth.isBroadcast() == true) {
 			logger.info("allowing ARP and L2 broadcast traffic");
+			decision = new FirewallDecision(IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
+			decision.addToContext(cntx);
 			return Command.CONTINUE;
 		}
 		
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
index ecf08caad542545d7f4d407f97df2f4068cb8830..4ae0420ddc5e9406d65cf789d64a8906e7e2e992 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
@@ -1,7 +1,9 @@
 package net.floodlightcontroller.firewall;
 
+import java.util.Arrays;
+
 public class FirewallRule implements Comparable {
-	public String ruleid;
+	public int ruleid;
 	public short src_inport;
 	public long src_mac;
 	public int src_ip_prefix;
@@ -44,6 +46,16 @@ public class FirewallRule implements Comparable {
 		this.wildcard_switchid = true;
 		this.priority = 32767;
 		this.is_denyrule = false;
+		this.ruleid = this.genID();
+	}
+	
+	public int genID() {
+		int uid = this.hashCode();
+		if (uid <= 0) {
+			uid = Math.abs(uid);
+			uid *= 15551;
+		}
+		return uid;
 	}
 	
 	public int compareTo(Object rule) {
@@ -72,4 +84,31 @@ public class FirewallRule implements Comparable {
 		}
 		return true;
 	}
+	
+	@Override
+    public int hashCode() {
+        final int prime = 2521;
+        int result = super.hashCode();
+        result = prime * result + src_inport;
+        result = prime * result + (int)src_mac;
+        result = prime * result + src_ip_prefix;
+        result = prime * result + src_ip_bits;
+        result = prime * result + proto_type;
+        result = prime * result + proto_srcport;
+        result = prime * result + proto_dstport;
+        result = prime * result + (int)dst_mac;
+        result = prime * result + dst_ip_prefix;
+        result = prime * result + dst_ip_bits;
+        result = prime * result + (int)switchid;
+        result = prime * result + priority;
+        result = prime * result + (new Boolean(is_denyrule)).hashCode();
+        result = prime * result + (new Boolean(wildcard_switchid)).hashCode();
+        result = prime * result + (new Boolean(wildcard_src_inport)).hashCode();
+        result = prime * result + (new Boolean(wildcard_src_ip)).hashCode();
+        result = prime * result + (new Boolean(wildcard_src_mac)).hashCode();
+        result = prime * result + (new Boolean(wildcard_proto_type)).hashCode();
+        result = prime * result + (new Boolean(wildcard_dst_ip)).hashCode();
+        result = prime * result + (new Boolean(wildcard_dst_mac)).hashCode();
+        return result;
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
index a05926645009ddb79d31894aa799ac484c27a93d..104ce6cc3a13d9a4debdd8250893a01c17308a61 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
@@ -90,7 +90,7 @@ public class FirewallRulesResource extends ServerResource {
     	Iterator<FirewallRule> iter = firewall.getRules().iterator();
     	while (iter.hasNext()) {
     		FirewallRule r = iter.next();
-    		if (r.ruleid.equalsIgnoreCase(rule.ruleid)) {
+    		if (r.ruleid == rule.ruleid) {
     			exists = true;
     			break;
     		}
@@ -140,7 +140,7 @@ public class FirewallRulesResource extends ServerResource {
             
             String tmp;
             if (n == "ruleid") {
-                rule.ruleid = jp.getText();
+                rule.ruleid = Integer.parseInt((String)jp.getText());
             } else if (n == "switchid") {
             		tmp = jp.getText();
             		if (tmp.equalsIgnoreCase("-1") == false) {
diff --git a/src/main/java/net/floodlightcontroller/firewall/IFirewallService.java b/src/main/java/net/floodlightcontroller/firewall/IFirewallService.java
index 7d5064487aa09f71b2b6e35a2f64d8bdcb9f29f6..40cd372a4fd10720d2b79d22322dd27efef6cb2b 100644
--- a/src/main/java/net/floodlightcontroller/firewall/IFirewallService.java
+++ b/src/main/java/net/floodlightcontroller/firewall/IFirewallService.java
@@ -39,5 +39,5 @@ public interface IFirewallService extends IFloodlightService {
 	/**
      * Deletes a Firewall rule
      */
-	public void deleteRule(String ruleid);
+	public void deleteRule(int ruleid);
 }
diff --git a/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java b/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc261f3ce190c6226541164518507cf942deb382
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java
@@ -0,0 +1,361 @@
+package net.floodlightcontroller.firewall;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.test.MockFloodlightProvider;
+import net.floodlightcontroller.packet.Data;
+import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.packet.IPacket;
+import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.packet.TCP;
+import net.floodlightcontroller.packet.UDP;
+import net.floodlightcontroller.restserver.IRestApiService;
+import net.floodlightcontroller.restserver.RestApiServer;
+import net.floodlightcontroller.routing.IRoutingDecision;
+import net.floodlightcontroller.storage.IStorageSourceService;
+import net.floodlightcontroller.storage.memory.MemoryStorageSource;
+import net.floodlightcontroller.test.FloodlightTestCase;
+import net.floodlightcontroller.util.MACAddress;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPacketIn.OFPacketInReason;
+import org.openflow.protocol.OFType;
+import org.openflow.util.HexString;
+
+public class FirewallTest extends FloodlightTestCase {
+	protected MockFloodlightProvider mockFloodlightProvider;
+    protected FloodlightContext cntx;
+	protected OFPacketIn packetIn;
+	protected IOFSwitch sw;
+    protected IPacket tcpPacket;
+    protected byte[] tcpPacketSerialized;
+    protected IPacket broadcastPacket;
+    protected byte[] broadcastPacketSerialized;
+    protected IPacket tcpPacketReply;
+    protected byte[] tcpPacketReplySerialized;
+    private Firewall firewall;
+    public static String TestSwitch1DPID = "00:00:00:00:00:00:00:01";
+    
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        cntx = new FloodlightContext();
+        mockFloodlightProvider = getMockFloodlightProvider();
+        firewall = new Firewall();
+        IStorageSourceService storageService = new MemoryStorageSource();
+        RestApiServer restApi = new RestApiServer();
+        
+        // Mock switches
+        long dpid = HexString.toLong(TestSwitch1DPID);
+        sw = EasyMock.createNiceMock(IOFSwitch.class);
+        expect(sw.getId()).andReturn(dpid).anyTimes();
+        expect(sw.getStringId()).andReturn(TestSwitch1DPID).anyTimes();
+        replay(sw);
+        // Load the switch map
+        Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>();
+        switches.put(dpid, sw);
+        mockFloodlightProvider.setSwitches(switches);
+        
+        FloodlightModuleContext fmc = new FloodlightModuleContext();
+        fmc.addService(IFloodlightProviderService.class, 
+                       mockFloodlightProvider);
+        fmc.addService(IFirewallService.class, firewall);
+        fmc.addService(IStorageSourceService.class, storageService);
+        fmc.addService(IRestApiService.class, restApi);
+        
+        try {
+            restApi.init(fmc);
+        } catch (FloodlightModuleException e) {
+            e.printStackTrace();
+        }
+
+        firewall.init(fmc);
+        firewall.startUp(fmc);
+       
+        // Build our test packet
+        this.tcpPacket = new Ethernet()
+            .setDestinationMACAddress("00:11:22:33:44:55")
+            .setSourceMACAddress("00:44:33:22:11:00")
+            .setVlanID((short) 42)
+            .setEtherType(Ethernet.TYPE_IPv4)
+            .setPayload(
+                new IPv4()
+                .setTtl((byte) 128)
+                .setSourceAddress("192.168.1.1")
+                .setDestinationAddress("192.168.1.2")
+                .setPayload(new TCP()
+                            .setSourcePort((short) 81)
+                            .setDestinationPort((short) 80)
+                            .setPayload(new Data(new byte[] {0x01}))));
+        this.tcpPacketSerialized = tcpPacket.serialize();
+        // Build a broadcast packet
+        this.broadcastPacket = new Ethernet()
+            .setDestinationMACAddress("FF:FF:FF:FF:FF:FF")
+            .setSourceMACAddress("00:44:33:22:11:00")
+            .setVlanID((short) 42)
+            .setEtherType(Ethernet.TYPE_IPv4)
+            .setPayload(
+                new IPv4()
+                .setTtl((byte) 128)
+                .setSourceAddress("192.168.1.1")
+                .setDestinationAddress("192.168.255.255")
+                .setPayload(new UDP()
+                        .setSourcePort((short) 5000)
+                        .setDestinationPort((short) 5001)
+                        .setPayload(new Data(new byte[] {0x01}))));
+
+        this.broadcastPacketSerialized = broadcastPacket.serialize();
+        this.tcpPacketReply = new Ethernet()
+            .setDestinationMACAddress("00:44:33:22:11:00")
+            .setSourceMACAddress("00:11:22:33:44:55")
+            .setVlanID((short) 42)
+            .setEtherType(Ethernet.TYPE_IPv4)
+            .setPayload(
+                    new IPv4()
+                    .setTtl((byte) 128)
+                    .setSourceAddress("192.168.1.2")
+                    .setDestinationAddress("192.168.1.1")
+                    .setPayload(new TCP()
+                    .setSourcePort((short) 80)
+                    .setDestinationPort((short) 81)
+                    .setPayload(new Data(new byte[] {0x02}))));
+        this.tcpPacketReplySerialized = tcpPacketReply.serialize();
+    }
+    
+    protected void setPacketIn(IPacket packet) {
+    	byte[] serializedPacket = packet.serialize();
+    	// Build the PacketIn
+        this.packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN))
+            .setBufferId(-1)
+            .setInPort((short) 1)
+            .setPacketData(serializedPacket)
+            .setReason(OFPacketInReason.NO_MATCH)
+            .setTotalLength((short) serializedPacket.length);
+        
+        // Add the packet to the context store
+        IFloodlightProviderService.bcStore.
+            put(cntx, 
+                IFloodlightProviderService.CONTEXT_PI_PAYLOAD, 
+                (Ethernet)packet);
+    }
+    
+    @Test
+    public void testNoRules() throws Exception {
+    	// enable firewall first
+    	firewall.enableFirewall();
+    	// simulate a packet-in event
+    	this.setPacketIn(tcpPacket);
+    	firewall.receive(sw, this.packetIn, cntx);
+    	verify(sw);
+    	
+    	assertEquals(0, firewall.countRules());
+    	
+    	IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	// no rules to match, so firewall should deny
+    	assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP);
+    }
+    
+    @Test
+    public void testRuleInsertionIntoStorage() throws Exception {
+    	// add TCP rule
+    	FirewallRule rule = new FirewallRule();
+    	rule.proto_type = IPv4.PROTOCOL_TCP;
+    	rule.wildcard_proto_type = false;
+    	rule.priority = 1;
+    	firewall.addRule(rule);
+    	
+    	List<Map<String, Object>> rulesFromStorage = firewall.getStorageRules();
+    	assertEquals(1, rulesFromStorage.size());
+    	assertEquals(rulesFromStorage.get(0).get("ruleid"), rule.ruleid);
+    }
+    
+    @Test
+    public void testRuleDeletion() throws Exception {
+    	// add TCP rule
+    	FirewallRule rule = new FirewallRule();
+    	rule.proto_type = IPv4.PROTOCOL_TCP;
+    	rule.wildcard_proto_type = false;
+    	rule.priority = 1;
+    	firewall.addRule(rule);
+    	int rid = rule.ruleid;
+    	
+    	List<Map<String, Object>> rulesFromStorage = firewall.getStorageRules();
+    	assertEquals(1, rulesFromStorage.size());
+    	assertEquals(rulesFromStorage.get(0).get("ruleid"), rid);
+    	
+    	// delete rule
+    	firewall.deleteRule(rid);
+    	rulesFromStorage = firewall.getStorageRules();
+    	assertEquals(0, rulesFromStorage.size());
+    }
+    
+    @Test
+    public void testFirewallDisabled() throws Exception {
+    	// firewall isn't enabled by default
+    	// so, it shouldn't make any decision
+    	
+    	// add TCP rule
+    	FirewallRule rule = new FirewallRule();
+    	rule.proto_type = IPv4.PROTOCOL_TCP;
+    	rule.wildcard_proto_type = false;
+    	rule.priority = 1;
+    	firewall.addRule(rule);
+    	
+    	this.setPacketIn(tcpPacket);
+    	firewall.receive(sw, this.packetIn, cntx);
+    	verify(sw);
+    	
+    	assertEquals(1, firewall.countRules());
+    	
+    	IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	assertNull(decision);
+    }
+    
+    @Test
+    public void testSimpleAllowRule() throws Exception {
+    	// enable firewall first
+    	firewall.enableFirewall();
+    	
+    	// add TCP rule
+    	FirewallRule rule = new FirewallRule();
+    	rule.proto_type = IPv4.PROTOCOL_TCP;
+    	rule.wildcard_proto_type = false;
+    	// source is IP 192.168.1.2
+    	rule.src_ip_prefix = IPv4.toIPv4Address("192.168.1.2");
+    	rule.wildcard_src_ip = false;
+    	// dest is network 192.168.1.0/24
+    	rule.dst_ip_prefix = IPv4.toIPv4Address("192.168.1.0");
+    	rule.dst_ip_bits = 24;
+    	rule.wildcard_dst_ip = false;
+    	rule.priority = 1;
+    	firewall.addRule(rule);
+    	
+    	// simulate a packet-in events
+    	
+    	this.setPacketIn(tcpPacketReply);
+    	firewall.receive(sw, this.packetIn, cntx);
+    	verify(sw);
+    	
+    	IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
+    	
+    	// clear decision
+    	IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	
+    	this.setPacketIn(tcpPacket);
+    	firewall.receive(sw, this.packetIn, cntx);
+    	verify(sw);
+    	
+    	decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP);
+    }
+    
+    @Test
+    public void testOverlappingRules() throws Exception {
+    	firewall.enableFirewall();
+    	
+    	// add TCP port 80 (destination only) allow rule
+    	FirewallRule rule = new FirewallRule();
+    	rule.proto_type = IPv4.PROTOCOL_TCP;
+    	rule.wildcard_proto_type = false;
+    	rule.proto_dstport = 80;
+    	rule.priority = 1;
+    	firewall.addRule(rule);
+    	
+    	// add block all rule
+    	rule = new FirewallRule();
+    	rule.is_denyrule = true;
+    	rule.priority = 2;
+    	firewall.addRule(rule);
+    	
+    	assertEquals(2, firewall.countRules());
+    	
+    	// packet destined to TCP port 80 - should be allowed
+    	
+    	this.setPacketIn(tcpPacket);
+    	firewall.receive(sw, this.packetIn, cntx);
+    	verify(sw);
+    	
+    	IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
+    	
+    	// clear decision
+    	IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	
+    	// packet destined for port 81 - should be denied
+    	
+    	this.setPacketIn(tcpPacketReply);
+    	firewall.receive(sw, this.packetIn, cntx);
+    	verify(sw);
+    	
+    	decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP);
+    }
+    
+    @Test
+    public void testBroadcast() throws Exception {
+    	// enable firewall first
+    	firewall.enableFirewall();
+    	
+    	// no rules inserted so all traffic other than broadcast and ARP should be blocked
+    	
+    	// simulate a packet-in event
+    	
+    	this.setPacketIn(broadcastPacket);
+    	firewall.receive(sw, this.packetIn, cntx);
+    	verify(sw);
+    	
+    	// broadcast traffic should be allowed
+    	IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
+    }
+    
+    @Test
+    public void testLayer2Rule() throws Exception {
+    	// enable firewall first
+    	firewall.enableFirewall();
+    	
+    	// add L2 rule
+    	FirewallRule rule = new FirewallRule();
+    	rule.src_mac = MACAddress.valueOf("00:44:33:22:11:00").toLong();
+    	rule.wildcard_src_mac = false;
+    	rule.dst_mac = MACAddress.valueOf("00:11:22:33:44:55").toLong();
+    	rule.wildcard_dst_mac = false;
+    	rule.priority = 1;
+    	firewall.addRule(rule);
+    	
+    	// add TCP deny all rule
+    	rule = new FirewallRule();
+    	rule.proto_type = IPv4.PROTOCOL_TCP;
+    	rule.wildcard_proto_type = false;
+    	rule.priority = 2;
+    	rule.is_denyrule = true;
+    	firewall.addRule(rule);
+    	
+    	// simulate a packet-in event
+    	
+    	this.setPacketIn(tcpPacket);
+    	firewall.receive(sw, this.packetIn, cntx);
+    	verify(sw);
+    	
+    	IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+    	assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
+    }
+    
+    // TODO - add cases for stress testing and malformed packets (e.g. L2 broadcast with L3 unicast)
+}