diff --git a/src/main/java/net/floodlightcontroller/core/util/AppCookie.java b/src/main/java/net/floodlightcontroller/core/util/AppCookie.java
index 5406bbd8c9a6a2b92b423db0598d225713b83fa4..370256fb1596f98aee6f1946b4008f8f26e2f3b4 100644
--- a/src/main/java/net/floodlightcontroller/core/util/AppCookie.java
+++ b/src/main/java/net/floodlightcontroller/core/util/AppCookie.java
@@ -69,6 +69,13 @@ 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);
+    }
+
     /**
      * 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..0fb28b24c46b73002f63830800bd812c3922595f 100644
--- a/src/main/java/net/floodlightcontroller/firewall/Firewall.java
+++ b/src/main/java/net/floodlightcontroller/firewall/Firewall.java
@@ -39,6 +39,7 @@ import org.projectfloodlight.openflow.types.IpProtocol;
 import org.projectfloodlight.openflow.types.MacAddress;
 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 +48,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;
 
@@ -76,6 +78,13 @@ 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);
 
 	// service modules needed
 	protected IFloodlightProviderService floodlightProvider;
@@ -309,8 +318,11 @@ 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);
 			}
 			break;
@@ -560,6 +572,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 +582,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 +595,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 +611,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 +630,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 9552487f7d11cdb9a700d0d42d4b223635466311..1062f14de6ffc7109a53df84c77722ad4b83f0d9 100644
--- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
@@ -76,6 +76,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;
@@ -88,6 +89,10 @@ import org.slf4j.LoggerFactory;
 
 public class Forwarding extends ForwardingBase implements IFloodlightModule, IOFSwitchListener, ILinkDiscoveryListener {
 	protected static Logger log = LoggerFactory.getLogger(Forwarding.class);
+	private final 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) {
@@ -104,11 +109,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);
@@ -123,21 +128,105 @@ 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);
+	}
+
+	/**
+	 * 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) {
+		List<Masked<U64>> result = new ArrayList<Masked<U64>>();
+
+		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.
+
+			result.add(
+					Masked.of(
+							AppCookie.makeCookie(FORWARDING_APP_ID, (int)user_value),
+							AppCookie.getAppFieldMask().or(U64.of(user_mask))
+					)
+			);
+		}
+
+		return result;
+	}
+
+	/**
+	 * 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()) {
+			for (DatapathId dpid : switchService.getAllSwitchDpids()) {
+				IOFSwitch sw = switchService.getActiveSwitch(dpid);
+				if (sw == null) {
+					continue;
+				}
+
+				// Would like to swap these for loops and only build the message set once,
+				// but doing so would assume all switches are using the same OF protocol version.
+				Set<OFMessage> msgs = new HashSet<OFMessage>();
+				for (Masked<U64> masked_cookie : masked_cookies) {
+					msgs.add(
+						sw.getOFFactory().buildFlowDelete()
+							.setCookie(masked_cookie.getValue())
+							.setCookieMask(masked_cookie.getMask())
+								.build()
+						);
+				}
+
+				sw.write(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("Droppingggg");
 		fmb.setCookie(cookie)
 		.setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
@@ -160,7 +249,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
 		}
 	}
 
-	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();
@@ -177,7 +266,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;
 			}
 
@@ -224,24 +313,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.getSwitchDPID(),
-					dstDap.getPort(), U64.of(0)); //cookie = 0, i.e., default route
+					dstDap.getPort(), 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) {
 				log.debug("pushRoute inPort={} route={} " +
@@ -271,7 +360,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);
 		}
 	}
 
@@ -384,9 +473,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();
@@ -615,14 +705,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());
 						srcSw.write(msgs);
@@ -638,14 +730,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());
 						dstSw.write(msgs);
diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java b/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
index 6af24c6e35a14bdcbc141c24ad020d4423f7de13..6d3b67f8e9fda5538b89cc938fb46c0ac917d252 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,6 @@ 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/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);