Import Floodlight v0.90
diff --git a/src/ext/floodlight/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/ext/floodlight/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
new file mode 100644
index 0000000..22312c1
--- /dev/null
+++ b/src/ext/floodlight/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
@@ -0,0 +1,692 @@
+/**
+ *    Copyright 2011, Big Switch Networks, Inc. 
+ *    Originally created by David Erickson, Stanford University
+ * 
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+package net.floodlightcontroller.routing;
+
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFMessageListener;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.annotations.LogMessageCategory;
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
+import net.floodlightcontroller.core.util.AppCookie;
+import net.floodlightcontroller.counter.ICounterStoreService;
+import net.floodlightcontroller.devicemanager.IDevice;
+import net.floodlightcontroller.devicemanager.IDeviceListener;
+import net.floodlightcontroller.devicemanager.IDeviceService;
+import net.floodlightcontroller.devicemanager.SwitchPort;
+import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.packet.IPacket;
+import net.floodlightcontroller.routing.IRoutingService;
+import net.floodlightcontroller.routing.IRoutingDecision;
+import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.topology.ITopologyService;
+import net.floodlightcontroller.topology.NodePortTuple;
+import net.floodlightcontroller.util.OFMessageDamper;
+import net.floodlightcontroller.util.TimedCache;
+
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract base class for implementing a forwarding module.  Forwarding is
+ * responsible for programming flows to a switch in response to a policy
+ * decision.
+ */
+@LogMessageCategory("Flow Programming")
+public abstract class ForwardingBase 
+    implements IOFMessageListener, IDeviceListener {
+    
+    protected static Logger log =
+            LoggerFactory.getLogger(ForwardingBase.class);
+
+    protected static int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
+    protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms 
+
+    public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds
+    public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
+    
+    protected IFloodlightProviderService floodlightProvider;
+    protected IDeviceService deviceManager;
+    protected IRoutingService routingEngine;
+    protected ITopologyService topology;
+    protected ICounterStoreService counterStore;
+    
+    protected OFMessageDamper messageDamper;
+    
+    // for broadcast loop suppression
+    protected boolean broadcastCacheFeature = true;
+    public final int prime1 = 2633;  // for hash calculation
+    public final static int prime2 = 4357;  // for hash calculation
+    public TimedCache<Long> broadcastCache =
+        new TimedCache<Long>(100, 5*1000);  // 5 seconds interval;
+
+    // flow-mod - for use in the cookie
+    public static final int FORWARDING_APP_ID = 2; // TODO: This must be managed
+                                                   // by a global APP_ID class
+    public long appCookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
+    
+    // Comparator for sorting by SwitchCluster
+    public Comparator<SwitchPort> clusterIdComparator =
+            new Comparator<SwitchPort>() {
+                @Override
+                public int compare(SwitchPort d1, SwitchPort d2) {
+                    Long d1ClusterId = 
+                            topology.getL2DomainId(d1.getSwitchDPID());
+                    Long d2ClusterId = 
+                            topology.getL2DomainId(d2.getSwitchDPID());
+                    return d1ClusterId.compareTo(d2ClusterId);
+                }
+            };
+            
+    /**
+     * init data structures
+     * 
+     */
+    protected void init() {
+        messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY, 
+                                            EnumSet.of(OFType.FLOW_MOD),
+                                            OFMESSAGE_DAMPER_TIMEOUT);
+    }
+
+    /**
+     * Adds a listener for devicemanager and registers for PacketIns.
+     */
+    protected void startUp() {
+        deviceManager.addListener(this);
+        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
+    }
+
+    /**
+     * Returns the application name "forwarding".
+     */
+    @Override
+    public String getName() {
+        return "forwarding";
+    }
+
+    /**
+     * All subclasses must define this function if they want any specific
+     * forwarding action
+     * 
+     * @param sw
+     *            Switch that the packet came in from
+     * @param pi
+     *            The packet that came in
+     * @param decision
+     *            Any decision made by a policy engine
+     */
+    public abstract Command
+            processPacketInMessage(IOFSwitch sw, OFPacketIn pi,
+                                   IRoutingDecision decision,
+                                   FloodlightContext cntx);
+
+    @Override
+    public Command receive(IOFSwitch sw, OFMessage msg,
+                           FloodlightContext cntx) {
+        switch (msg.getType()) {
+            case PACKET_IN:
+                IRoutingDecision decision = null;
+                if (cntx != null)
+                     decision =
+                             IRoutingDecision.rtStore.get(cntx,
+                                                          IRoutingDecision.CONTEXT_DECISION);
+
+                return this.processPacketInMessage(sw,
+                                                   (OFPacketIn) msg,
+                                                   decision,
+                                                   cntx);
+            default:
+                break;
+        }
+        return Command.CONTINUE;
+    }
+
+    /**
+     * Push routes from back to front
+     * @param route Route to push
+     * @param match OpenFlow fields to match on
+     * @param srcSwPort Source switch port for the first hop
+     * @param dstSwPort Destination switch port for final hop
+     * @param cookie The cookie to set in each flow_mod
+     * @param cntx The floodlight context
+     * @param reqeustFlowRemovedNotifn if set to true then the switch would
+     * send a flow mod removal notification when the flow mod expires
+     * @param doFlush if set to true then the flow mod would be immediately
+     *        written to the switch
+     * @param flowModCommand flow mod. command to use, e.g. OFFlowMod.OFPFC_ADD,
+     *        OFFlowMod.OFPFC_MODIFY etc.
+     * @return srcSwitchIincluded True if the source switch is included in this route
+     */
+    @LogMessageDocs({
+        @LogMessageDoc(level="WARN",
+            message="Unable to push route, switch at DPID {dpid} not available",
+            explanation="A switch along the calculated path for the " +
+                        "flow has disconnected.",
+            recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+            message="Failure writing flow mod",
+            explanation="An I/O error occurred while writing a " +
+                        "flow modification to a switch",
+            recommendation=LogMessageDoc.CHECK_SWITCH)            
+    })
+    public boolean pushRoute(Route route, OFMatch match, 
+                             Integer wildcard_hints,
+                             OFPacketIn pi,
+                             long pinSwitch,
+                             long cookie, 
+                             FloodlightContext cntx,
+                             boolean reqeustFlowRemovedNotifn,
+                             boolean doFlush,
+                             short   flowModCommand) {
+
+        boolean srcSwitchIncluded = false;
+        OFFlowMod fm =
+                (OFFlowMod) floodlightProvider.getOFMessageFactory()
+                                              .getMessage(OFType.FLOW_MOD);
+        OFActionOutput action = new OFActionOutput();
+        action.setMaxLength((short)0xffff);
+        List<OFAction> actions = new ArrayList<OFAction>();
+        actions.add(action);
+
+        fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
+            .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+            .setBufferId(OFPacketOut.BUFFER_ID_NONE)
+            .setCookie(cookie)
+            .setCommand(flowModCommand)
+            .setMatch(match)
+            .setActions(actions)
+            .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
+
+        List<NodePortTuple> switchPortList = route.getPath();
+
+        for (int indx = switchPortList.size()-1; indx > 0; indx -= 2) {
+            // indx and indx-1 will always have the same switch DPID.
+            long switchDPID = switchPortList.get(indx).getNodeId();
+            IOFSwitch sw = floodlightProvider.getSwitches().get(switchDPID);
+            if (sw == null) {
+                if (log.isWarnEnabled()) {
+                    log.warn("Unable to push route, switch at DPID {} " +
+                            "not available", switchDPID);
+                }
+                return srcSwitchIncluded;
+            }
+
+            // set the match.
+            fm.setMatch(wildcard(match, sw, wildcard_hints));
+
+            // set buffer id if it is the source switch
+            if (1 == indx) {
+                // Set the flag to request flow-mod removal notifications only for the
+                // source switch. The removal message is used to maintain the flow
+                // cache. Don't set the flag for ARP messages - TODO generalize check
+                if ((reqeustFlowRemovedNotifn)
+                        && (match.getDataLayerType() != Ethernet.TYPE_ARP)) {
+                    fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
+                    match.setWildcards(fm.getMatch().getWildcards());
+                }
+            }
+
+            short outPort = switchPortList.get(indx).getPortId();
+            short inPort = switchPortList.get(indx-1).getPortId();
+            // set input and output ports on the switch
+            fm.getMatch().setInputPort(inPort);
+            ((OFActionOutput)fm.getActions().get(0)).setPort(outPort);
+
+            try {
+                counterStore.updatePktOutFMCounterStore(sw, fm);
+                if (log.isTraceEnabled()) {
+                    log.trace("Pushing Route flowmod routeIndx={} " + 
+                            "sw={} inPort={} outPort={}",
+                            new Object[] {indx,
+                                          sw,
+                                          fm.getMatch().getInputPort(),
+                                          outPort });
+                }
+                messageDamper.write(sw, fm, cntx);
+                if (doFlush) {
+                    sw.flush();
+                }
+
+                // Push the packet out the source switch
+                if (sw.getId() == pinSwitch) {
+                    // TODO: Instead of doing a packetOut here we could also 
+                    // send a flowMod with bufferId set.... 
+                    pushPacket(sw, match, pi, outPort, cntx);
+                    srcSwitchIncluded = true;
+                }
+            } catch (IOException e) {
+                log.error("Failure writing flow mod", e);
+            }
+
+            try {
+                fm = fm.clone();
+            } catch (CloneNotSupportedException e) {
+                log.error("Failure cloning flow mod", e);
+            }
+        }
+
+        return srcSwitchIncluded;
+    }
+
+    protected OFMatch wildcard(OFMatch match, IOFSwitch sw,
+                               Integer wildcard_hints) {
+        if (wildcard_hints != null) {
+            return match.clone().setWildcards(wildcard_hints.intValue());
+        }
+        return match.clone();
+    }
+    
+    /**
+     * Pushes a packet-out to a switch. If bufferId != BUFFER_ID_NONE we 
+     * assume that the packetOut switch is the same as the packetIn switch
+     * and we will use the bufferId 
+     * Caller needs to make sure that inPort and outPort differs
+     * @param packet    packet data to send
+     * @param sw        switch from which packet-out is sent
+     * @param bufferId  bufferId
+     * @param inPort    input port
+     * @param outPort   output port
+     * @param cntx      context of the packet
+     * @param flush     force to flush the packet.
+     */
+    @LogMessageDocs({
+        @LogMessageDoc(level="ERROR",
+            message="BufferId is not and packet data is null. " +
+                    "Cannot send packetOut. " +
+                    "srcSwitch={dpid} inPort={port} outPort={port}",
+            explanation="The switch send a malformed packet-in." +
+                        "The packet will be dropped",
+            recommendation=LogMessageDoc.REPORT_SWITCH_BUG),
+        @LogMessageDoc(level="ERROR",
+            message="Failure writing packet out",
+            explanation="An I/O error occurred while writing a " +
+                    "packet out to a switch",
+            recommendation=LogMessageDoc.CHECK_SWITCH)            
+    })
+    public void pushPacket(IPacket packet, 
+                           IOFSwitch sw,
+                           int bufferId,
+                           short inPort,
+                           short outPort, 
+                           FloodlightContext cntx,
+                           boolean flush) {
+        
+        
+        if (log.isTraceEnabled()) {
+            log.trace("PacketOut srcSwitch={} inPort={} outPort={}", 
+                      new Object[] {sw, inPort, outPort});
+        }
+
+        OFPacketOut po =
+                (OFPacketOut) floodlightProvider.getOFMessageFactory()
+                                                .getMessage(OFType.PACKET_OUT);
+
+        // set actions
+        List<OFAction> actions = new ArrayList<OFAction>();
+        actions.add(new OFActionOutput(outPort, (short) 0xffff));
+
+        po.setActions(actions)
+          .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
+        short poLength =
+                (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
+
+        // set buffer_id, in_port
+        po.setBufferId(bufferId);
+        po.setInPort(inPort);
+
+        // set data - only if buffer_id == -1
+        if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
+            if (packet == null) {
+                log.error("BufferId is not set and packet data is null. " +
+                          "Cannot send packetOut. " +
+                        "srcSwitch={} inPort={} outPort={}",
+                        new Object[] {sw, inPort, outPort});
+                return;
+            }
+            byte[] packetData = packet.serialize();
+            poLength += packetData.length;
+            po.setPacketData(packetData);
+        }
+
+        po.setLength(poLength);
+
+        try {
+            counterStore.updatePktOutFMCounterStore(sw, po);
+            messageDamper.write(sw, po, cntx, flush);
+        } catch (IOException e) {
+            log.error("Failure writing packet out", e);
+        }
+    }
+
+    /**
+     * Pushes a packet-out to a switch.  The assumption here is that
+     * the packet-in was also generated from the same switch.  Thus, if the input
+     * port of the packet-in and the outport are the same, the function will not 
+     * push the packet-out.
+     * @param sw        switch that generated the packet-in, and from which packet-out is sent
+     * @param match     OFmatch
+     * @param pi        packet-in
+     * @param outport   output port
+     * @param cntx      context of the packet
+     */
+    protected void pushPacket(IOFSwitch sw, OFMatch match, OFPacketIn pi, 
+                           short outport, FloodlightContext cntx) {
+
+        if (pi == null) {
+            return;
+        } else if (pi.getInPort() == outport){
+            log.warn("Packet out not sent as the outport matches inport. {}",
+                     pi);
+            return;
+        }
+
+        // The assumption here is (sw) is the switch that generated the 
+        // packet-in. If the input port is the same as output port, then
+        // the packet-out should be ignored.
+        if (pi.getInPort() == outport) {
+            if (log.isDebugEnabled()) {
+                log.debug("Attempting to do packet-out to the same " + 
+                          "interface as packet-in. Dropping packet. " + 
+                          " SrcSwitch={}, match = {}, pi={}", 
+                          new Object[]{sw, match, pi});
+                return;
+            }
+        }
+
+        if (log.isTraceEnabled()) {
+            log.trace("PacketOut srcSwitch={} match={} pi={}", 
+                      new Object[] {sw, match, pi});
+        }
+
+        OFPacketOut po =
+                (OFPacketOut) floodlightProvider.getOFMessageFactory()
+                                                .getMessage(OFType.PACKET_OUT);
+
+        // set actions
+        List<OFAction> actions = new ArrayList<OFAction>();
+        actions.add(new OFActionOutput(outport, (short) 0xffff));
+
+        po.setActions(actions)
+          .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
+        short poLength =
+                (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
+
+        // If the switch doens't support buffering set the buffer id to be none
+        // otherwise it'll be the the buffer id of the PacketIn
+        if (sw.getBuffers() == 0) {
+            // We set the PI buffer id here so we don't have to check again below
+            pi.setBufferId(OFPacketOut.BUFFER_ID_NONE);
+            po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
+        } else {
+            po.setBufferId(pi.getBufferId());
+        }
+
+        po.setInPort(pi.getInPort());
+
+        // If the buffer id is none or the switch doesn's support buffering
+        // we send the data with the packet out
+        if (pi.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
+            byte[] packetData = pi.getPacketData();
+            poLength += packetData.length;
+            po.setPacketData(packetData);
+        }
+
+        po.setLength(poLength);
+
+        try {
+            counterStore.updatePktOutFMCounterStore(sw, po);
+            messageDamper.write(sw, po, cntx);
+        } catch (IOException e) {
+            log.error("Failure writing packet out", e);
+        }
+    }
+
+    
+    /**
+     * Write packetout message to sw with output actions to one or more
+     * output ports with inPort/outPorts passed in.
+     * @param packetData
+     * @param sw
+     * @param inPort
+     * @param ports
+     * @param cntx
+     */
+    public void packetOutMultiPort(byte[] packetData,
+                                   IOFSwitch sw,
+                                   short inPort,
+                                   Set<Integer> outPorts,
+                                   FloodlightContext cntx) {
+        //setting actions
+        List<OFAction> actions = new ArrayList<OFAction>();
+
+        Iterator<Integer> j = outPorts.iterator();
+
+        while (j.hasNext())
+        {
+            actions.add(new OFActionOutput(j.next().shortValue(), 
+                                           (short) 0));
+        }
+
+        OFPacketOut po = 
+                (OFPacketOut) floodlightProvider.getOFMessageFactory().
+                getMessage(OFType.PACKET_OUT);
+        po.setActions(actions);
+        po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * 
+                outPorts.size()));
+
+        // set buffer-id to BUFFER_ID_NONE, and set in-port to OFPP_NONE
+        po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
+        po.setInPort(inPort);
+
+        // data (note buffer_id is always BUFFER_ID_NONE) and length
+        short poLength = (short)(po.getActionsLength() + 
+                OFPacketOut.MINIMUM_LENGTH);
+        poLength += packetData.length;
+        po.setPacketData(packetData);
+        po.setLength(poLength);
+
+        try {
+            counterStore.updatePktOutFMCounterStore(sw, po);
+            if (log.isTraceEnabled()) {
+                log.trace("write broadcast packet on switch-id={} " + 
+                        "interfaces={} packet-out={}",
+                        new Object[] {sw.getId(), outPorts, po});
+            }
+            messageDamper.write(sw, po, cntx);
+
+        } catch (IOException e) {
+            log.error("Failure writing packet out", e);
+        }
+    }
+    
+    /** 
+     * @see packetOutMultiPort
+     * Accepts a PacketIn instead of raw packet data. Note that the inPort
+     * and switch can be different than the packet in switch/port
+     */
+    public void packetOutMultiPort(OFPacketIn pi,
+                                   IOFSwitch sw,
+                                   short inPort,
+                                   Set<Integer> outPorts,
+                                   FloodlightContext cntx) {
+        packetOutMultiPort(pi.getPacketData(), sw, inPort, outPorts, cntx);
+    }
+    
+    /** 
+     * @see packetOutMultiPort
+     * Accepts an IPacket instead of raw packet data. Note that the inPort
+     * and switch can be different than the packet in switch/port
+     */
+    public void packetOutMultiPort(IPacket packet,
+                                   IOFSwitch sw,
+                                   short inPort,
+                                   Set<Integer> outPorts,
+                                   FloodlightContext cntx) {
+        packetOutMultiPort(packet.serialize(), sw, inPort, outPorts, cntx);
+    }
+
+    protected boolean isInBroadcastCache(IOFSwitch sw, OFPacketIn pi,
+                        FloodlightContext cntx) {
+        // Get the cluster id of the switch.
+        // Get the hash of the Ethernet packet.
+        if (sw == null) return true;  
+        
+        // If the feature is disabled, always return false;
+        if (!broadcastCacheFeature) return false;
+
+        Ethernet eth = 
+            IFloodlightProviderService.bcStore.get(cntx,
+                IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+        
+        Long broadcastHash;
+        broadcastHash = topology.getL2DomainId(sw.getId()) * prime1 +
+                        pi.getInPort() * prime2 + eth.hashCode();
+        if (broadcastCache.update(broadcastHash)) {
+            sw.updateBroadcastCache(broadcastHash, pi.getInPort());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected boolean isInSwitchBroadcastCache(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
+        if (sw == null) return true;
+        
+        // If the feature is disabled, always return false;
+        if (!broadcastCacheFeature) return false;
+
+        // Get the hash of the Ethernet packet.
+        Ethernet eth =
+                IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+
+        long hash =  pi.getInPort() * prime2 + eth.hashCode();
+
+        // some FORWARD_OR_FLOOD packets are unicast with unknown destination mac
+        return sw.updateBroadcastCache(hash, pi.getInPort());
+    }
+
+    @LogMessageDocs({
+        @LogMessageDoc(level="ERROR",
+            message="Failure writing deny flow mod",
+            explanation="An I/O error occurred while writing a " +
+                    "deny flow mod to a switch",
+            recommendation=LogMessageDoc.CHECK_SWITCH)            
+    })
+    public static boolean
+            blockHost(IFloodlightProviderService floodlightProvider,
+                      SwitchPort sw_tup, long host_mac,
+                      short hardTimeout, long cookie) {
+
+        if (sw_tup == null) {
+            return false;
+        }
+
+        IOFSwitch sw = 
+                floodlightProvider.getSwitches().get(sw_tup.getSwitchDPID());
+        if (sw == null) return false;
+        int inputPort = sw_tup.getPort();
+        log.debug("blockHost sw={} port={} mac={}",
+                  new Object[] { sw, sw_tup.getPort(), new Long(host_mac) });
+
+        // Create flow-mod based on packet-in and src-switch
+        OFFlowMod fm =
+                (OFFlowMod) floodlightProvider.getOFMessageFactory()
+                                              .getMessage(OFType.FLOW_MOD);
+        OFMatch match = new OFMatch();
+        List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to
+                                                            // drop
+        match.setDataLayerSource(Ethernet.toByteArray(host_mac))
+             .setInputPort((short)inputPort)
+             .setWildcards(OFMatch.OFPFW_ALL & ~OFMatch.OFPFW_DL_SRC
+                     & ~OFMatch.OFPFW_IN_PORT);
+        fm.setCookie(cookie)
+          .setHardTimeout((short) hardTimeout)
+          .setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
+          .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+          .setBufferId(OFPacketOut.BUFFER_ID_NONE)
+          .setMatch(match)
+          .setActions(actions)
+          .setLengthU(OFFlowMod.MINIMUM_LENGTH); // +OFActionOutput.MINIMUM_LENGTH);
+
+        try {
+            log.debug("write drop flow-mod sw={} match={} flow-mod={}",
+                      new Object[] { sw, match, fm });
+            // TODO: can't use the message damper sine this method is static
+            sw.write(fm, null);
+        } catch (IOException e) {
+            log.error("Failure writing deny flow mod", e);
+            return false;
+        }
+        return true;
+
+    }
+
+    @Override
+    public void deviceAdded(IDevice device) {
+        // NOOP
+    }
+
+    @Override
+    public void deviceRemoved(IDevice device) {
+        // NOOP
+    }
+
+    @Override
+    public void deviceMoved(IDevice device) {
+    }
+
+    @Override
+    public void deviceIPV4AddrChanged(IDevice device) {
+
+    }
+
+    @Override
+    public void deviceVlanChanged(IDevice device) {
+
+    }
+
+    @Override
+    public boolean isCallbackOrderingPrereq(OFType type, String name) {
+        return (type.equals(OFType.PACKET_IN) && 
+                (name.equals("topology") || 
+                 name.equals("devicemanager")));
+    }
+
+    @Override
+    public boolean isCallbackOrderingPostreq(OFType type, String name) {
+        return false;
+    }
+
+}