diff --git a/.gitignore b/.gitignore
index 82d143f44f3b0707dbc09ebdf82c6c015569dbc4..0c0e028da7769c5a0bf218c9f98d29ea1b990a43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,4 @@ findbugs-results
 *.idea/*
 *.iml
 .metadata/
+/bin/
diff --git a/src/main/java/net/floodlightcontroller/core/util/AppCookie.java b/src/main/java/net/floodlightcontroller/core/util/AppCookie.java
index 5406bbd8c9a6a2b92b423db0598d225713b83fa4..d35e6a9e56631e21f3c13f52db9b6f693199fe76 100644
--- a/src/main/java/net/floodlightcontroller/core/util/AppCookie.java
+++ b/src/main/java/net/floodlightcontroller/core/util/AppCookie.java
@@ -69,6 +69,20 @@ public class AppCookie {
     private static ConcurrentMap<Integer, String> appIdMap =
             new ConcurrentHashMap<Integer, String>();
 
+    /**
+     * Returns a mask suitable for matching the App ID within a cookie.
+     */
+    static public U64 getAppFieldMask() {
+        return U64.of(APP_ID_MASK << APP_ID_SHIFT);
+    }
+
+    /**
+     * Returns a mask suitable for matching the User field within a cookie.
+     */
+    static public U64 getUserFieldMask() {
+        return U64.of(USER_MASK);
+    }
+    
     /**
      * Encapsulate an application ID and a user block of stuff into a cookie
      *
diff --git a/src/main/java/net/floodlightcontroller/firewall/Firewall.java b/src/main/java/net/floodlightcontroller/firewall/Firewall.java
index 5b63189012de1a7aa544816ac4823673e79d438a..4ecc605c40e359ea828e3d380d2b18b9cc1886b6 100644
--- a/src/main/java/net/floodlightcontroller/firewall/Firewall.java
+++ b/src/main/java/net/floodlightcontroller/firewall/Firewall.java
@@ -37,8 +37,10 @@ import org.projectfloodlight.openflow.types.IPv4Address;
 import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
 import org.projectfloodlight.openflow.types.IpProtocol;
 import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.Masked;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U64;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IOFMessageListener;
@@ -47,6 +49,7 @@ import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.core.util.AppCookie;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.devicemanager.IDeviceService;
 
@@ -58,6 +61,7 @@ import net.floodlightcontroller.packet.TCP;
 import net.floodlightcontroller.packet.UDP;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.routing.IRoutingDecision;
+import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.RoutingDecision;
 import net.floodlightcontroller.storage.IResultSet;
 import net.floodlightcontroller.storage.IStorageSourceService;
@@ -66,6 +70,8 @@ import net.floodlightcontroller.storage.StorageException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableList;
+
 /**
  * Stateless firewall implemented as a Google Summer of Code project.
  * Configuration done through REST API
@@ -76,11 +82,20 @@ import org.slf4j.LoggerFactory;
  */
 public class Firewall implements IFirewallService, IOFMessageListener,
 IFloodlightModule {
+	private static final short APP_ID = 30;
+	static {
+		AppCookie.registerApp(APP_ID, "Firewall");
+	}
+	private static final U64 DENY_BCAST_COOKIE = AppCookie.makeCookie(APP_ID, 0xaaaaaaaa);
+	private static final U64 ALLOW_BCAST_COOKIE = AppCookie.makeCookie(APP_ID, 0x55555555);
+	private static final U64 RULE_MISS_COOKIE = AppCookie.makeCookie(APP_ID, -1);
+	static final U64 DEFAULT_COOKIE = AppCookie.makeCookie(APP_ID, 0);
 
 	// service modules needed
 	protected IFloodlightProviderService floodlightProvider;
 	protected IStorageSourceService storageSource;
 	protected IRestApiService restApi;
+	protected IRoutingService routingService;
 	protected static Logger logger;
 
 	protected List<FirewallRule> rules; // protected by synchronized
@@ -161,6 +176,7 @@ IFloodlightModule {
 		l.add(IFloodlightProviderService.class);
 		l.add(IStorageSourceService.class);
 		l.add(IRestApiService.class);
+		l.add(IRoutingService.class);
 		return l;
 	}
 
@@ -279,6 +295,7 @@ IFloodlightModule {
 		floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
 		storageSource = context.getServiceImpl(IStorageSourceService.class);
 		restApi = context.getServiceImpl(IRestApiService.class);
+		routingService = context.getServiceImpl(IRoutingService.class);
 		rules = new ArrayList<FirewallRule>();
 		logger = LoggerFactory.getLogger(Firewall.class);
 
@@ -309,7 +326,9 @@ IFloodlightModule {
 		switch (msg.getType()) {
 		case PACKET_IN:
 			IRoutingDecision decision = null;
-			if (cntx != null) {
+			if (cntx == null) {
+				logger.warn("Firewall unable to request packet drop: FloodlightContext is null.");
+			} else {
 				decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
 				return this.processPacketInMessage(sw, (OFPacketIn) msg, decision, cntx);
 			}
@@ -323,8 +342,17 @@ IFloodlightModule {
 
 	@Override
 	public void enableFirewall(boolean enabled) {
-		logger.info("Setting firewall to {}", enabled);
-		this.enabled = enabled;
+		if(this.enabled != enabled) {
+			logger.info("Setting firewall to {}", enabled);
+			this.enabled = enabled;
+
+			List<Masked<U64>> changes = ImmutableList.of(
+						Masked.of(DEFAULT_COOKIE, AppCookie.getAppFieldMask())
+					);
+
+			// Add announcement that all firewall decisions changed
+			routingService.handleRoutingDecisionChange(changes);
+		}
 	}
 
 	@Override
@@ -412,6 +440,18 @@ IFloodlightModule {
 		entry.put(COLUMN_PRIORITY, Integer.toString(rule.priority));
 		entry.put(COLUMN_ACTION, Integer.toString(rule.action.ordinal()));
 		storageSource.insertRow(TABLE_NAME, entry);
+		
+		U64 singleRuleMask = AppCookie.getAppFieldMask().or(AppCookie.getUserFieldMask());
+		ImmutableList.Builder<Masked<U64>> changesBuilder = ImmutableList.builder();
+		Iterator<FirewallRule> iter = this.rules.iterator();
+		while (iter.hasNext()) {
+			FirewallRule r = iter.next();
+			if (r.priority >= rule.priority) {
+				changesBuilder.add(Masked.of(AppCookie.makeCookie(APP_ID, r.ruleid), singleRuleMask));
+			}
+		}
+		changesBuilder.add(Masked.of(RULE_MISS_COOKIE, singleRuleMask));
+		routingService.handleRoutingDecisionChange(changesBuilder.build());
 	}
 
 	@Override
@@ -427,6 +467,17 @@ IFloodlightModule {
 		}
 		// delete from database
 		storageSource.deleteRow(TABLE_NAME, Integer.toString(ruleid));
+		
+		//Add announcement that the rule has been deleted
+		Masked<U64> delDescriptor = Masked.of(
+				AppCookie.makeCookie(APP_ID, ruleid),
+				AppCookie.getAppFieldMask().or(AppCookie.getUserFieldMask()));
+		
+		List<Masked<U64>> changes = ImmutableList.of(delDescriptor);
+		
+		//Add announcement that rule is added
+		// should we try to delete the flow even if not found in this.rules
+		routingService.handleRoutingDecisionChange(changes);
 	}
 
 	/**
@@ -560,6 +611,7 @@ IFloodlightModule {
 				decision = new RoutingDecision(sw.getId(), inPort, 
 						IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
 						IRoutingDecision.RoutingAction.MULTICAST);
+				decision.setDescriptor(ALLOW_BCAST_COOKIE);
 				decision.addToContext(cntx);
 			} else {
 				if (logger.isTraceEnabled()) {
@@ -569,6 +621,7 @@ IFloodlightModule {
 				decision = new RoutingDecision(sw.getId(), inPort,
 						IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
 						IRoutingDecision.RoutingAction.DROP);
+				decision.setDescriptor(DENY_BCAST_COOKIE);
 				decision.addToContext(cntx);
 			}
 			return Command.CONTINUE;
@@ -581,6 +634,7 @@ IFloodlightModule {
 		 * else if (eth.getEtherType() == Ethernet.TYPE_ARP) {
 		 * logger.info("allowing ARP traffic"); decision = new
 		 * FirewallDecision(IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
+		 * decision.setDescriptor(ALLOW_BCAST_COOKIE);
 		 * decision.addToContext(cntx); return Command.CONTINUE; }
 		 */
 
@@ -596,6 +650,11 @@ IFloodlightModule {
 						IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), 
 						IRoutingDecision.RoutingAction.DROP);
 				decision.setMatch(rmp.match);
+				if (rule == null) {
+					decision.setDescriptor(RULE_MISS_COOKIE);
+				} else {
+					decision.setDescriptor(AppCookie.makeCookie(APP_ID, rule.ruleid));
+				}
 				decision.addToContext(cntx);
 				if (logger.isTraceEnabled()) {
 					if (rule == null) {
@@ -610,6 +669,7 @@ IFloodlightModule {
 						IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
 						IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
 				decision.setMatch(rmp.match);
+				decision.setDescriptor(AppCookie.makeCookie(APP_ID, rule.ruleid));
 				decision.addToContext(cntx);
 				if (logger.isTraceEnabled()) {
 					logger.trace("Allow rule={} match for PacketIn={}", rule, pi);
diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
index ca041e49a4f5320d163491524cecea400ae6d002..87ffc5500174a7f7d96483be1ec4bb21fe0890f2 100644
--- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
@@ -50,6 +50,7 @@ import net.floodlightcontroller.packet.TCP;
 import net.floodlightcontroller.packet.UDP;
 import net.floodlightcontroller.routing.ForwardingBase;
 import net.floodlightcontroller.routing.IRoutingDecision;
+import net.floodlightcontroller.routing.IRoutingDecisionChangedListener;
 import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.Route;
 import net.floodlightcontroller.topology.ITopologyService;
@@ -77,6 +78,7 @@ import org.projectfloodlight.openflow.types.IPv4Address;
 import org.projectfloodlight.openflow.types.IPv6Address;
 import org.projectfloodlight.openflow.types.IpProtocol;
 import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.Masked;
 import org.projectfloodlight.openflow.types.OFBufferId;
 import org.projectfloodlight.openflow.types.OFGroup;
 import org.projectfloodlight.openflow.types.OFPort;
@@ -84,12 +86,18 @@ import org.projectfloodlight.openflow.types.OFVlanVidMatch;
 import org.projectfloodlight.openflow.types.TableId;
 import org.projectfloodlight.openflow.types.U64;
 import org.projectfloodlight.openflow.types.VlanVid;
+import org.python.google.common.collect.ImmutableList;
+import org.python.google.common.collect.Maps;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class Forwarding extends ForwardingBase implements IFloodlightModule, IOFSwitchListener, ILinkDiscoveryListener {
+public class Forwarding extends ForwardingBase implements IFloodlightModule, IOFSwitchListener, ILinkDiscoveryListener, IRoutingDecisionChangedListener {
     protected static Logger log = LoggerFactory.getLogger(Forwarding.class);
-
+    final static U64 DEFAULT_FORWARDING_COOKIE = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
+    
+    // This mask determines how much of each cookie will contain IRoutingDecision descriptor bits.
+ 	private final long DECISION_MASK = 0x00000000ffffffffL; // TODO: shrink this mask if you need to add more sub-fields.
+    
     @Override
     public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
         Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
@@ -105,11 +113,11 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
                 return Command.CONTINUE;
             case FORWARD_OR_FLOOD:
             case FORWARD:
-                doForwardFlow(sw, pi, cntx, false);
+                doForwardFlow(sw, pi, decision, cntx, false);
                 return Command.CONTINUE;
             case MULTICAST:
                 // treat as broadcast
-                doFlood(sw, pi, cntx);
+                doFlood(sw, pi, decision, cntx);
                 return Command.CONTINUE;
             case DROP:
                 doDropFlow(sw, pi, decision, cntx);
@@ -124,21 +132,124 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
             }
 
             if (eth.isBroadcast() || eth.isMulticast()) {
-                doFlood(sw, pi, cntx);
+                doFlood(sw, pi, decision, cntx);
             } else {
-                doForwardFlow(sw, pi, cntx, false);
+                doForwardFlow(sw, pi, decision, cntx, false);
             }
         }
 
         return Command.CONTINUE;
     }
+    
+    /**
+	 * Builds a cookie that includes routing decision information.
+	 *
+	 * @param decision The routing decision providing a descriptor, or null
+	 * @return A cookie with our app id and the required routing fields masked-in
+	 */
+	protected U64 makeForwardingCookie(IRoutingDecision decision) {
+		int user_fields = 0;
+
+		U64 decision_cookie = (decision == null) ? null : decision.getDescriptor();
+		if (decision_cookie != null) {
+			user_fields |= AppCookie.extractUser(decision_cookie) & DECISION_MASK;
+		}
+
+		// TODO: Mask in any other required fields here (e.g. link failure flowset ID)
+
+		if (user_fields == 0) {
+			return DEFAULT_FORWARDING_COOKIE;
+		}
+		return AppCookie.makeCookie(FORWARDING_APP_ID, user_fields);
+	}
+
+	/** Called when the handleDecisionChange is triggered by an event (routing decision was changed in firewall).
+	 *  
+	 *  @param changedDecisions Masked routing descriptors for flows that should be deleted from the switch.
+	 */
+	@Override
+	public void routingDecisionChanged(Iterable<Masked<U64>> changedDecisions) {
+		deleteFlowsByDescriptor(changedDecisions);
+	}
+	
+	/**
+	 * Converts a sequence of masked IRoutingDecision descriptors into masked Forwarding cookies.
+	 *
+	 * This generates a list of masked cookies that can then be matched in flow-mod messages.
+	 *
+	 * @param maskedDescriptors A sequence of masked cookies describing IRoutingDecision descriptors
+	 * @return A collection of masked cookies suitable for flow-mod operations
+	 */
+	protected Collection<Masked<U64>> convertRoutingDecisionDescriptors(Iterable<Masked<U64>> maskedDescriptors) {
+		if(maskedDescriptors == null) {
+			return null;
+		}
+
+		ImmutableList.Builder<Masked<U64>> resultBuilder = ImmutableList.builder();
+		for (Masked<U64> maskedDescriptor : maskedDescriptors) {
+			long user_mask = AppCookie.extractUser(maskedDescriptor.getMask()) & DECISION_MASK;
+			long user_value = AppCookie.extractUser(maskedDescriptor.getValue()) & user_mask;
+
+			// TODO combine in any other cookie fields you need here.
+
+			resultBuilder.add(
+					Masked.of(
+							AppCookie.makeCookie(FORWARDING_APP_ID, (int)user_value),
+							AppCookie.getAppFieldMask().or(U64.of(user_mask))
+					)
+			);
+		}
+
+		return resultBuilder.build();
+	}
+
+	/**
+	 * On all active switches, deletes all flows matching the IRoutingDecision descriptors provided
+	 * as arguments.
+	 *
+	 * @param descriptors The descriptors and masks describing which flows to delete.
+	 */
+	protected void deleteFlowsByDescriptor(Iterable<Masked<U64>> descriptors) {
+		Collection<Masked<U64>> masked_cookies = convertRoutingDecisionDescriptors(descriptors);
+
+		if (masked_cookies != null && !masked_cookies.isEmpty()) {
+			Map<OFVersion, List<OFMessage>> cache = Maps.newHashMap();
+
+			for (DatapathId dpid : switchService.getAllSwitchDpids()) {
+				IOFSwitch sw = switchService.getActiveSwitch(dpid);
+				if (sw == null) {
+					continue;
+				}
+
+				OFVersion ver = sw.getOFFactory().getVersion();
+				if (cache.containsKey(ver)) {
+					sw.write(cache.get(ver));
+				} else {
+					ImmutableList.Builder<OFMessage> msgsBuilder = ImmutableList.builder();
+					for (Masked<U64> masked_cookie : masked_cookies) {
+						msgsBuilder.add(
+							sw.getOFFactory().buildFlowDelete()
+								.setCookie(masked_cookie.getValue())
+								.setCookieMask(masked_cookie.getMask())
+									.build()
+							);
+					}
+
+					List<OFMessage> msgs = msgsBuilder.build();
+					sw.write(msgs);
+					cache.put(ver, msgs);
+				}
+			}
+		}
+	}
+
 
     protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
         OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
         Match m = createMatchFromPacket(sw, inPort, cntx);
         OFFlowMod.Builder fmb = sw.getOFFactory().buildFlowAdd(); // this will be a drop-flow; a flow that will not output to any ports
         List<OFAction> actions = new ArrayList<OFAction>(); // set no action to drop
-        U64 cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
+        U64 cookie = makeForwardingCookie(decision); 
         log.info("Dropping");
         fmb.setCookie(cookie)
         .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
@@ -162,7 +273,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
         log.debug("OFMessage dampened: {}", dampened);
     }
 
-    protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, boolean requestFlowRemovedNotifn) {
+    protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx, boolean requestFlowRemovedNotifn) {
         OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
         IDevice dstDevice = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE);
         DatapathId source = sw.getId();
@@ -179,7 +290,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
                     IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD).getEtherType() 
                     == EthType.ARP) {
                 log.debug("ARP flows disabled in Forwarding. Flooding ARP packet");
-                doFlood(sw, pi, cntx);
+                doFlood(sw, pi, decision, cntx);
                 return;
             }
 
@@ -226,24 +337,24 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
              */
             if (dstDap == null) {
                 log.warn("Could not locate edge attachment point for device {}. Flooding packet");
-                doFlood(sw, pi, cntx);
+                doFlood(sw, pi, decision, cntx);
                 return; 
             }
 
             /* It's possible that we learned packed destination while it was in flight */
             if (!topologyService.isEdge(source, inPort)) {	
                 log.debug("Packet destination is known, but packet was not received on an edge port (rx on {}/{}). Flooding packet", source, inPort);
-                doFlood(sw, pi, cntx);
+                doFlood(sw, pi, decision, cntx);
                 return; 
             }				
 
+            U64 cookie = makeForwardingCookie(decision);
             Route route = routingEngineService.getRoute(source, 
                     inPort,
                     dstDap.getNodeId(),
-                    dstDap.getPortId(), U64.of(0)); //cookie = 0, i.e., default route
+                    dstDap.getPortId(), cookie); // Cookie currently ignored. May carry useful info in the future.
 
             Match m = createMatchFromPacket(sw, inPort, cntx);
-            U64 cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
 
             if (route != null) {
                 if (log.isDebugEnabled()) {
@@ -275,7 +386,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
             }
         } else {
             log.debug("Destination unknown. Flooding packet");
-            doFlood(sw, pi, cntx);
+            doFlood(sw, pi, decision, cntx);
         }
     }
 
@@ -388,9 +499,10 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
      * the port is blocked, in which case the packet will be dropped.
      * @param sw The switch that receives the OFPacketIn
      * @param pi The OFPacketIn that came to the switch
+     * @param decision The decision that caused flooding, or null
      * @param cntx The FloodlightContext associated with this OFPacketIn
      */
-    protected void doFlood(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
+    protected void doFlood(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
         OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
         // Set Action to flood
         OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
@@ -543,6 +655,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
     public void startUp(FloodlightModuleContext context) {
         super.startUp();
         switchService.addOFSwitchListener(this);
+        routingEngineService.addRoutingDecisionChangedListener(this);
 
         /* Register only if we want to remove stale flows */
         if (REMOVE_FLOWS_ON_LINK_OR_PORT_DOWN) {
@@ -621,14 +734,16 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
                     if (srcSw != null) {
                         /* flows matching on src port */
                         msgs.add(srcSw.getOFFactory().buildFlowDelete()
-                                .setCookie(AppCookie.makeCookie(FORWARDING_APP_ID, 0))
+                        		.setCookie(DEFAULT_FORWARDING_COOKIE)
+                        		.setCookieMask(AppCookie.getAppFieldMask())
                                 .setMatch(srcSw.getOFFactory().buildMatch()
                                         .setExact(MatchField.IN_PORT, u.getSrcPort())
                                         .build())
                                 .build());
                         /* flows outputting to src port */
                         msgs.add(srcSw.getOFFactory().buildFlowDelete()
-                                .setCookie(AppCookie.makeCookie(FORWARDING_APP_ID, 0))
+                        		.setCookie(DEFAULT_FORWARDING_COOKIE)
+                        		.setCookieMask(AppCookie.getAppFieldMask())
                                 .setOutPort(u.getSrcPort())
                                 .build());
                         messageDamper.write(srcSw, msgs);
@@ -644,14 +759,16 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
                         /* flows matching on dst port */
                         msgs.clear();
                         msgs.add(dstSw.getOFFactory().buildFlowDelete()
-                                .setCookie(AppCookie.makeCookie(FORWARDING_APP_ID, 0))
+                        		.setCookie(DEFAULT_FORWARDING_COOKIE)
+                        		.setCookieMask(AppCookie.getAppFieldMask())
                                 .setMatch(dstSw.getOFFactory().buildMatch()
                                         .setExact(MatchField.IN_PORT, u.getDstPort())
                                         .build())
                                 .build());
                         /* flows outputting to dst port */
                         msgs.add(dstSw.getOFFactory().buildFlowDelete()
-                                .setCookie(AppCookie.makeCookie(FORWARDING_APP_ID, 0))
+                        		.setCookie(DEFAULT_FORWARDING_COOKIE)
+                        		.setCookieMask(AppCookie.getAppFieldMask())
                                 .setOutPort(u.getDstPort())
                                 .build());
                         messageDamper.write(dstSw, msgs);
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index 7e933000316c2c2a625d816ee69a21404308f402..a4b835724baf922e6acbe14dd03e8a829f0aee67 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -325,7 +325,7 @@ IFloodlightModule, IInfoProvider {
 		byte[] srcMac = ofpPort.getHwAddr().getBytes();
 		byte[] zeroMac = { 0, 0, 0, 0, 0, 0 };
 		if (Arrays.equals(srcMac, zeroMac)) {
-			log.warn("Port {}/{} has zero hareware address"
+			log.warn("Port {}/{} has zero hardware address"
 					+ "overwrite with lower 6 bytes of dpid",
 					dpid.toString(), ofpPort.getPortNo().getPortNumber());
 			System.arraycopy(dpidArray, 2, srcMac, 0, 6);
diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java b/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
index 6af24c6e35a14bdcbc141c24ad020d4423f7de13..592623fb89b63a758d119833833c9078ac27b67b 100644
--- a/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
+++ b/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
@@ -20,6 +20,7 @@ package net.floodlightcontroller.routing;
 import java.util.List;
 
 import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.types.U64;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.FloodlightContextStore;
@@ -63,4 +64,7 @@ public interface IRoutingDecision {
     public void setMatch(Match match);
     public int getHardTimeout();
     public void setHardTimeout(short hardTimeout);
+    public U64 getDescriptor();
+    public void setDescriptor(U64 descriptor);
+    
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingDecisionChangedListener.java b/src/main/java/net/floodlightcontroller/routing/IRoutingDecisionChangedListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..c82b420c8c9469cf08c90eca9871c0ed5a479160
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/routing/IRoutingDecisionChangedListener.java
@@ -0,0 +1,18 @@
+package net.floodlightcontroller.routing;
+
+import org.projectfloodlight.openflow.types.Masked;
+import org.projectfloodlight.openflow.types.U64;
+
+public interface IRoutingDecisionChangedListener {
+	
+    /** Notifies the listener that routing logic has changed, requiring certain past routing decisions
+     * to become invalid.  The caller provides a sequence of masked values that match against
+     * past values of IRoutingDecision.getDescriptor().  Services that have operated on past
+     * routing decisions are then able to remove the results of past decisions, normally by deleting
+     * flows.
+     * 
+     * @param changedDecisions Masked descriptors identifying routing decisions that are now obsolete or invalid  
+     */
+	public void routingDecisionChanged(Iterable<Masked<U64>> changedDecisions);
+	
+}
diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
index fde607b89cef1ca00a78e8867748c0c2f4c2c795..c773cdfcf153cb05e70bef454fcfe9fbfe041bd4 100644
--- a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
+++ b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
@@ -20,6 +20,7 @@ package net.floodlightcontroller.routing;
 import java.util.ArrayList;
 
 import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.Masked;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.U64;
 
@@ -82,5 +83,25 @@ public interface IRoutingService extends IFloodlightService {
      *  or not have tunnels as part of the path.
      */
     public boolean routeExists(DatapathId src, DatapathId dst, boolean tunnelEnabled);
+    
+    /** Register the RDCListener 
+     * @param listener - The module that wants to listen for events
+     */
+    public void addRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener);
+    
+    /** Remove the RDCListener
+     * @param listener - The module that wants to stop listening for events
+     */
+    public void removeRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener);
+    
+    /** Notifies listeners that routing logic has changed, requiring certain past routing decisions
+     * to become invalid.  The caller provides a sequence of masked values that match against
+     * past values of IRoutingDecision.getDescriptor().  Services that have operated on past
+     * routing decisions are then able to remove the results of past decisions, normally by deleting
+     * flows.
+     * 
+     * @param changedDecisions Masked descriptors identifying routing decisions that are now obsolete or invalid  
+     */
+    public void handleRoutingDecisionChange(Iterable<Masked<U64>> changedDecisions);
 
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java b/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java
index e72ccfc6eb56ce2652b013efbcb64fc2e4b6d4cc..8ce5c5c9415fcd14a3dcd34de0264b719b5536f7 100644
--- a/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java
+++ b/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java
@@ -23,6 +23,7 @@ import java.util.List;
 import org.projectfloodlight.openflow.protocol.match.Match;
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.devicemanager.IDevice;
@@ -38,6 +39,7 @@ public class RoutingDecision implements IRoutingDecision {
     protected IDevice srcDevice;
     protected List<IDevice> destDevices;
     protected List<SwitchPort> broadcastIntertfaces;
+    protected U64 descriptor;
 
     public RoutingDecision(DatapathId swDipd,
                                   OFPort inPort,
@@ -114,6 +116,16 @@ public class RoutingDecision implements IRoutingDecision {
         this.hardTimeout = hardTimeout;
     }
 
+	@Override
+	public U64 getDescriptor() {
+		return descriptor;
+	}
+
+	@Override
+	public void setDescriptor(U64 descriptor) {
+		this.descriptor = descriptor;
+	}
+
     @Override
     public void addToContext(FloodlightContext cntx) {
         rtStore.put(cntx, IRoutingDecision.CONTEXT_DECISION, this);
diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
index 648910916ed36c529e184a65113c44e8a4463fc8..39211be7371b7729fbe75336c09111c4650948d4 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
@@ -32,6 +32,7 @@ import net.floodlightcontroller.packet.BSN;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.LLDP;
 import net.floodlightcontroller.restserver.IRestApiService;
+import net.floodlightcontroller.routing.IRoutingDecisionChangedListener;
 import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.Link;
 import net.floodlightcontroller.routing.Route;
@@ -41,6 +42,7 @@ import org.projectfloodlight.openflow.protocol.*;
 import org.projectfloodlight.openflow.protocol.action.OFAction;
 import org.projectfloodlight.openflow.protocol.match.MatchField;
 import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.Masked;
 import org.projectfloodlight.openflow.types.OFBufferId;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.U64;
@@ -135,6 +137,9 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
 	 */
 	protected static final String PACKAGE = TopologyManager.class.getPackage().getName();
 	protected IDebugCounter ctrIncoming;
+	
+	/** Array list that contains all of the decisionChangedListeners */
+	protected ArrayList<IRoutingDecisionChangedListener> decisionChangedListeners;
 
 	//  Getter/Setter methods
 	/**
@@ -605,6 +610,41 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
 		result.add(getRoute(srcDpid, dstDpid, U64.of(0), tunnelEnabled));
 		return result;
 	}
+	
+    /** 
+     *  Registers an IRoutingDecisionChangedListener.
+     *   
+     *  @param {IRoutingDecisionChangedListener} listener - 
+     *  @return {void}
+     */
+	@Override
+	public void addRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener) {
+		decisionChangedListeners.add(listener);
+	}
+	
+	/** 
+     *  Deletes an IRoutingDecisionChangedListener.
+     *   
+     *  @param {IRoutingDecisionChangedListener} listener - 
+     *  @return {void}
+     */
+	@Override
+	public void removeRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener) {
+		decisionChangedListeners.remove(listener);
+	}
+
+	/** 
+     *  Listens for the event to the IRoutingDecisionChanged listener and calls routingDecisionChanged().
+     *   
+     *  @param {Iterable<Masked<U64>>} - event
+     *  @return {void}
+     */
+	@Override
+	public void handleRoutingDecisionChange(Iterable<Masked<U64>> changedDecisions) {
+		for(IRoutingDecisionChangedListener listener : decisionChangedListeners) {
+			listener.routingDecisionChanged(changedDecisions);
+		}
+	}
 
 	// ******************
 	// IOFMessageListener
@@ -743,6 +783,7 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
 		topologyAware = new ArrayList<ITopologyListener>();
 		ldUpdates = new LinkedBlockingQueue<LDUpdate>();
 		haListener = new HAListenerDelegate();
+		this.decisionChangedListeners = new ArrayList<IRoutingDecisionChangedListener>();
 		registerTopologyDebugCounters();
 	}
 
diff --git a/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java b/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java
index 5e0f87538b0a7f850446a826420418cdaa67e352..5d0e22b6447ebcd88ce8c937d4ea430f1e053ee8 100644
--- a/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java
+++ b/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java
@@ -109,4 +109,17 @@ public class AppCookieTest {
 
 
     }
+    
+    @Test
+    public void testAppFieldMask(){
+    	final int myAppId = 71;
+    	AppCookie.registerApp(myAppId, "TestFieldMask");
+    	U64 result = AppCookie.getAppFieldMask();
+    	U64 expectedMask = U64.of(0xfff0000000000000L);
+    	assertEquals(expectedMask, result);
+    	
+    	U64 cookie = AppCookie.makeCookie(myAppId, -1);
+    	U64 maskAppField = cookie.and(result);
+    	assertEquals(U64.of(0x470000000000000L),maskAppField);
+    }
 }
diff --git a/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java b/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java
index 9c0daa5c9b9f5e02101e86c6b43027e5252b1ca8..027d688b32d8415de450c80c2b619cbe3a4afe50 100644
--- a/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java
+++ b/src/test/java/net/floodlightcontroller/firewall/FirewallTest.java
@@ -17,11 +17,15 @@
 
 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 static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.reset;
 import static org.junit.Assert.*;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -31,6 +35,7 @@ import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.util.AppCookie;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.debugcounter.MockDebugCounterService;
 import net.floodlightcontroller.packet.ARP;
@@ -43,10 +48,13 @@ import net.floodlightcontroller.packet.UDP;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.restserver.RestApiServer;
 import net.floodlightcontroller.routing.IRoutingDecision;
+import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.storage.IStorageSourceService;
 import net.floodlightcontroller.storage.memory.MemoryStorageSource;
 import net.floodlightcontroller.test.FloodlightTestCase;
 
+import org.easymock.Capture;
+import org.easymock.CaptureType;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
@@ -61,9 +69,11 @@ import org.projectfloodlight.openflow.types.IPv4Address;
 import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
 import org.projectfloodlight.openflow.types.IpProtocol;
 import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.Masked;
 import org.projectfloodlight.openflow.types.OFBufferId;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U64;
 
 /**
  * Unit test for stateless firewall implemented as a Google Summer of Code project.
@@ -71,6 +81,7 @@ import org.projectfloodlight.openflow.types.TransportPort;
  * @author Amer Tahir
  */
 public class FirewallTest extends FloodlightTestCase {
+	protected IRoutingService routingService;
     protected FloodlightContext cntx;
     protected OFPacketIn packetIn;
     protected IOFSwitch sw;
@@ -83,6 +94,14 @@ public class FirewallTest extends FloodlightTestCase {
     private Firewall firewall;
     private MockDebugCounterService debugCounterService;
     public static String TestSwitch1DPID = "00:00:00:00:00:00:00:01";
+    private static final short APP_ID = 30;
+    static {
+                AppCookie.registerApp(APP_ID, "Firewall");
+        }
+    private static final U64 DENY_BCAST_COOKIE = AppCookie.makeCookie(APP_ID, 0xaaaaaaaa);
+    private static final U64 ALLOW_BCAST_COOKIE = AppCookie.makeCookie(APP_ID, 0x55555555);
+    private static final U64 RULE_MISS_COOKIE = AppCookie.makeCookie(APP_ID, -1);
+
 
     @Override
     @Before
@@ -95,6 +114,7 @@ public class FirewallTest extends FloodlightTestCase {
         firewall = new Firewall();
         MemoryStorageSource storageService = new MemoryStorageSource();
         RestApiServer restApi = new RestApiServer();
+        routingService = createMock(IRoutingService.class);
 
         // Mock switches
         DatapathId dpid = DatapathId.of(TestSwitch1DPID);
@@ -114,6 +134,7 @@ public class FirewallTest extends FloodlightTestCase {
         fmc.addService(IFirewallService.class, firewall);
         fmc.addService(IStorageSourceService.class, storageService);
         fmc.addService(IRestApiService.class, restApi);
+        fmc.addService(IRoutingService.class, routingService);
 
         debugCounterService.init(fmc);
         storageService.init(fmc);
@@ -240,6 +261,32 @@ public class FirewallTest extends FloodlightTestCase {
                 IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
                 (Ethernet)packet);
     }
+    
+    public boolean compareU64ListsOrdered(List<Masked<U64>> a,List<Masked<U64>> b){
+    	Object[] aArray = a.toArray();
+    	Object[] bArray = b.toArray();
+    	if (aArray.length != bArray.length) return false;
+    	for(int i = 0; i<aArray.length; i++){
+    		if(aArray[i].equals(bArray[i]) == false){
+    			return false;
+    		}
+    	}
+    	return true;
+    }
+    
+    @Test
+    public void enableFirewall() throws Exception{
+		Capture<ArrayList<Masked<U64>>> wc1 = EasyMock.newCapture(CaptureType.ALL);
+		routingService.handleRoutingDecisionChange(capture(wc1));
+		ArrayList<Masked<U64>> test_changes = new ArrayList<Masked<U64>>();
+
+		replay(routingService);
+		firewall.enableFirewall(true);
+		verify(routingService);
+		test_changes.add(Masked.of(Firewall.DEFAULT_COOKIE, AppCookie.getAppFieldMask()));
+
+		assertTrue(compareU64ListsOrdered(wc1.getValue(),test_changes));
+    }
 
     @Test
     public void testNoRules() throws Exception {
@@ -255,10 +302,15 @@ public class FirewallTest extends FloodlightTestCase {
         IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         // no rules to match, so firewall should deny
         assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP);
+        assertEquals(RULE_MISS_COOKIE, decision.getDescriptor());
     }
 
     @Test
     public void testReadRulesFromStorage() throws Exception {
+        Capture<ArrayList<Masked<U64>>> wc1 = EasyMock.newCapture(CaptureType.ALL);
+        routingService.handleRoutingDecisionChange(capture(wc1));
+        ArrayList<Masked<U64>> test_changes = new ArrayList<Masked<U64>>();
+        U64 singleRuleMask = AppCookie.getAppFieldMask().or(AppCookie.getUserFieldMask());
         // add 2 rules first
         FirewallRule rule = new FirewallRule();
         rule.in_port = OFPort.of(2);
@@ -266,7 +318,17 @@ public class FirewallTest extends FloodlightTestCase {
         rule.dl_dst = MacAddress.of("00:00:00:00:00:02");
         rule.priority = 1;
         rule.action = FirewallRule.FirewallAction.DROP;
+        replay(routingService);
         firewall.addRule(rule);
+        verify(routingService);
+        test_changes.add(Masked.of(AppCookie.makeCookie(APP_ID, rule.ruleid), singleRuleMask));
+        test_changes.add(Masked.of(RULE_MISS_COOKIE, singleRuleMask));
+        assertEquals(compareU64ListsOrdered(wc1.getValue(),test_changes),true);
+        reset(routingService);
+        // next rule
+        wc1 = EasyMock.newCapture(CaptureType.ALL);
+        test_changes = new ArrayList<Masked<U64>>();
+        routingService.handleRoutingDecisionChange(capture(wc1));
         rule = new FirewallRule();
         rule.in_port = OFPort.of(3);
         rule.dl_src = MacAddress.of("00:00:00:00:00:02");
@@ -276,9 +338,16 @@ public class FirewallTest extends FloodlightTestCase {
         rule.tp_dst = TransportPort.of(80);
         rule.priority = 2;
         rule.action = FirewallRule.FirewallAction.ALLOW;
+        replay(routingService);
         firewall.addRule(rule);
-
+        verify(routingService);
+        test_changes.add(Masked.of(AppCookie.makeCookie(APP_ID, rule.ruleid), singleRuleMask));
+        test_changes.add(Masked.of(RULE_MISS_COOKIE, singleRuleMask));
+        assertTrue(compareU64ListsOrdered(wc1.getValue(),test_changes));
+        reset(routingService);
+        
         List<FirewallRule> rules = firewall.readRulesFromStorage();
+        
         // verify rule 1
         FirewallRule r = rules.get(0);
         assertEquals(r.in_port, OFPort.of(2));
@@ -321,15 +390,26 @@ public class FirewallTest extends FloodlightTestCase {
         rule.priority = 1;
         firewall.addRule(rule);
         int rid = rule.ruleid;
+        reset(routingService);
+
+    	Capture<ArrayList<Masked<U64>>> wc1 = EasyMock.newCapture(CaptureType.ALL);
+    	routingService.handleRoutingDecisionChange(capture(wc1));
+        ArrayList<Masked<U64>> test_changes = new ArrayList<Masked<U64>>();
+        U64 singleRuleMask = AppCookie.getAppFieldMask().or(AppCookie.getUserFieldMask());
 
         List<Map<String, Object>> rulesFromStorage = firewall.getStorageRules();
         assertEquals(1, rulesFromStorage.size());
         assertEquals(Integer.parseInt((String)rulesFromStorage.get(0).get("ruleid")), rid);
 
         // delete rule
+        replay(routingService);
         firewall.deleteRule(rid);
+        verify(routingService);
+        test_changes.add(Masked.of(AppCookie.makeCookie(APP_ID, rule.ruleid), singleRuleMask));
         rulesFromStorage = firewall.getStorageRules();
         assertEquals(0, rulesFromStorage.size());
+        assertTrue(compareU64ListsOrdered(wc1.getValue(),test_changes));
+        reset(routingService);
     }
 
     @Test
@@ -373,6 +453,7 @@ public class FirewallTest extends FloodlightTestCase {
         rule.any_nw_dst = false;
         rule.priority = 1;
         firewall.addRule(rule);
+        U64 TCP_COOKIE = AppCookie.makeCookie(APP_ID, rule.ruleid);
 
         // simulate a packet-in events
 
@@ -382,6 +463,7 @@ public class FirewallTest extends FloodlightTestCase {
 
         IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         assertEquals(IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD, decision.getRoutingAction());
+        assertEquals(TCP_COOKIE, decision.getDescriptor());
 
         // clear decision
         IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION);
@@ -392,6 +474,7 @@ public class FirewallTest extends FloodlightTestCase {
 
         decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         assertEquals(IRoutingDecision.RoutingAction.DROP, decision.getRoutingAction());
+        assertEquals(RULE_MISS_COOKIE, decision.getDescriptor());
     }
 
     @Test
@@ -407,12 +490,14 @@ public class FirewallTest extends FloodlightTestCase {
         rule.tp_dst = TransportPort.of(80);
         rule.priority = 1;
         firewall.addRule(rule);
+        U64 TCP_COOKIE = AppCookie.makeCookie(APP_ID, rule.ruleid);
 
         // add block all rule
         rule = new FirewallRule();
         rule.action = FirewallRule.FirewallAction.DROP;
         rule.priority = 2;
         firewall.addRule(rule);
+        U64 BLOCK_ALL_COOKIE = AppCookie.makeCookie(APP_ID, rule.ruleid);
 
         assertEquals(2, firewall.rules.size());
 
@@ -424,6 +509,7 @@ public class FirewallTest extends FloodlightTestCase {
 
         IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
+        assertEquals(TCP_COOKIE, decision.getDescriptor());
 
         // clear decision
         IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION);
@@ -436,6 +522,7 @@ public class FirewallTest extends FloodlightTestCase {
 
         decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP);
+        assertEquals(BLOCK_ALL_COOKIE, decision.getDescriptor());
     }
 
     @Test
@@ -454,6 +541,7 @@ public class FirewallTest extends FloodlightTestCase {
         // broadcast-ARP traffic should be allowed
         IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         assertEquals(IRoutingDecision.RoutingAction.MULTICAST, decision.getRoutingAction());
+        assertEquals(ALLOW_BCAST_COOKIE, decision.getDescriptor());
 
         // clear decision
         IRoutingDecision.rtStore.remove(cntx, IRoutingDecision.CONTEXT_DECISION);
@@ -467,6 +555,7 @@ public class FirewallTest extends FloodlightTestCase {
         // ARP reply traffic should be denied
         decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP);
+        assertEquals(RULE_MISS_COOKIE, decision.getDescriptor());
     }
 
     @Test
@@ -488,6 +577,7 @@ public class FirewallTest extends FloodlightTestCase {
         // broadcast traffic should be allowed
         IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         assertEquals(IRoutingDecision.RoutingAction.MULTICAST, decision.getRoutingAction());
+        assertEquals(ALLOW_BCAST_COOKIE, decision.getDescriptor());
     }
 
     @Test
@@ -506,6 +596,7 @@ public class FirewallTest extends FloodlightTestCase {
         // malformed broadcast traffic should NOT be allowed
         IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.DROP);
+        assertEquals(DENY_BCAST_COOKIE, decision.getDescriptor());
     }
 
     @Test
@@ -521,6 +612,7 @@ public class FirewallTest extends FloodlightTestCase {
         rule.any_dl_dst = false;
         rule.priority = 1;
         firewall.addRule(rule);
+        U64 L2_LAYER_COOKIE = AppCookie.makeCookie(APP_ID, rule.ruleid);
 
         // add TCP deny all rule
         rule = new FirewallRule();
@@ -538,6 +630,7 @@ public class FirewallTest extends FloodlightTestCase {
 
         IRoutingDecision decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
         assertEquals(decision.getRoutingAction(), IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
+        assertEquals(L2_LAYER_COOKIE, decision.getDescriptor());
     }
 
     @Test
@@ -584,5 +677,17 @@ public class FirewallTest extends FloodlightTestCase {
         // Change dl_dst, rules no longer "same"
         rule2.dl_dst = MacAddress.of("00:01:02:03:04:05");
         assertFalse(rule1.isSameAs(rule2));
+
+    }
+    
+    /* Testing to make sure that the cookies are properly formatted with the correct info before hitting the firewall. */
+    @Test
+    public void cookieAddedSuccessfully() {
+    	assertEquals("DENY_BCAST_COOKIE app_id is not correct", APP_ID, AppCookie.extractApp(DENY_BCAST_COOKIE));
+    	assertEquals("DENY_BCAST_COOKIE user_id is not correct", 0xaaaaaaaa, AppCookie.extractUser(DENY_BCAST_COOKIE));
+    	assertEquals("ALLOW_BCAST_COOKIE app_id is not correct", APP_ID, AppCookie.extractApp(DENY_BCAST_COOKIE));
+    	assertEquals("ALLOW_BCAST_COOKIE user_id is not correct", 0x55555555, AppCookie.extractUser(ALLOW_BCAST_COOKIE));
+      	assertEquals("RULE_MISS_COOKIE app_id is not correct", APP_ID, AppCookie.extractApp(DENY_BCAST_COOKIE));
+      	assertEquals("RULE_MISS_COOKIE user_id is not correct", -1, AppCookie.extractUser(RULE_MISS_COOKIE));
     }
 }
diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
index 9d68ba9f98a4309d13fda155978e799f12b083db..beaf22ad490c5adaffb2ed63fcc97e5781153cba 100644
--- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
+++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -36,6 +37,7 @@ import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.test.MockThreadPoolService;
 import net.floodlightcontroller.core.types.NodePortTuple;
+import net.floodlightcontroller.core.util.AppCookie;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.debugcounter.MockDebugCounterService;
 import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier;
@@ -51,8 +53,10 @@ import net.floodlightcontroller.packet.IPacket;
 import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.packet.IPv6;
 import net.floodlightcontroller.packet.UDP;
+import net.floodlightcontroller.routing.IRoutingDecision.RoutingAction;
 import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.RoutingDecision;
 import net.floodlightcontroller.test.FloodlightTestCase;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.topology.ITopologyListener;
@@ -81,6 +85,7 @@ import org.projectfloodlight.openflow.types.IPv4Address;
 import org.projectfloodlight.openflow.types.IPv6Address;
 import org.projectfloodlight.openflow.types.IpProtocol;
 import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.Masked;
 import org.projectfloodlight.openflow.types.OFBufferId;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.TransportPort;
@@ -92,6 +97,8 @@ import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
 import org.sdnplatform.sync.ISyncService;
 import org.sdnplatform.sync.test.MockSyncService;
 
+import com.google.common.collect.ImmutableList;
+
 public class ForwardingTest extends FloodlightTestCase {
 	protected FloodlightContext cntx;
 	protected MockDeviceManager deviceManager;
@@ -176,6 +183,7 @@ public class ForwardingTest extends FloodlightTestCase {
 		expect(sw1.getId()).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(sw1.getOFFactory()).andReturn(factory).anyTimes();
 		expect(sw1.getBuffers()).andReturn(swFeatures.getNBuffers()).anyTimes();
+		
 
 		sw2 = EasyMock.createMock(IOFSwitch.class);
 		expect(sw2.getId()).andReturn(DatapathId.of(2L)).anyTimes();
@@ -316,6 +324,36 @@ public class ForwardingTest extends FloodlightTestCase {
 				IDeviceService.CONTEXT_DST_DEVICE);
 	}
 
+	static boolean messageListsEqualIgnoreXid(List<OFMessage> c1, List<OFMessage> c2) {
+		if (c1 == c2) {
+			return true;
+		}
+
+		if (c1 == null || c2 == null) {
+			return false;
+		}
+
+		if (c1.size() != c2.size()) {
+			return false;
+		}
+
+		Iterator<OFMessage> it1 = c1.iterator();
+		Iterator<OFMessage> it2 = c2.iterator();
+		while (it1.hasNext()) {
+			OFMessage m1 = it1.next();
+			OFMessage m2 = it2.next();
+			if (m1 == m2) {
+				continue;
+			}
+
+			if (m1 == null || m2 == null || !m1.equalsIgnoreXid(m2)) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
 	enum DestDeviceToLearn { NONE, DEVICE1 ,DEVICE2 };
 	public void learnDevices(DestDeviceToLearn destDeviceToLearn) {
 		// Build src and dest devices
@@ -445,8 +483,9 @@ public class ForwardingTest extends FloodlightTestCase {
 		nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(1)));
 		nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3)));
 		route.setPath(nptList);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce();
-
+		reset(routingEngine);
+		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
+		
 		// Expected Flow-mods
 		Match match = packetIn.getMatch();
 		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
@@ -515,8 +554,9 @@ public class ForwardingTest extends FloodlightTestCase {
 		nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(1)));
 		nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3)));
 		route.setPath(nptList);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce();
-
+		reset(routingEngine);
+		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
+		
 		// Expected Flow-mods
 		Match match = packetInIPv6.getMatch();
 		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
@@ -581,13 +621,14 @@ public class ForwardingTest extends FloodlightTestCase {
 		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce();
-
+		
 		// Expected Flow-mods
 		Match match = packetIn.getMatch();
 		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
 		List<OFAction> actions = new ArrayList<OFAction>();
 		actions.add(action);
+		
+		//routingEngine.addRoutingDecisionChangedListener(anyObject(IRoutingDecisionChangedListener.class));
 
 		OFFlowMod fm1 = factory.buildFlowAdd()
 				.setIdleTimeout((short)5)
@@ -612,6 +653,8 @@ public class ForwardingTest extends FloodlightTestCase {
 		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
 
 		// Reset mocks, trigger the packet in, and validate results
+		reset(routingEngine);
+		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
 		replay(sw1, sw2, routingEngine, topology);
 		forwarding.receive(sw1, this.packetIn, cntx);
 		verify(sw1, sw2, routingEngine);
@@ -635,8 +678,9 @@ public class ForwardingTest extends FloodlightTestCase {
 		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce();
-
+		reset(routingEngine);
+		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
+		
 		// Expected Flow-mods
 		Match match = packetInIPv6.getMatch();
 		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
@@ -743,6 +787,7 @@ public class ForwardingTest extends FloodlightTestCase {
 
 		// Set no destination attachment point or route
 		// expect no Flow-mod but expect the packet to be flooded
+		reset(routingEngine);
 
 		Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
 		
@@ -771,6 +816,8 @@ public class ForwardingTest extends FloodlightTestCase {
 	@Test
 	public void testForwardNoPathIPv6() throws Exception {
 		learnDevicesIPv6(DestDeviceToLearn.NONE);
+		
+		reset(routingEngine);
 
 		// Set no destination attachment point or route
 		// expect no Flow-mod but expect the packet to be flooded
@@ -800,4 +847,230 @@ public class ForwardingTest extends FloodlightTestCase {
 		
 		removeDeviceFromContext();
 	}
+	
+	/*
+	 * TODO Consider adding test cases for other Decision != null paths (I only added FORWARD and none of the paths had test cases)
+	 */
+	@Test
+	public void testForwardDecisionForwardingCookieZero() throws Exception {
+		learnDevices(DestDeviceToLearn.DEVICE2);
+		
+		Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
+		Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
+
+		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
+		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
+		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
+		reset(routingEngine);
+		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
+		
+		// Expected Flow-mods
+		Match match = packetIn.getMatch();
+		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
+		List<OFAction> actions = new ArrayList<OFAction>();
+		actions.add(action);
+		
+		RoutingDecision decision = new RoutingDecision(DatapathId.of(1L), OFPort.of(1), dstDevice1, RoutingAction.FORWARD);
+		decision.setDescriptor(U64.ZERO);
+		decision.addToContext(cntx);
+		
+		OFFlowMod fm1 = factory.buildFlowAdd()
+				.setIdleTimeout((short)5)
+				.setMatch(match)
+				.setActions(actions)
+				.setOutPort(OFPort.of(3))
+				.setBufferId(OFBufferId.NO_BUFFER)
+				.setCookie(U64.of(2L<< 52))
+				.setPriority(1)
+				.build();
+
+		// Record expected packet-outs/flow-mods
+		expect(sw1.write(capture(wc1))).andReturn(true).once();
+		expect(sw1.write(capture(wc2))).andReturn(true).once();
+
+		reset(topology);
+		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
+		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
+		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
+
+		// Reset mocks, trigger the packet in, and validate results
+		replay(sw1, sw2, routingEngine, topology);
+		forwarding.receive(sw1, this.packetIn, cntx);
+		verify(sw1, sw2, routingEngine);
+
+		assertTrue(wc1.hasCaptured());
+		assertTrue(wc2.hasCaptured());
+
+		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1));
+		assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOut));
+	}
+	
+	@Test
+	public void testForwardDecisionForwardingCookieNotZero() throws Exception {
+		learnDevices(DestDeviceToLearn.DEVICE2);
+		
+		Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
+		Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
+
+		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
+		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
+		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
+		reset(routingEngine);
+		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.of(0x200000FFffFFffL))).andReturn(route).atLeastOnce();
+		
+		// Expected Flow-mods
+		Match match = packetIn.getMatch();
+		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
+		List<OFAction> actions = new ArrayList<OFAction>();
+		actions.add(action);
+		
+		RoutingDecision decision = new RoutingDecision(DatapathId.of(1L), OFPort.of(1), dstDevice1, RoutingAction.FORWARD);
+		decision.setDescriptor(U64.of(0x00000000ffffffffL));
+		decision.addToContext(cntx);
+		//RoutingDecision de2 = (RoutingDecision) RoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); // Same as decision
+		//(DatapathId swDipd, OFPort inPort, IDevice srcDevice, RoutingAction action);
+		
+		OFFlowMod fm1 = factory.buildFlowAdd()
+				.setIdleTimeout((short)5)
+				.setMatch(match)
+				.setActions(actions)
+				.setOutPort(OFPort.of(3))
+				.setBufferId(OFBufferId.NO_BUFFER)
+				.setCookie(U64.of(2L<< 52 | 0xFFffFFffL))
+				.setPriority(1)
+				.build();
+
+		// Record expected packet-outs/flow-mods
+		expect(sw1.write(capture(wc1))).andReturn(true).once();
+		expect(sw1.write(capture(wc2))).andReturn(true).once();
+
+		reset(topology);
+		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
+		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
+		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
+
+		// Reset mocks, trigger the packet in, and validate results
+		replay(sw1, sw2, routingEngine, topology);
+		forwarding.receive(sw1, this.packetIn, cntx);
+		verify(sw1, sw2, routingEngine);
+
+		assertTrue(wc1.hasCaptured());
+		assertTrue(wc2.hasCaptured());
+		
+		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1));
+		assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOut));
+	}
+
+	@Test
+	public void testForwardDeleteFlowsByDescriptorSingle() throws Exception {
+		reset(routingEngine);
+		
+		Capture<List<OFMessage>> wc1 = EasyMock.newCapture(CaptureType.ALL);
+		Capture<List<OFMessage>> wc2 = EasyMock.newCapture(CaptureType.ALL);
+		
+		List<Masked<U64>> descriptors = new ArrayList<Masked<U64>>();
+		descriptors.add(Masked.of(
+				U64.of(0x00000000FFffFFffL),
+				U64.of(0x00200000FFffFFffL))); // User mask = 0xffFFffFFL which is forwarding.DECISION_MASK/AppCookie.USER_MASK//descriptors.add(Masked.of(U64.of(0x00000000FFffFFffL),U64.of(0x0020000000000000L)));//descriptors.add(Masked.of(U64.of(0xffFFffFFffFFffFFL),U64.of(0x00200000FFffFFffL))); // Mask = 0xffFFffFFffFFffFFL which is the value returned by forwarding.AppCookie.getAppFieldMask()//descriptors.add(Masked.of(U64.of(0xffFFffFFffFFffFFL),U64.of(0x0020000000000000L)));
+		
+		expect(sw1.getStatus()).andReturn(IOFSwitch.SwitchStatus.MASTER).anyTimes();
+		expect(sw2.getStatus()).andReturn(IOFSwitch.SwitchStatus.MASTER).anyTimes();
+		
+		expect(sw1.write(capture(wc1))).andReturn(ImmutableList.of()).once();
+		expect(sw2.write(capture(wc2))).andReturn(ImmutableList.of()).once();
+		
+		replay(sw1, sw2, routingEngine);
+		forwarding.deleteFlowsByDescriptor(descriptors);
+		verify(sw1, sw2, routingEngine);
+		
+		assertTrue(wc1.hasCaptured());
+		assertTrue(wc2.hasCaptured());
+		
+		Masked<U64> masked_cookie = Masked.of(
+				AppCookie.makeCookie(Forwarding.FORWARDING_APP_ID, (int)4294967295L),
+				AppCookie.getAppFieldMask().or(U64.of(0xffffffffL)));
+		List<OFMessage> msgs_test = new ArrayList<>();
+		msgs_test.add( 	factory.buildFlowDelete()
+						.setCookie(masked_cookie.getValue())
+						.setCookieMask(masked_cookie.getMask())
+						.build());
+		
+		assertTrue(messageListsEqualIgnoreXid(wc1.getValue(), msgs_test));
+		assertTrue(messageListsEqualIgnoreXid(wc2.getValue(), msgs_test));
+	}
+	
+	@Test
+	public void testForwardDeleteFlowsByDescriptorMultiple() throws Exception {
+		reset(routingEngine);
+		
+		Capture<List<OFMessage>> wc1 = EasyMock.newCapture(CaptureType.ALL);
+		Capture<List<OFMessage>> wc2 = EasyMock.newCapture(CaptureType.ALL);
+		
+		List<Masked<U64>> descriptors = new ArrayList<Masked<U64>>();
+		descriptors.add(Masked.of(
+				U64.of(0x00000000FFffFFffL),
+				U64.of(0x00200000FFffFFffL))); // User mask = 0xffFFffFFL which is forwarding.DECISION_MASK/AppCookie.USER_MASK
+		descriptors.add(Masked.of(
+				U64.of(0x00000000FFffFFffL),
+				U64.of(0x0020000000000000L)));
+		
+		expect(sw1.getStatus()).andReturn(IOFSwitch.SwitchStatus.MASTER).anyTimes();
+		expect(sw2.getStatus()).andReturn(IOFSwitch.SwitchStatus.MASTER).anyTimes();
+		
+		expect(sw1.write(capture(wc1))).andReturn(ImmutableList.of()).once();
+		expect(sw2.write(capture(wc2))).andReturn(ImmutableList.of()).once();
+		
+		replay(sw1, sw2, routingEngine);
+		forwarding.deleteFlowsByDescriptor(descriptors);
+		verify(sw1, sw2, routingEngine);
+		
+		assertTrue(wc1.hasCaptured());
+		assertTrue(wc2.hasCaptured());
+		
+		// Cookies
+		Masked<U64> masked_cookie = Masked.of(	AppCookie.makeCookie(Forwarding.FORWARDING_APP_ID, (int)4294967295L),
+												AppCookie.getAppFieldMask().or(U64.of(0xffffffffL)));
+		Masked<U64> masked_cookie2 = Masked.of(	AppCookie.makeCookie(Forwarding.FORWARDING_APP_ID, 0),
+												AppCookie.getAppFieldMask().or(U64.of(0x0L)));
+		// Add cookies to a msg set
+		List<OFMessage> msgs_test = new ArrayList<OFMessage>();
+		msgs_test.add( 	factory.buildFlowDelete()
+						.setCookie(masked_cookie.getValue())
+						.setCookieMask(masked_cookie.getMask())
+						.build());
+		msgs_test.add( 	factory.buildFlowDelete()
+						.setCookie(masked_cookie2.getValue())
+						.setCookieMask(masked_cookie2.getMask())
+						.build());
+		assertTrue(messageListsEqualIgnoreXid(wc1.getValue(), msgs_test));
+		assertTrue(messageListsEqualIgnoreXid(wc2.getValue(), msgs_test));
+	}
+	
+	@Test
+	public void testForwardDeleteFlowsByDescriptorNoCookies() throws Exception {
+		reset(routingEngine);
+		
+		List<Masked<U64>> descriptors = new ArrayList<Masked<U64>>();
+		
+		replay(routingEngine);
+		forwarding.deleteFlowsByDescriptor(descriptors);
+		verify(routingEngine);
+	}
+	
+	@Test
+	public void testForwardDeleteFlowsByDescriptorNoCookiesContainer() throws Exception {
+		reset(routingEngine);
+		
+		List<Masked<U64>> descriptors = null;
+		
+		replay(routingEngine);
+		forwarding.deleteFlowsByDescriptor(descriptors);
+		verify(routingEngine);
+	}
 }
\ No newline at end of file