diff --git a/src/main/java/net/floodlightcontroller/core/ControllerId.java b/src/main/java/net/floodlightcontroller/core/ControllerId.java
deleted file mode 100644
index 6fd347b234219ae4bee0b36923d5cf3893018b0c..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/ControllerId.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package net.floodlightcontroller.core;
-
-import org.sdnplatform.sync.ISyncService;
-import org.sdnplatform.sync.internal.config.ClusterConfig;
-
-import com.google.common.base.Optional;
-
-/** This class represents a unique id of this controller node. It is derived from
- *  the node id as returned by {@link ISyncService#getLocalNodeId()}.
- *  <p>
- *  Note that the unconfigured Node Id is not supported. Users are encouraged to
- *  represent an unconfigured Controller Node by {@link Optional#absent()}.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- */
-public class ControllerId {
-    private final short nodeId;
-
-    private ControllerId(short nodeId) {
-        if(nodeId == ClusterConfig.NODE_ID_UNCONFIGURED)
-            throw new IllegalArgumentException("nodeId is unconfigured");
-
-        this.nodeId = nodeId;
-    }
-
-    public short getNodeId() {
-        return nodeId;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + nodeId;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        ControllerId other = (ControllerId) obj;
-        if (nodeId != other.nodeId)
-            return false;
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return Short.toString(nodeId);
-    }
-
-    public static ControllerId of(short nodeId) {
-        return new ControllerId(nodeId);
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/Deliverable.java b/src/main/java/net/floodlightcontroller/core/Deliverable.java
deleted file mode 100644
index c82f31d85bd2ffab1567ac8fee25a926315f77b7..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/Deliverable.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package net.floodlightcontroller.core;
-
-/**
- * abstracts the 'back side' of a Future that is being listened on, i.e., an
- * object that receives a result or an error of the computaton once it is ready.
- * A deliverable can accept multiple computation results, indicated by the
- * return value of deliver.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- * @param <T>
- *            type of the result of the computation
- */
-public interface Deliverable<T> {
-    public static enum Status {
-        DONE,
-        CONTINUE
-    }
-
-    /**
-     * deliver the result after a successful computation has completed
-     *
-     * @param msg
-     *            result
-     * @return whether the delivery is complete with this result.
-     **/
-    public void deliver(T msg);
-
-    /** deliver an error result for the computation
-     * @param cause throwable that describes the error
-     */
-    void deliverError(Throwable cause);
-
-    /** whether or not the deliverable has been completed before.
-     */
-    boolean isDone();
-
-    boolean cancel(boolean mayInterruptIfRunning);
-}
diff --git a/src/main/java/net/floodlightcontroller/core/DeliverableListenableFuture.java b/src/main/java/net/floodlightcontroller/core/DeliverableListenableFuture.java
deleted file mode 100644
index 1e724ac51819fc6a52d26a649ded028f0bd917cf..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/DeliverableListenableFuture.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.floodlightcontroller.core;
-
-import com.google.common.util.concurrent.AbstractFuture;
-
-/** Implementation of a ListenableFuture that provides a Deliverable interface to
- *  the provider.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- * @see Deliverable
- * @param <T>
- */
-public class DeliverableListenableFuture<T> extends AbstractFuture<T> implements Deliverable<T> {
-    @Override
-    public void deliver(final T result) {
-        set(result);
-    }
-
-    @Override
-    public void deliverError(final Throwable cause) {
-        setException(cause);
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/GenTableMap.java b/src/main/java/net/floodlightcontroller/core/GenTableMap.java
deleted file mode 100644
index ef32a19796dfc977183fe39cf8f55fdf5049a6cb..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/GenTableMap.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package net.floodlightcontroller.core;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-import javax.annotation.concurrent.Immutable;
-
-import org.projectfloodlight.openflow.protocol.OFBsnGentableDescStatsEntry;
-import org.projectfloodlight.openflow.protocol.OFBsnGentableDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFBsnGentableDescStatsRequest;
-import org.projectfloodlight.openflow.types.GenTableId;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableMap;
-
-/** A registry for GenTables. Initialized during switch handshake, based on a
- *  {@link OFBsnGentableDescStatsRequest}. The table for a particular switch
- *  can be retrieved via {@link IOFSwitch#getGenTableMap()}.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- */
-@Immutable
-public class GenTableMap {
-    private static final Logger logger = LoggerFactory.getLogger(GenTableMap.class);
-
-    private final Map<GenTableId, OFBsnGentableDescStatsEntry> idMap;
-    private final Map<String, OFBsnGentableDescStatsEntry> nameMap;
-
-    // an empty gentable map
-    private GenTableMap() {
-        idMap = ImmutableMap.of();
-        nameMap = ImmutableMap.of();
-    }
-
-    public GenTableMap(Iterable<OFBsnGentableDescStatsEntry> entries) {
-        // note: not using an ImmutableMap.Builder here, because we need to
-        // check for duplicates
-        Map<GenTableId, OFBsnGentableDescStatsEntry> idBuildMap = new LinkedHashMap<>();
-        Map<String, OFBsnGentableDescStatsEntry> nameBuildMap = new LinkedHashMap<>();
-
-        for (OFBsnGentableDescStatsEntry e : entries) {
-            GenTableId id = e.getTableId();
-            String name = e.getName();
-            if (idBuildMap.containsKey(id)) {
-                logger.warn("Duplicate table id " + id + " - entry {} present. Ignoring new entry {}",
-                        idBuildMap.get(id), e);
-                continue;
-            }
-            if (nameBuildMap.containsKey(name)) {
-                logger.warn(
-                        "Duplicate table name " + name + " - entry named {} present. Ignoring new entry {}",
-                        nameBuildMap.get(name), e);
-                continue;
-            }
-            idBuildMap.put(id, e);
-            nameBuildMap.put(name, e);
-        }
-        this.idMap = ImmutableMap.copyOf(idBuildMap);
-        this.nameMap = ImmutableMap.copyOf(nameBuildMap);
-    }
-
-    public Set<GenTableId> getIds() {
-        return idMap.keySet();
-    }
-
-    public Set<String> getNames() {
-        return nameMap.keySet();
-    }
-
-    public Collection<OFBsnGentableDescStatsEntry> getEntries() {
-        return idMap.values();
-    }
-
-    public boolean hasEntry(GenTableId id) {
-        return idMap.containsKey(id);
-    }
-
-    /** retrieve a GenTable Description from the map by id.
-     *
-     * @param id
-     * @return the retrieved gen  table description.
-     * @throws GenTableNotFoundException if no gentable with the given id was found in the map
-     */
-    @Nonnull
-    public OFBsnGentableDescStatsEntry getEntry(GenTableId id) throws GenTableNotFoundException {
-        OFBsnGentableDescStatsEntry entry = idMap.get(id);
-        if(entry == null)
-            throw new GenTableNotFoundException(id, idMap.values());
-        return entry;
-    }
-
-    public boolean hasEntry(String name) {
-        return nameMap.containsKey(name);
-    }
-
-    /** retrieve a GenTable Description from the map by name.
-     *
-     * @param name
-     * @return the retrieved gen table description.
-     * @throws GenTableNotFoundException if no gentable with the given name was found in the map
-     */
-    @Nonnull
-    public OFBsnGentableDescStatsEntry getEntry(String name) throws GenTableNotFoundException {
-        OFBsnGentableDescStatsEntry entry = nameMap.get(name);
-        if(entry == null)
-            throw new GenTableNotFoundException(name, nameMap.values());
-        return entry;
-    }
-
-    public final static GenTableMap empty() {
-        return new GenTableMap();
-    }
-
-    public static GenTableMap of(Iterable<OFBsnGentableDescStatsReply> replies) {
-        List<OFBsnGentableDescStatsEntry> allEntries = new ArrayList<>();
-        for(OFBsnGentableDescStatsReply reply: replies) {
-            allEntries.addAll(reply.getEntries());
-        }
-        return new GenTableMap(allEntries);
-    }
-
-    @Override
-    public String toString() {
-        return idMap.toString();
-    }
-
-    public int size() {
-        return idMap.size();
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/GenTableNotFoundException.java b/src/main/java/net/floodlightcontroller/core/GenTableNotFoundException.java
deleted file mode 100644
index 544fc1e8488a0fa33ee934be31d3d6e03ce64ca2..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/GenTableNotFoundException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package net.floodlightcontroller.core;
-
-import org.projectfloodlight.openflow.protocol.OFBsnGentableDescStatsEntry;
-import org.projectfloodlight.openflow.types.GenTableId;
-
-/** A GenTable was not found in the {@link GenTableMap}.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- */
-public class GenTableNotFoundException extends RuntimeException {
-    private static final long serialVersionUID = 1L;
-
-    public GenTableNotFoundException(String name, Iterable<OFBsnGentableDescStatsEntry> available) {
-        super(getMessageForName(name, available));
-    }
-
-    private static String getMessageForName(String name,
-            Iterable<OFBsnGentableDescStatsEntry> available) {
-        return String.format("Table not found: %s (available tables: %s)", name, availableDescr(available));
-    }
-
-    public GenTableNotFoundException(GenTableId id, Iterable<OFBsnGentableDescStatsEntry> available) {
-        super(getMessageForId(id, available));
-    }
-
-    private static String getMessageForId(GenTableId id,
-            Iterable<OFBsnGentableDescStatsEntry> available) {
-        return String.format("Table not found: %s (available tables: %s)", id, availableDescr(available));
-    }
-
-    private static String availableDescr(Iterable<OFBsnGentableDescStatsEntry> available) {
-        StringBuilder b = new StringBuilder();
-        boolean first = true;
-        for(OFBsnGentableDescStatsEntry e: available) {
-            if(!first)
-                b.append(", ");
-            first = false;
-            b.append(e.getName()).append("=").append(e.getTableId());
-        }
-        return b.toString();
-    }
-
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/HARole.java b/src/main/java/net/floodlightcontroller/core/HARole.java
deleted file mode 100644
index 0c2886f1e179579fc0b011317cdf8362a95cab9f..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/HARole.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package net.floodlightcontroller.core;
-
-import org.projectfloodlight.openflow.protocol.OFControllerRole;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * HARole describes the role that a given controller node currently plays in the
- * management of the SDN network. Controller nodes can be either
- * <ul>
- * <li>ACTIVE - currently controlling the network
- * <li>STANDBY - standing by in case of a fail-over from the ACTIVE node
- * </ul>
- * At any given time there SHOULD be at most one ACTIVE node in the network
- * (this invariant cannot be strictly guranteed for certain split-brain
- * situtations). There can be multiple STANDBY controllers. There are other
- * HA-related roles in the system. Try to not confuse them.
- * <ul>
- * <li>On the cluster management/bigsync layer {@link ISyncService} determines a
- * DOMAIN LEADER / DOMAIN FOLLOWER (which are exposed via
- * <li>On the OF layer, switch connections can be in either MASTER, SLAVE or
- * EQUAL {@link Role} (exposed by {@link IOFSwitchListener}).
- * </ul>
- * Most applications and modules trying to decide something on the ACTIVE node
- * should base that decision on the HARole.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- */
-public enum HARole {
-    /** This controller node is currently actively managing the SDN network. At any given
-     *  time, there should be at most one ACTIVE node. When the ACTIVE node fails, a STANDBY
-     *  node is determined to become ACTIVE.
-     */
-    ACTIVE(OFControllerRole.ROLE_MASTER),
-
-    /** This controller node is currently standing by and not managing the networking. There
-     *  may be more than one STANDBY nodes in the network.
-     */
-    STANDBY(OFControllerRole.ROLE_SLAVE);
-
-    private static final Logger logger = LoggerFactory.getLogger(HARole.class);
-    private final OFControllerRole ofRole;
-
-    HARole(OFControllerRole ofRole) {
-        this.ofRole = ofRole;
-    }
-
-    /** a backwards-compatible {@link #valueOf} that accepts the old terms "MASTER" and "SLAVE"
-     *  and normalizes them to ACTIVE and STANDBY.
-     *
-     * @param roleString
-     * @return an HARole
-     * @throws IllegalArgumentException - if no such role can be found.
-     */
-    public static HARole valueOfBackwardsCompatible(String roleString) throws IllegalArgumentException {
-        roleString = roleString.trim().toUpperCase();
-        if("MASTER".equals(roleString)) {
-            logger.warn("got legacy role name MASTER - normalized to ACTIVE", roleString);
-            if(logger.isDebugEnabled()) {
-               logger.debug("Legacy role call stack", new IllegalArgumentException());
-            }
-            roleString = "ACTIVE";
-        } else if ("SLAVE".equals(roleString)) {
-            logger.warn("got legacy role name SLAVE - normalized to STANDBY", roleString);
-            if(logger.isDebugEnabled()) {
-               logger.debug("Legacy role call stack", new IllegalArgumentException());
-            }
-            roleString = "STANDBY";
-        }
-        return valueOf(roleString);
-    }
-
-    public OFControllerRole getOFRole() {
-        return ofRole;
-    }
-
-    public static HARole ofOFRole(OFControllerRole role) {
-        switch(role) {
-            case ROLE_MASTER:
-            case ROLE_EQUAL:
-                return ACTIVE;
-            case ROLE_SLAVE:
-                return STANDBY;
-            default:
-                throw new IllegalArgumentException("Unmappable controller role: " + role);
-        }
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
index ce3e1786f90660064f7cc0e8e0ed6b634670ce5d..c0aa1fd6d5faa9426c7580d7e02fc685c0a96021 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -17,6 +17,8 @@
 
 package net.floodlightcontroller.core;
 
+import java.util.HashMap;
+
 import java.util.List;
 import java.util.Set;
 import java.util.Map;
@@ -24,22 +26,11 @@ import java.util.Map;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.packet.Ethernet;
 
-import org.jboss.netty.util.Timer;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.HARole;
-import net.floodlightcontroller.core.IHAListener;
-import net.floodlightcontroller.core.IInfoProvider;
-import net.floodlightcontroller.core.IOFMessageListener;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.RoleInfo;
-import net.floodlightcontroller.core.internal.RoleManager;
-import net.floodlightcontroller.core.internal.Controller.IUpdate;
-import net.floodlightcontroller.core.internal.Controller.ModuleLoaderState;
-
-import net.floodlightcontroller.core.FloodlightContextStore;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFType;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.vendor.nicira.OFRoleVendorData;
+
 /**
  * The interface exposed by the core bundle that allows you to interact
  * with connected switches.
@@ -54,7 +45,38 @@ public interface IFloodlightProviderService extends
      * representation of the payload of a packet-in message.
      */
     public static final String CONTEXT_PI_PAYLOAD =
-            "org.projectfloodlight.core.IFloodlightProvider.piPayload";
+            "net.floodlightcontroller.core.IFloodlightProvider.piPayload";
+
+    /**
+     * The role of the controller as used by the OF 1.2 and OVS failover and
+     * load-balancing mechanism.
+     */
+    public static enum Role {
+        EQUAL(OFRoleVendorData.NX_ROLE_OTHER),
+        MASTER(OFRoleVendorData.NX_ROLE_MASTER),
+        SLAVE(OFRoleVendorData.NX_ROLE_SLAVE);
+
+        private final int nxRole;
+
+        private Role(int nxRole) {
+            this.nxRole = nxRole;
+        }
+
+        private static Map<Integer,Role> nxRoleToEnum
+                = new HashMap<Integer,Role>();
+        static {
+            for(Role r: Role.values())
+                nxRoleToEnum.put(r.toNxRole(), r);
+        }
+        public int toNxRole() {
+            return nxRole;
+        }
+        // Return the enum representing the given nxRole or null if no
+        // such role exists
+        public static Role fromNxRole(int nxRole) {
+            return nxRoleToEnum.get(nxRole);
+        }
+    };
 
     /**
      * A FloodlightContextStore object that can be used to retrieve the
@@ -63,15 +85,6 @@ public interface IFloodlightProviderService extends
     public static final FloodlightContextStore<Ethernet> bcStore =
             new FloodlightContextStore<Ethernet>();
 
-    /**
-     * Service name used in the service directory representing
-     * the OpenFlow controller-switch channel
-     *
-     * @see  ILocalServiceAddressTracker
-     * @see  IClusterServiceAddressDirectory
-     */
-    public static final String SERVICE_DIRECTORY_SERVICE_NAME = "openflow";
-
     /**
      * Adds an OpenFlow message listener
      * @param type The OFType the component wants to listen for
@@ -93,52 +106,77 @@ public interface IFloodlightProviderService extends
     public Map<OFType, List<IOFMessageListener>> getListeners();
 
     /**
-     * Get the current role of the controller
+     * If the switch with the given DPID is known to any controller in the
+     * cluster, this method returns the associated IOFSwitch instance. As such
+     * the returned switches not necessarily connected or in master role for
+     * the local controller.
+     *
+     * Multiple calls to this method with the same DPID may return different
+     * IOFSwitch references. A caller must not store or otherwise rely on
+     * IOFSwitch references to be constant over the lifecycle of a switch.
+     *
+     * @param dpid the dpid of the switch to query
+     * @return the IOFSwitch instance associated with the dpid, null if no
+     * switch with the dpid is known to the cluster
      */
-    public HARole getRole();
+    public IOFSwitch getSwitch(long dpid);
 
     /**
-     * Get the current role of the controller
+     * Returns a snapshot of the set DPIDs for all known switches.
+     *
+     * The returned set is owned by the caller: the caller can modify it at
+     * will and changes to the known switches are not reflected in the returned
+     * set. The caller needs to call getAllSwitchDpids() if an updated
+     * version is needed.
+     *
+     * See {@link #getSwitch(long)} for what  "known" switch is.
+     * @return the set of DPIDs of all known switches
      */
-    public RoleInfo getRoleInfo();
+    public Set<Long> getAllSwitchDpids();
 
     /**
-     * Get the current mapping of controller IDs to their IP addresses
-     * Returns a copy of the current mapping.
-     * @see IHAListener
+     * Return a snapshot
+     * FIXME: asdf
+     * @return
      */
-    public Map<String,String> getControllerNodeIPs();
+    public Map<Long,IOFSwitch> getAllSwitchMap();
 
     /**
-     * Gets the ID of the controller
+     * Get the current role of the controller
      */
-    public String getControllerId();
+    public Role getRole();
 
     /**
-     * Gets the controller hostname
-     * @return the controller hostname
+     * Get the current role of the controller
      */
-    public String getOFHostname();
+    public RoleInfo getRoleInfo();
 
     /**
-     * Gets the controller's openflow port
-     * @return the controller's openflow port
+     * Get the current mapping of controller IDs to their IP addresses
+     * Returns a copy of the current mapping.
+     * @see IHAListener
      */
-    public int getOFPort();
+    public Map<String,String> getControllerNodeIPs();
+
 
     /**
      * Set the role of the controller
      * @param role The new role for the controller node
      * @param changeDescription The reason or other information for this role change
      */
-    public void setRole(HARole role, String changeDescription);
+    public void setRole(Role role, String changeDescription);
 
     /**
-     * Add an update task for asynchronous, serialized execution
-     *
-     * @param update
+     * Add a switch listener
+     * @param listener The module that wants to listen for events
+     */
+    public void addOFSwitchListener(IOFSwitchListener listener);
+
+    /**
+     * Remove a switch listener
+     * @param listener The The module that no longer wants to listen for events
      */
-    public void addUpdateToQueue(IUpdate update);
+    public void removeOFSwitchListener(IOFSwitchListener listener);
 
     /**
      * Adds a listener for HA role events
@@ -152,13 +190,53 @@ public interface IFloodlightProviderService extends
      */
     public void removeHAListener(IHAListener listener);
 
+    /**
+     * Add a listener for ready-for-flow-reconcile events
+     * @param l
+     */
+    public void addReadyForReconcileListener(IReadyForReconcileListener l);
+
+    /**
+     * Terminate the process
+     */
+    public void terminate();
+
+    /**
+     * Re-injects an OFMessage back into the packet processing chain
+     * @param sw The switch to use for the message
+     * @param msg the message to inject
+     * @return True if successfully re-injected, false otherwise
+     * @throws NullPointerException if switch or msg is null
+     */
+    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg);
+
+    /**
+     * Re-injects an OFMessage back into the packet processing chain
+     * @param sw The switch to use for the message
+     * @param msg the message to inject
+     * @param bContext a floodlight context to use if required. Can be null
+     * @return True if successfully re-injected, false otherwise
+     * @throws NullPointerException if switch or msg is null
+     */
+    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
+            FloodlightContext bContext);
+
     /**
      * Process written messages through the message listeners for the controller
      * @param sw The switch being written to
      * @param m the message
+     * @param bc any accompanying context object. Can be null in which case a
+     * new context will be allocated and passed to listeners
      * @throws NullPointerException if switch or msg is null
      */
-    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m);
+    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
+            FloodlightContext bc);
+
+    /**
+     * Gets the BasicFactory
+     * @return an OpenFlow message factory
+     */
+    public BasicFactory getOFMessageFactory();
 
     /**
      * Run the main I/O loop of the Controller.
@@ -187,12 +265,21 @@ public interface IFloodlightProviderService extends
     */
    public Map<String, Object> getControllerInfo(String type);
 
+
    /**
     * Return the controller start time in  milliseconds
     * @return
     */
    public long getSystemStartTime();
 
+   /**
+    * Configure controller to always clear the flow table on the switch,
+    * when it connects to controller. This will be true for first time switch
+    * reconnect, as well as a switch re-attaching to Controller after HA
+    * switch over to ACTIVE role
+    */
+   public void setAlwaysClearFlowsOnSwActivate(boolean value);
+
    /**
     * Get controller memory information
     */
@@ -205,38 +292,30 @@ public interface IFloodlightProviderService extends
    public Long getUptime();
 
    /**
-    * Get the set of port prefixes that will define an UPLINK port.
-    * @return The set of prefixes
+    * Adds an OFSwitch driver
+    *  @param manufacturerDescriptionPrefix Register the given prefix
+    * with the driver.
+    * @param driver A IOFSwitchDriver instance to handle IOFSwitch instaniation
+    * for the given manufacturer description prefix
+    * @throws IllegalStateException If the the manufacturer description is
+    * already registered
+    * @throws NullPointerExeption if manufacturerDescriptionPrefix is null
+    * @throws NullPointerExeption if driver is null
     */
-   public Set<String> getUplinkPortPrefixSet();
-
-
-   public void handleMessage(IOFSwitch sw, OFMessage m,
-                          FloodlightContext bContext);
+   public void addOFSwitchDriver(String desc, IOFSwitchDriver driver);
 
    /**
-    * Gets a hash wheeled timer to be used for for timeout scheduling
-    * @return a hash wheeled timer
+    * Record a switch event in in-memory debug-event
+    * @param switchDPID
+    * @param reason Reason for this event
+    * @param flushNow see debug-event flushing in IDebugEventService
     */
-   public Timer getTimer();
+   public void addSwitchEvent(long switchDPID, String reason, boolean flushNow);
 
    /**
-    * Gets the role manager
-    * @return the role manager
-    */
-   public RoleManager getRoleManager();
-
-   /**
-    * Gets the current module loading state.
-    * @return the current module loading state.
-    */
-   ModuleLoaderState getModuleLoaderState();
-
-   /**
-    * Gets the current number of worker threads
-    * @return Used for netty setup
+    * Get the set of port prefixes that will define an UPLINK port.
+    * @return The set of prefixes
     */
-   public int getWorkerThreads();
+   public Set<String> getUplinkPortPrefixSet();
 
 }
-
diff --git a/src/main/java/net/floodlightcontroller/core/IHAListener.java b/src/main/java/net/floodlightcontroller/core/IHAListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ffe82fd586b1012f29c24d397eb6c212a5aa02e
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IHAListener.java
@@ -0,0 +1,45 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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.core;
+
+import java.util.Map;
+
+public interface IHAListener extends IListener<HAListenerTypeMarker> {
+
+    /**
+     * This notification is fired if the controller's initial role was SLAVE
+     * and the controller is now transitioning to MASTER.
+     * Modules need to read their initial role in startUp from floodlight
+     * provider.
+     */
+    public void transitionToMaster();
+
+    /**
+     * Gets called when the IP addresses of the controller nodes in the
+     * controller cluster change. All parameters map controller ID to
+     * the controller's IP.
+     *
+     * @param curControllerNodeIPs The current mapping of controller IDs to IP
+     * @param addedControllerNodeIPs These IPs were added since the last update
+     * @param removedControllerNodeIPs These IPs were removed since the last update
+     */
+    public void controllerNodeIPsChanged(
+            Map<String, String> curControllerNodeIPs,
+            Map<String, String> addedControllerNodeIPs,
+            Map<String, String> removedControllerNodeIPs
+            );
+}
diff --git a/src/main/java/net/floodlightcontroller/core/IOFConnection.java b/src/main/java/net/floodlightcontroller/core/IOFConnection.java
deleted file mode 100644
index a14021fbd47b087495b57bdd3b1736966df0a798..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/IOFConnection.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package net.floodlightcontroller.core;
-
-import java.net.SocketAddress;
-
-import java.util.Date;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFAuxId;
-
-
-/** Contract for an openflow connection to a switch.
- *  Provides message write and request/response handling capabilities.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- */
-public interface IOFConnection extends IOFMessageWriter {
-
-    /**
-     * Retrieves the date the connection connected to this controller
-     * @return the date
-     */
-    Date getConnectedSince();
-
-    /**
-     * Flush all flows queued for this switch in the current thread.
-     * NOTE: The contract is limited to the current thread
-     */
-    void flush();
-
-    /** @return the DatapathId of the switch associated with the connection */
-    DatapathId getDatapathId();
-
-    /** @return the OFAuxId of the this connection */
-    OFAuxId getAuxId();
-
-    /**
-    * Get the IP address of the remote (switch) end of the connection
-    * @return the inet address
-    */
-    SocketAddress getRemoteInetAddress();
-
-    /**
-     * Get the IP address of the local end of the connection
-     *
-     * @return the inet address
-     */
-    SocketAddress getLocalInetAddress();
-
-    /**
-     * Get's the OFFactory that this connection was constructed with.
-     * This is the factory that was found in the features reply during
-     * the channel handshake
-     * @return The connection's OFFactory
-     */
-    OFFactory getOFFactory();
-
-    /** @return whether this connection is currently (still) connected to the controller.
-     */
-    boolean isConnected();
-
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/IOFConnectionBackend.java b/src/main/java/net/floodlightcontroller/core/IOFConnectionBackend.java
deleted file mode 100644
index 0ec7a9e1b2b081b34c813d5d9dd959028e1e49cc..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/IOFConnectionBackend.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package net.floodlightcontroller.core;
-
-import net.floodlightcontroller.core.internal.IOFConnectionListener;
-
-public interface IOFConnectionBackend extends IOFConnection {
-    /**
-     * Disconnect the channel
-     */
-    void disconnect();
-
-    /**
-     * Cancel all pending request
-     */
-    void cancelAllPendingRequests();
-
-    /** @return whether the output stream associated with this connection
-     *  is currently writeable (for throttling)
-     */
-    boolean isWritable();
-
-    /** set the message/closing listener for this connection */
-    void setListener(IOFConnectionListener listener);
-}
diff --git a/src/main/java/net/floodlightcontroller/core/IOFMessageListener.java b/src/main/java/net/floodlightcontroller/core/IOFMessageListener.java
index 1fe71529c9e64d364c92a0d2255083169a737dc8..00fdac1f99379ee8aa1e5dfee00de6bd4da9a4f1 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFMessageListener.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFMessageListener.java
@@ -17,8 +17,8 @@
 
 package net.floodlightcontroller.core;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFType;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
 
 /**
  *
diff --git a/src/main/java/net/floodlightcontroller/core/IOFMessageWriter.java b/src/main/java/net/floodlightcontroller/core/IOFMessageWriter.java
deleted file mode 100644
index bd27181f19e9170fac71db1557942dcc8cef0510..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/IOFMessageWriter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
-*    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.core;
-
-import java.util.List;
-
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFRequest;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * An interface to describe classes that write OF messages.
- * E.g. IOFSwitch, IOFConnection
- */
-
-public interface IOFMessageWriter{
-
-    /**
-     * Writes to the OFMessage to the output stream.
-     *
-     * <p><b>Note:</b> this method has fire-and-forget semantics. When the connection is
-     * not currently connected, it will silently discard the messages.
-     *
-     * @param m
-     */
-    void write(OFMessage m);
-
-    /**
-     * Writes the list of messages to the output stream.
-     *
-     * <p><b>Note:</b> this method has fire-and-forget semantics. When the connection is
-     * not currently connected, it will silently discard the messages.
-     *
-     * @param msglist
-     */
-    void write(Iterable<OFMessage> msglist);
-    
-    /** write an OpenFlow Request message, register for a single corresponding reply message
-     *  or error message.
-     *
-     * @param request
-     * @return a Future object that can be used to retrieve the asynchrounous
-     *         response when available.
-     *
-     *         If the connection is not currently connected, will
-     *         return a Future that immediately fails with a @link{SwitchDisconnectedException}.
-     */
-    <R extends OFMessage> ListenableFuture<R> writeRequest(OFRequest<R> request);
-
-    /** write a Stats (Multipart-) request, register for all corresponding reply messages.
-     * Returns a Future object that can be used to retrieve the List of asynchronous
-     * OFStatsReply messages when it is available.
-     *
-     * @param request stats request
-     * @return Future object wrapping OFStatsReply
-     *         If the connection is not currently connected, will
-     *         return a Future that immediately fails with a @link{SwitchDisconnectedException}.
-     */
-    <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> writeStatsRequest(
-            OFStatsRequest<REPLY> request);
-}
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb27460401007cdc639d4c8ee38cc73101ce0c40
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -0,0 +1,669 @@
+/**
+*    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.core;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Future;
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.internal.Controller;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.util.OrderedCollection;
+
+import org.jboss.netty.channel.Channel;
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPortStatus;
+import org.openflow.protocol.OFStatisticsReply;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import org.openflow.protocol.statistics.OFStatistics;
+
+/**
+ *
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface IOFSwitch {
+    // Attribute keys
+    public static final String SWITCH_DESCRIPTION_FUTURE = "DescriptionFuture";
+    public static final String SWITCH_SUPPORTS_NX_ROLE = "supportsNxRole";
+    public static final String SWITCH_IS_CORE_SWITCH = "isCoreSwitch";
+    public static final String PROP_FASTWILDCARDS = "FastWildcards";
+    public static final String PROP_REQUIRES_L3_MATCH = "requiresL3Match";
+    public static final String PROP_SUPPORTS_OFPP_TABLE = "supportsOfppTable";
+    public static final String PROP_SUPPORTS_OFPP_FLOOD = "supportsOfppFlood";
+    public static final String PROP_SUPPORTS_NETMASK_TBL = "supportsNetmaskTbl";
+
+    public enum OFPortType {
+        NORMAL("normal"),         // normal port (default)
+        TUNNEL("tunnel"),         // tunnel port
+        UPLINK("uplink"),         // uplink port (on a virtual switch)
+        MANAGEMENT("management"), // for in-band management
+        TUNNEL_LOOPBACK("tunnel-loopback");
+
+        private final String value;
+        OFPortType(String v) {
+            value = v;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+
+        public static OFPortType fromString(String str) {
+            for (OFPortType m : OFPortType.values()) {
+                if (m.value.equals(str)) {
+                    return m;
+                }
+            }
+            return OFPortType.NORMAL;
+        }
+    }
+
+    /**
+     * Describes a change of an open flow port
+     */
+    public static class PortChangeEvent {
+        public final ImmutablePort port;
+        public final PortChangeType type;
+        /**
+         * @param port
+         * @param type
+         */
+        public PortChangeEvent(ImmutablePort port,
+                               PortChangeType type) {
+            this.port = port;
+            this.type = type;
+        }
+        /* (non-Javadoc)
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((port == null) ? 0 : port.hashCode());
+            result = prime * result + ((type == null) ? 0 : type.hashCode());
+            return result;
+        }
+        /* (non-Javadoc)
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (obj == null) return false;
+            if (getClass() != obj.getClass()) return false;
+            PortChangeEvent other = (PortChangeEvent) obj;
+            if (port == null) {
+                if (other.port != null) return false;
+            } else if (!port.equals(other.port)) return false;
+            if (type != other.type) return false;
+            return true;
+        }
+        /* (non-Javadoc)
+         * @see java.lang.Object#toString()
+         */
+        @Override
+        public String toString() {
+            return "[" + type + " " + port.toBriefString() + "]";
+        }
+    }
+
+    /**
+     * the type of change that happened to an open flow port
+     */
+    public enum PortChangeType {
+        ADD, OTHER_UPDATE, DELETE, UP, DOWN,
+    }
+
+    /**
+     * Set IFloodlightProviderService for this switch instance
+     * Called immediately after instantiation
+     *
+     * @param controller
+     */
+    public void setFloodlightProvider(Controller controller);
+
+    /**
+     * Set IThreadPoolService for this switch instance
+     * Called immediately after instantiation
+     *
+     * @param threadPool
+     */
+    public void setThreadPoolService(IThreadPoolService threadPool);
+
+    /**
+     * Set debug counter service for per-switch counters
+     * Called immediately after instantiation
+     * @param debugCounters
+     * @throws CounterException
+     */
+    public void setDebugCounterService(IDebugCounterService debugCounters)
+            throws CounterException;
+
+    /**
+     * Set the netty Channel this switch instance is associated with
+     * Called immediately after instantiation
+     *
+     * @param channel
+     */
+    public void setChannel(Channel channel);
+
+    /**
+     * Called when OFMessage enters pipeline. Returning true cause the message
+     * to be dropped.
+     * @param ofm
+     * @return
+     */
+    public boolean inputThrottled(OFMessage ofm);
+
+    /**
+     * Return if the switch is currently overloaded. The definition of
+     * overload refers to excessive traffic in the control path, namely
+     * a high packet in rate.
+     * @return
+     */
+    boolean isOverloaded();
+
+    /**
+     * Write OFMessage to the output stream, subject to switch rate limiting.
+     * The message will be handed to the floodlightProvider for possible filtering
+     * and processing by message listeners
+     * @param msg
+     * @param cntx
+     * @throws IOException
+     */
+    public void writeThrottled(OFMessage msg, FloodlightContext cntx) throws IOException;
+
+    /**
+     * Writes the list of messages to the output stream, subject to rate limiting.
+     * The message will be handed to the floodlightProvider for possible filtering
+     * and processing by message listeners.
+     * @param msglist
+     * @param bc
+     * @throws IOException
+     */
+    void writeThrottled(List<OFMessage> msglist, FloodlightContext bc)
+            throws IOException;
+
+    /**
+     * Writes to the OFMessage to the output stream, bypassing rate limiting.
+     * The message will be handed to the floodlightProvider for possible filtering
+     * and processing by message listeners
+     * @param m
+     * @param bc
+     * @throws IOException
+     */
+    public void write(OFMessage m, FloodlightContext bc) throws IOException;
+
+    /**
+     * Writes the list of messages to the output stream, bypassing rate limiting.
+     * The message will be handed to the floodlightProvider for possible filtering
+     * and processing by message listeners.
+     * @param msglist
+     * @param bc
+     * @throws IOException
+     */
+    public void write(List<OFMessage> msglist, FloodlightContext bc) throws IOException;
+
+    /**
+     *
+     * @throws IOException
+     */
+    public void disconnectOutputStream();
+
+    /**
+     * Returns switch features from features Reply
+     * @return
+     */
+    public int getBuffers();
+
+    public int getActions();
+
+    public int getCapabilities();
+
+    public byte getTables();
+
+    /**
+     * @return a copy of the description statistics for this switch
+     */
+    public OFDescriptionStatistics getDescriptionStatistics();
+
+    /**
+     * Set the OFFeaturesReply message returned by the switch during initial
+     * handshake.
+     * @param featuresReply
+     */
+    public void setFeaturesReply(OFFeaturesReply featuresReply);
+
+    /**
+     * Get list of all enabled ports. This will typically be different from
+     * the list of ports in the OFFeaturesReply, since that one is a static
+     * snapshot of the ports at the time the switch connected to the controller
+     * whereas this port list also reflects the port status messages that have
+     * been received.
+     * @return Unmodifiable list of ports not backed by the underlying collection
+     */
+    public Collection<ImmutablePort> getEnabledPorts();
+
+    /**
+     * Get list of the port numbers of all enabled ports. This will typically
+     * be different from the list of ports in the OFFeaturesReply, since that
+     * one is a static snapshot of the ports at the time the switch connected
+     * to the controller whereas this port list also reflects the port status
+     * messages that have been received.
+     * @return Unmodifiable list of ports not backed by the underlying collection
+     */
+    public Collection<Short> getEnabledPortNumbers();
+
+    /**
+     * Retrieve the port object by the port number. The port object
+     * is the one that reflects the port status updates that have been
+     * received, not the one from the features reply.
+     * @param portNumber
+     * @return port object
+     */
+    public ImmutablePort getPort(short portNumber);
+
+    /**
+     * Retrieve the port object by the port name. The port object
+     * is the one that reflects the port status updates that have been
+     * received, not the one from the features reply.
+     * Port names are case insentive
+     * @param portName
+     * @return port object
+     */
+    public ImmutablePort getPort(String portName);
+
+    /**
+     * Add or modify a switch port.
+     * This is called by the core controller
+     * code in response to a OFPortStatus message. It should not typically be
+     * called by other floodlight applications.
+     *
+     * OFPPR_MODIFY and OFPPR_ADD will be treated as equivalent. The OpenFlow
+     * spec is not clear on whether portNames are portNumbers are considered
+     * authoritative identifiers. We treat portNames <-> portNumber mappings
+     * as fixed. If they change, we delete all previous conflicting ports and
+     * add all new ports.
+     *
+     * @param ps the port status message
+     * @return the ordered Collection of changes "applied" to the old ports
+     * of the switch according to the PortStatus message. A single PortStatus
+     * message can result in multiple changes.
+     * If portName <-> portNumber mappings have
+     * changed, the iteration order ensures that delete events for old
+     * conflicting appear before before events adding new ports
+     */
+    public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps);
+
+    /**
+     * Get list of all ports. This will typically be different from
+     * the list of ports in the OFFeaturesReply, since that one is a static
+     * snapshot of the ports at the time the switch connected to the controller
+     * whereas this port list also reflects the port status messages that have
+     * been received.
+     * @return Unmodifiable list of ports
+     */
+    public Collection<ImmutablePort> getPorts();
+
+    /**
+     * @param portNumber
+     * @return Whether a port is enabled per latest port status message
+     * (not configured down nor link down nor in spanning tree blocking state)
+     */
+    public boolean portEnabled(short portNumber);
+
+    /**
+     * @param portNumber
+     * @return Whether a port is enabled per latest port status message
+     * (not configured down nor link down nor in spanning tree blocking state)
+     */
+    public boolean portEnabled(String portName);
+
+    /**
+     * Compute the changes that would be required to replace the old ports
+     * of this switch with the new ports
+     * @param ports new ports to set
+     * @return the ordered collection of changes "applied" to the old ports
+     * of the switch in order to set them to the new set.
+     * If portName <-> portNumber mappings have
+     * changed, the iteration order ensures that delete events for old
+     * conflicting appear before before events adding new ports
+     */
+    public OrderedCollection<PortChangeEvent>
+            comparePorts(Collection<ImmutablePort> ports);
+
+    /**
+     * Replace the ports of this switch with the given ports.
+     * @param ports new ports to set
+     * @return the ordered collection of changes "applied" to the old ports
+     * of the switch in order to set them to the new set.
+     * If portName <-> portNumber mappings have
+     * changed, the iteration order ensures that delete events for old
+     * conflicting appear before before events adding new ports
+     */
+    public OrderedCollection<PortChangeEvent>
+            setPorts(Collection<ImmutablePort> ports);
+
+
+    /**
+     * Get the datapathId of the switch
+     * @return
+     */
+    public long getId();
+
+    /**
+     * Get a string version of the ID for this switch
+     * @return
+     */
+    public String getStringId();
+
+    /**
+     * Get the IP Address for the switch
+     * @return the inet address
+     */
+    public SocketAddress getInetAddress();
+
+    /**
+     * Retrieves attributes of this switch
+     * @return
+     */
+    public Map<Object, Object> getAttributes();
+
+    /**
+     * Retrieves the date the switch connected to this controller
+     * @return the date
+     */
+    public Date getConnectedSince();
+
+    /**
+     * Returns the next available transaction id
+     * @return
+     */
+    public int getNextTransactionId();
+
+    /**
+     * Returns a Future object that can be used to retrieve the asynchronous
+     * OFStatisticsReply when it is available.
+     *
+     * @param request statistics request
+     * @return Future object wrapping OFStatisticsReply
+     * @throws IOException
+     */
+    public Future<List<OFStatistics>> queryStatistics(OFStatisticsRequest request)
+
+            throws IOException;
+
+    /**
+     * Returns a Future object that can be used to retrieve the asynchronous
+     * OFStatisticsReply when it is available.
+     *
+     * @param request statistics request
+     * @return Future object wrapping OFStatisticsReply
+     * @throws IOException
+     */
+    public Future<OFFeaturesReply> querySwitchFeaturesReply()
+            throws IOException;
+
+    /**
+     * Deliver the featuresReply future reply
+     * @param reply the reply to deliver
+     */
+    void deliverOFFeaturesReply(OFMessage reply);
+
+    /*
+     * Cancel features reply with a specific transction ID
+     * @param transactionId the transaction ID
+     */
+    public void cancelFeaturesReply(int transactionId);
+
+    /**
+     * Check if the switch is connected to this controller. Whether a switch
+     * is connected is independent of whether the switch is active
+     * @return whether the switch is still disconnected
+     */
+    public boolean isConnected();
+
+    /**
+     * Check if the switch is active. I.e., the switch is connected to this
+     * controller and is in master role
+     * @return
+     */
+    public boolean isActive();
+
+    /**
+     * Set whether the switch is connected
+     * @param connected whether the switch is connected
+     */
+    public void setConnected(boolean connected);
+
+    /**
+     * Get the current role of the controller for the switch
+     * @return the role of the controller
+     */
+    public Role getHARole();
+
+    /**
+     * Set switch's HA role to role. The haRoleReplyReceived indicates
+     * if a reply was received from the switch (error replies excluded).
+     *
+     * If role is null, the switch should close the channel connection.
+     *
+     * @param role
+     * @param haRoleReplyReceived
+     */
+    public void setHARole(Role role);
+
+    /**
+     * Deliver the statistics future reply
+     * @param reply the reply to deliver
+     */
+    public void deliverStatisticsReply(OFStatisticsReply reply);
+
+    /**
+     * Cancel the statistics reply with the given transaction ID
+     * @param transactionId the transaction ID
+     */
+    public void cancelStatisticsReply(int transactionId);
+
+    /**
+     * Cancel all statistics replies
+     */
+    public void cancelAllStatisticsReplies();
+
+    /**
+     * Checks if a specific switch property exists for this switch
+     * @param name name of property
+     * @return value for name
+     */
+    boolean hasAttribute(String name);
+
+    /**
+     * Set properties for switch specific behavior
+     * @param name name of property
+     * @return value for name
+     */
+    Object getAttribute(String name);
+
+    /**
+     * Check if the given attribute is present and if so whether it is equal
+     * to "other"
+     * @param name the name of the attribute to check
+     * @param other the object to compare the attribute against.
+     * @return true iff the specified attribute is set and equals() the given
+     * other object.
+     */
+    boolean attributeEquals(String name, Object other);
+
+    /**
+     * Set properties for switch specific behavior
+     * @param name name of property
+     * @param value value for name
+     */
+    void setAttribute(String name, Object value);
+
+    /**
+     * Set properties for switch specific behavior
+     * @param name name of property
+     * @return current value for name or null (if not present)
+     */
+    Object removeAttribute(String name);
+
+    /**
+     * Clear all flowmods on this switch
+     */
+    public void clearAllFlowMods();
+
+    /**
+     * Update broadcast cache
+     * @param data
+     * @return true if there is a cache hit
+     *         false if there is no cache hit.
+     */
+    public boolean updateBroadcastCache(Long entry, Short port);
+
+    /**
+     * Get the portBroadcastCacheHits
+     * @return
+     */
+    public Map<Short, Long> getPortBroadcastHits();
+
+    /**
+     * Send a flow statistics request to the switch. This call returns after
+     * sending the stats. request to the switch.
+     * @param request flow statistics request message
+     * @param xid transaction id, must be obtained by using the getXid() API.
+     * @param caller the caller of the API. receive() callback of this
+     * caller would be called when the reply from the switch is received.
+     * @return the transaction id for the message sent to the switch. The
+     * transaction id can be used to match the response with the request. Note
+     * that the transaction id is unique only within the scope of this switch.
+     * @throws IOException
+     */
+    public void sendStatsQuery(OFStatisticsRequest request, int xid,
+                            IOFMessageListener caller) throws IOException;
+
+    /**
+     * Flush all flows queued for this switch in the current thread.
+     * NOTE: The contract is limited to the current thread
+     */
+    public void flush();
+
+    /***********************************************
+     * The following method can be overridden by
+     * specific types of switches
+     ***********************************************
+     */
+
+    /**
+     * Set the SwitchProperties based on it's description
+     * @param description
+     */
+    public void setSwitchProperties(OFDescriptionStatistics description);
+
+    /**
+     * Return the type of OFPort
+     * @param port_num
+     * @return
+     */
+    public OFPortType getPortType(short port_num);
+
+    /**
+     * Can the port be turned on without forming a new loop?
+     * @param port_num
+     * @return
+     */
+    public boolean isFastPort(short port_num);
+
+    /**
+     * Return whether write throttling is enabled on the switch
+     */
+    public boolean isWriteThrottleEnabled();
+
+    /**
+     * Set the flow table full flag in the switch
+     */
+    public void setTableFull(boolean isFull);
+
+    /**
+     * Set the suggested priority to use when installing access flows in
+     * this switch.
+     */
+    public void setAccessFlowPriority(short prio);
+
+    /**
+     * Set the suggested priority to use when installing core flows in
+     * this switch.
+     */
+    public void setCoreFlowPriority(short prio);
+
+    /**
+     * Get the suggested priority to use when installing access flows in
+     * this switch.
+     */
+    public short getAccessFlowPriority();
+
+    /**
+     * Get the suggested priority to use when installing core flows in
+     * this switch.
+     */
+    public short getCoreFlowPriority();
+
+    /**
+     * Start this switch driver's sub handshake. This might be a no-op but
+     * this method must be called at least once for the switch to be become
+     * ready.
+     * This method must only be called from the I/O thread
+     * @throws SwitchDriverSubHandshakeAlreadyStarted if the sub-handshake has
+     * already been started
+     */
+    public void startDriverHandshake();
+
+    /**
+     * Check if the sub-handshake for this switch driver has been completed.
+     * This method can only be called after startDriverHandshake()
+     *
+     * This methods must only be called from the I/O thread
+     * @return true if the sub-handshake has been completed. False otherwise
+     * @throws SwitchDriverSubHandshakeNotStarted if startDriverHandshake() has
+     * not been called yet.
+     */
+    public boolean isDriverHandshakeComplete();
+
+    /**
+     * Pass the given OFMessage to the driver as part of this driver's
+     * sub-handshake. Must not be called after the handshake has been completed
+     * This methods must only be called from the I/O thread
+     * @param m The message that the driver should process
+     * @throws SwitchDriverSubHandshakeCompleted if isDriverHandshake() returns
+     * false before this method call
+     * @throws SwitchDriverSubHandshakeNotStarted if startDriverHandshake() has
+     * not been called yet.
+     */
+    public void processDriverHandshakeMessage(OFMessage m);
+}
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java
deleted file mode 100644
index 58cc627860d679bb80975637604ca59314ec1daa..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/**
-*    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.core;
-
-import java.util.Collection;
-
-import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionsReply;
-import org.projectfloodlight.openflow.protocol.OFControllerRole;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFPortStatus;
-
-import net.floodlightcontroller.util.OrderedCollection;
-
-/**
- * An openflow switch connecting to the controller.  This interface offers
- * methods for interacting with switches using OpenFlow, and retrieving
- * information about the switches.
- */
-public interface IOFSwitchBackend extends IOFSwitch {
-    /**
-     * Set the netty Channel this switch instance is associated with
-     * Called immediately after instantiation
-     * @param channel
-     */
-    void registerConnection(IOFConnectionBackend connection);
-
-    /**
-     * Remove the netty Channels associated with this switch
-     * @param channel
-     */
-    void removeConnections();
-
-    /**
-     * Remove the netty Channel belonging to the specified connection
-     * @param connection
-     */
-    void removeConnection(IOFConnectionBackend connection);
-
-    /**
-     * Set the OFFeaturesReply message returned by the switch during initial
-     * handshake.
-     * @param featuresReply
-     */
-    void setFeaturesReply(OFFeaturesReply featuresReply);
-
-    /** set the gentable mapping for this switch */
-    void setGenTableMap(GenTableMap map);
-
-    /**
-     * Add or modify a switch port.
-     * This is called by the core controller
-     * code in response to a OFPortStatus message. It should not typically be
-     * called by other floodlight applications.
-     *
-     * OFPPR_MODIFY and OFPPR_ADD will be treated as equivalent. The OpenFlow
-     * spec is not clear on whether portNames are portNumbers are considered
-     * authoritative identifiers. We treat portNames <-> portNumber mappings
-     * as fixed. If they change, we delete all previous conflicting ports and
-     * add all new ports.
-     *
-     * @param ps the port status message
-     * @return the ordered Collection of changes "applied" to the old ports
-     * of the switch according to the PortStatus message. A single PortStatus
-     * message can result in multiple changes.
-     * If portName <-> portNumber mappings have
-     * changed, the iteration order ensures that delete events for old
-     * conflicting appear before before events adding new ports
-     */
-    OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps);
-
-    /**
-     * Compute the changes that would be required to replace the old ports
-     * of this switch with the new ports
-     * @param ports new ports to set
-     * @return the ordered collection of changes "applied" to the old ports
-     * of the switch in order to set them to the new set.
-     * If portName <-> portNumber mappings have
-     * changed, the iteration order ensures that delete events for old
-     * conflicting appear before before events adding new ports
-     */
-    OrderedCollection<PortChangeEvent>
-            comparePorts(Collection<OFPortDesc> ports);
-
-    /**
-     * Replace the ports of this switch with the given ports.
-     * @param ports new ports to set
-     * @return the ordered collection of changes "applied" to the old ports
-     * of the switch in order to set them to the new set.
-     * If portName <-> portNumber mappings have
-     * changed, the iteration order ensures that delete events for old
-     * conflicting appear before before events adding new ports
-     */
-    OrderedCollection<PortChangeEvent>
-            setPorts(Collection<OFPortDesc> ports);
-
-    /***********************************************
-     * The following method can be overridden by
-     * specific types of switches
-     ***********************************************
-     */
-
-    /**
-     * Set the SwitchProperties based on it's description
-     * @param description
-     */
-    void setSwitchProperties(SwitchDescription description);
-
-    /**
-     * Set the flow table full flag in the switch
-     */
-    void setTableFull(boolean isFull);
-
-    /**
-     * Start this switch driver's sub handshake. This might be a no-op but
-     * this method must be called at least once for the switch to be become
-     * ready.
-     * This method must only be called from the I/O thread
-     * @throws SwitchDriverSubHandshakeAlreadyStarted if the sub-handshake has
-     * already been started
-     */
-    void startDriverHandshake();
-
-    /**
-     * Check if the sub-handshake for this switch driver has been completed.
-     * This method can only be called after startDriverHandshake()
-     *
-     * This methods must only be called from the I/O thread
-     * @return true if the sub-handshake has been completed. False otherwise
-     * @throws SwitchDriverSubHandshakeNotStarted if startDriverHandshake() has
-     * not been called yet.
-     */
-    boolean isDriverHandshakeComplete();
-
-    /**
-     * Pass the given OFMessage to the driver as part of this driver's
-     * sub-handshake. Must not be called after the handshake has been completed
-     * This methods must only be called from the I/O thread
-     * @param m The message that the driver should process
-     * @throws SwitchDriverSubHandshakeCompleted if isDriverHandshake() returns
-     * false before this method call
-     * @throws SwitchDriverSubHandshakeNotStarted if startDriverHandshake() has
-     * not been called yet.
-     */
-    void processDriverHandshakeMessage(OFMessage m);
-
-    void setPortDescStats(OFPortDescStatsReply portDescStats);
-
-    /**
-     * Cancel all pending request
-     */
-    void cancelAllPendingRequests();
-
-    /** the the current HA role of this switch */
-    void setControllerRole(OFControllerRole role);
-
-    void setStatus(SwitchStatus switchStatus);
-
-    /**
-     * Updates the switch's mapping of controller connections
-     * @param controllerCxnsReply the controller connections message sent from the switch
-     */
-    void updateControllerConnections(OFBsnControllerConnectionsReply controllerCxnsReply);
-
-    /**
-     * Determines whether there is another master controller that the switches are
-     * connected to by looking at the controller connections.
-     * @return true if another viable master exists
-     */
-    boolean hasAnotherMaster();
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
index b56655535373e57b59e017791dce25834abe5649..f7f720f914d34f6e812dc9032ccb135a8a3f100a 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
@@ -16,10 +16,7 @@
 
 package net.floodlightcontroller.core;
 
-import net.floodlightcontroller.core.IOFSwitchBackend;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-
-import net.floodlightcontroller.core.SwitchDescription;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
 
 public interface IOFSwitchDriver {
     /**
@@ -29,5 +26,5 @@ public interface IOFSwitchDriver {
      * @return A IOFSwitch instance if the driver found an implementation
      * for the given description. Null otherwise
      */
-    public IOFSwitchBackend getOFSwitchImpl(SwitchDescription description, OFFactory factory);
-}
\ No newline at end of file
+    public IOFSwitch getOFSwitchImpl(OFDescriptionStatistics description);
+}
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
index 57eb4d179d27ad38d7202991ac26799bd822e6e7..e0c7b53f8b29eb8349f28d9f42cc97b43b309c8f 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
@@ -17,9 +17,6 @@
 
 package net.floodlightcontroller.core;
 
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.types.DatapathId;
-
 /**
  * Switch lifecycle notifications.
  *
@@ -48,20 +45,20 @@ public interface IOFSwitchListener {
      * the switch is connected at some controller in the cluster
      * @param switchId the datapath Id of the new switch
      */
-    public void switchAdded(DatapathId switchId);
+    public void switchAdded(long switchId);
 
     /**
      * Fired when a switch disconnects from the cluster ,
      * @param switchId the datapath Id of the switch
      */
-    public void switchRemoved(DatapathId switchId);
+    public void switchRemoved(long switchId);
 
     /**
      * Fired when a switch becomes active *on the local controller*, I.e.,
      * the switch is connected to the local controller and is in MASTER mode
      * @param switchId the datapath Id of the switch
      */
-    public void switchActivated(DatapathId switchId);
+    public void switchActivated(long switchId);
 
     /**
      * Fired when a port on a known switch changes.
@@ -77,9 +74,9 @@ public interface IOFSwitchListener {
      * @param port
      * @param type
      */
-    public void switchPortChanged(DatapathId switchId,
-                                  OFPortDesc port,
-                                  PortChangeType type);
+    public void switchPortChanged(long switchId,
+                                  ImmutablePort port,
+                                  IOFSwitch.PortChangeType type);
 
     /**
      * Fired when any non-port related information (e.g., attributes,
@@ -87,5 +84,5 @@ public interface IOFSwitchListener {
      * TODO: currently unused
      * @param switchId
      */
-    public void switchChanged(DatapathId switchId);
+    public void switchChanged(long switchId);
 }
diff --git a/src/main/java/net/floodlightcontroller/core/ImmutablePort.java b/src/main/java/net/floodlightcontroller/core/ImmutablePort.java
new file mode 100644
index 0000000000000000000000000000000000000000..c015454cad15d3d24d85a0d0ddc89531062237d4
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/ImmutablePort.java
@@ -0,0 +1,561 @@
+package net.floodlightcontroller.core;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import net.floodlightcontroller.util.EnumBitmaps;
+import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
+import org.openflow.protocol.OFPhysicalPort.OFPortFeatures;
+import org.openflow.protocol.OFPhysicalPort.OFPortState;
+import org.openflow.protocol.OFPhysicalPort.PortSpeed;
+import org.openflow.util.HexString;
+
+
+/**
+ * An immutable version of an OFPhysical port. In addition, it uses EnumSets
+ * instead of integer bitmaps to represent
+ * OFPortConfig, OFPortState, and OFPortFeature bitmaps.
+ *
+ * Port names are stored with the original case but equals() and XXXX use
+ * case-insentivie comparisions for port names!!
+ *
+ * TODO: create a Builder so we can easily construct OFPhysicalPorts
+ * TODO: should we verify / ensure that the features make sense, i.e., that
+ *     currentFeatures IsSubsetOf advertisedFeatures IsSubsetOf
+ *     supportedFeatures
+ *
+ * @author gregor
+ *
+ */
+public class ImmutablePort {
+    private final short portNumber;
+    private final byte[] hardwareAddress;
+    private final String name;
+    private final EnumSet<OFPortConfig> config;
+    private final boolean portStateLinkDown;
+    private final OFPortState stpState;
+    private final EnumSet<OFPortFeatures> currentFeatures;
+    private final EnumSet<OFPortFeatures> advertisedFeatures;
+    private final EnumSet<OFPortFeatures> supportedFeatures;
+    private final EnumSet<OFPortFeatures> peerFeatures;
+
+    /**
+     * A builder class to create ImmutablePort instances
+     *
+     * TODO: add methods to remove elements from the EnumSets
+     */
+    public static class Builder {
+        private short portNumber;
+        private byte[] hardwareAddress;
+        private String name;
+        private EnumSet<OFPortConfig> config;
+        private boolean portStateLinkDown;
+        private OFPortState stpState;
+        private EnumSet<OFPortFeatures> currentFeatures;
+        private EnumSet<OFPortFeatures> advertisedFeatures;
+        private EnumSet<OFPortFeatures> supportedFeatures;
+        private EnumSet<OFPortFeatures> peerFeatures;
+
+        public Builder() {
+            this.portNumber = (short)1;
+            this.hardwareAddress = new byte[] { 0, 0, 0, 0, 0, 0 };
+            this.name = "";
+            this.config = EnumSet.noneOf(OFPortConfig.class);
+            this.portStateLinkDown = false;
+            this.stpState = OFPortState.OFPPS_STP_LISTEN;
+            this.currentFeatures = EnumSet.noneOf(OFPortFeatures.class);
+            this.advertisedFeatures = EnumSet.noneOf(OFPortFeatures.class);
+            this.supportedFeatures = EnumSet.noneOf(OFPortFeatures.class);
+            this.peerFeatures = EnumSet.noneOf(OFPortFeatures.class);
+        }
+
+        public Builder(ImmutablePort p) {
+            this.portNumber = p.getPortNumber();
+            this.hardwareAddress = p.getHardwareAddress();
+            this.name = p.getName();
+            this.config = EnumSet.copyOf(p.getConfig());
+            this.portStateLinkDown = p.isLinkDown();
+            this.stpState = p.getStpState();
+            this.currentFeatures = EnumSet.copyOf(p.getCurrentFeatures());
+            this.advertisedFeatures = EnumSet.copyOf(p.getAdvertisedFeatures());
+            this.supportedFeatures = EnumSet.copyOf(p.getSupportedFeatures());
+            this.peerFeatures = EnumSet.copyOf(p.getPeerFeatures());
+        }
+
+        /**
+         * @param portNumber the portNumber to set
+         */
+        public Builder setPortNumber(short portNumber) {
+            this.portNumber = portNumber;
+            return this;
+        }
+        /**
+         * @param hardwareAddress the hardwareAddress to set
+         */
+        public Builder setHardwareAddress(byte[] hardwareAddress) {
+            if (hardwareAddress== null)  {
+                throw new NullPointerException("Hardware address must not be null");
+            }
+            if (hardwareAddress.length != 6) {
+                throw new IllegalArgumentException("Harware address must be 6 " +
+                        "bytes long but hardware address is " +
+                        Arrays.toString(hardwareAddress));
+            }
+            this.hardwareAddress = Arrays.copyOf(hardwareAddress, 6);
+            return this;
+        }
+        /**
+         * @param name the name to set
+         */
+        public Builder setName(String name) {
+            if (name == null)
+                throw new NullPointerException("Port name must not be null");
+            this.name = name;
+            return this;
+        }
+        /**
+         * @param config the config to set
+         */
+        public Builder addConfig(OFPortConfig config) {
+            if (config == null)
+                throw new NullPointerException("PortConfig must not be null");
+            this.config.add(config);
+            return this;
+        }
+        /**
+         * @param portStateLinkDown the portStateLinkDown to set
+         */
+        public Builder setPortStateLinkDown(boolean portStateLinkDown) {
+            this.portStateLinkDown = portStateLinkDown;
+            return this;
+        }
+        /**
+         * @param stpState the stpState to set
+         */
+        public Builder setStpState(OFPortState stpState) {
+            if (stpState == null)
+                throw new NullPointerException("stpState must not be null");
+            if (!stpState.isStpState()) {
+                String msg = String.format("OFPortState enum constant %s " +
+                        "is not an STP state", stpState);
+                throw new IllegalArgumentException(msg);
+            }
+            this.stpState = stpState;
+            return this;
+        }
+        /**
+         * @param currentFeatures the currentFeatures to set
+         */
+        public Builder addCurrentFeature(OFPortFeatures currentFeature) {
+            if (currentFeature == null)
+                throw new NullPointerException("CurrentFeature must not be null");
+            this.currentFeatures.add(currentFeature);
+            return this;
+        }
+        /**
+         * @param advertisedFeatures the advertisedFeatures to set
+         */
+        public Builder
+                addAdvertisedFeature(OFPortFeatures advertisedFeature) {
+            if (advertisedFeature == null) {
+                throw new
+                    NullPointerException("AdvertisedFeature must not be null");
+            }
+            this.advertisedFeatures.add(advertisedFeature);
+            return this;
+        }
+        /**
+         * @param supportedFeatures the supportedFeatures to set
+         */
+        public Builder addSupportedFeature(OFPortFeatures supportedFeature) {
+            if (supportedFeature == null) {
+                throw new NullPointerException("SupportedFeature must not be null");
+            }
+            this.supportedFeatures.add(supportedFeature);
+            return this;
+        }
+        /**
+         * @param peerFeatures the peerFeatures to set
+         */
+        public Builder addPeerFeature(OFPortFeatures peerFeature) {
+            if (peerFeature == null)
+                throw new NullPointerException("PortFeature must not be null");
+            this.peerFeatures.add(peerFeature);
+            return this;
+        }
+
+        /**
+         * @return
+         */
+        public ImmutablePort build() {
+            return new ImmutablePort(portNumber,
+                                     hardwareAddress,
+                                     name,
+                                     EnumSet.copyOf(config),
+                                     portStateLinkDown,
+                                     stpState,
+                                     EnumSet.copyOf(currentFeatures),
+                                     EnumSet.copyOf(advertisedFeatures),
+                                     EnumSet.copyOf(supportedFeatures),
+                                     EnumSet.copyOf(peerFeatures));
+        }
+    }
+
+
+    public static ImmutablePort fromOFPhysicalPort(OFPhysicalPort p) {
+        if (p == null) {
+            throw new NullPointerException("OFPhysicalPort must not be null");
+        }
+        if (p.getHardwareAddress() == null)  {
+            throw new NullPointerException("Hardware address must not be null");
+        }
+        if (p.getName() == null) {
+            throw new NullPointerException("Port name must not be null");
+        }
+
+        return new ImmutablePort(
+
+                p.getPortNumber(),
+                Arrays.copyOf(p.getHardwareAddress(), 6),
+                p.getName(),
+                EnumBitmaps.toEnumSet(OFPortConfig.class, p.getConfig()),
+                OFPortState.isPortDown(p.getState()),
+                OFPortState.getStpState(p.getState()),
+                EnumBitmaps.toEnumSet(OFPortFeatures.class,
+                                      p.getCurrentFeatures()),
+                EnumBitmaps.toEnumSet(OFPortFeatures.class,
+                                      p.getAdvertisedFeatures()),
+                EnumBitmaps.toEnumSet(OFPortFeatures.class,
+                                      p.getSupportedFeatures()),
+                EnumBitmaps.toEnumSet(OFPortFeatures.class,
+                                      p.getPeerFeatures())
+                                      );
+    }
+
+    public static ImmutablePort create(String name, Short portNumber) {
+        return new ImmutablePort(portNumber,
+                                         new byte[] { 0, 0, 0, 0, 0, 0 },
+                                         name,
+                                         EnumSet.noneOf(OFPortConfig.class),
+                                         false,
+                                         OFPortState.OFPPS_STP_LISTEN,
+                                         EnumSet.noneOf(OFPortFeatures.class),
+                                         EnumSet.noneOf(OFPortFeatures.class),
+                                         EnumSet.noneOf(OFPortFeatures.class),
+                                         EnumSet.noneOf(OFPortFeatures.class));
+    }
+
+    /**
+     * Private constructor. Use factory methods.
+     *
+     * Verifies pre-conditions of arguments
+     * Does NOT make defensive copies. Calling factory methods are required
+     * to copy defensively if required.
+     *
+     * @param portNumber
+     * @param hardwareAddress
+     * @param name
+     * @param config
+     * @param portStateLinkDown
+     * @param portStateStp
+     * @param currentFeatures
+     * @param advertisedFeatures
+     * @param supportedFeatures
+     * @param peerFeatures
+     */
+    private ImmutablePort(short portNumber, byte[] hardwareAddress,
+                                 String name, EnumSet<OFPortConfig> config,
+                                 boolean portStateLinkDown,
+                                 OFPortState portStateStp,
+                                 EnumSet<OFPortFeatures> currentFeatures,
+                                 EnumSet<OFPortFeatures> advertisedFeatures,
+                                 EnumSet<OFPortFeatures> supportedFeatures,
+                                 EnumSet<OFPortFeatures> peerFeatures) {
+        if (name == null) {
+            throw new NullPointerException("Port name must not be null");
+        }
+        if (hardwareAddress== null)  {
+            throw new NullPointerException("Hardware address must not be null");
+        }
+        if (hardwareAddress.length != 6) {
+            throw new IllegalArgumentException("Harware address must be 6 " +
+                    "bytes long but hardware address is " +
+                    Arrays.toString(hardwareAddress));
+        }
+        if (config == null)
+            throw new NullPointerException("portConfig must not be null");
+        if (portStateStp == null)
+            throw new NullPointerException("portStateStp must not be null");
+        if (currentFeatures == null)
+            throw new NullPointerException("currentFeatures must not be null");
+        if (advertisedFeatures == null)
+            throw new NullPointerException("advertisedFeatures must not be null");
+        if (supportedFeatures == null)
+            throw new NullPointerException("supportedFeatures must not be null");
+        if (peerFeatures == null)
+            throw new NullPointerException("peerFeatures must not be null");
+
+        this.portNumber = portNumber;
+        this.hardwareAddress = hardwareAddress;
+        this.name = name;
+        this.config = config;
+        this.portStateLinkDown = portStateLinkDown;
+        this.stpState = portStateStp;
+        this.currentFeatures = currentFeatures;
+        this.advertisedFeatures = advertisedFeatures;
+        this.supportedFeatures = supportedFeatures;
+        this.peerFeatures = peerFeatures;
+    }
+
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    public byte[] getHardwareAddress() {
+        // FIXME: don't use arrays.
+        return Arrays.copyOf(hardwareAddress, 6);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Set<OFPortConfig> getConfig() {
+        return Collections.unmodifiableSet(config);
+    }
+
+    /**
+     * Returns true if the OFPortState indicates the port is down
+     * @return
+     */
+    public boolean isLinkDown() {
+        return portStateLinkDown;
+    }
+
+    /**
+     * Returns the STP state portion of the OFPortState. The returned
+     * enum constant will be one of the four STP states and will have
+     * isStpState() return true
+     * @return
+     */
+    public OFPortState getStpState() {
+        return this.stpState;
+    }
+
+    public Set<OFPortFeatures> getCurrentFeatures() {
+        return Collections.unmodifiableSet(currentFeatures);
+    }
+
+    public Set<OFPortFeatures> getAdvertisedFeatures() {
+        return Collections.unmodifiableSet(advertisedFeatures);
+    }
+
+    public Set<OFPortFeatures> getSupportedFeatures() {
+        return Collections.unmodifiableSet(supportedFeatures);
+    }
+
+    public Set<OFPortFeatures> getPeerFeatures() {
+        return Collections.unmodifiableSet(peerFeatures);
+    }
+
+
+    /**
+     * Returns true if the port is up, i.e., it's neither administratively
+     * down nor link down. It currently does NOT take STP state into
+     * consideration
+     * @return
+     */
+    public boolean isEnabled() {
+        return (!portStateLinkDown &&
+                !config.contains(OFPortConfig.OFPPC_PORT_DOWN));
+    }
+
+    /**
+     * @return the speed of the port (from currentFeatures) if the port is
+     * enabled, otherwise return SPEED_NONE
+     */
+    public PortSpeed getCurrentPortSpeed() {
+        if (!isEnabled())
+            return PortSpeed.SPEED_NONE;
+        PortSpeed maxSpeed = PortSpeed.SPEED_NONE;
+        for (OFPortFeatures f: currentFeatures)
+            PortSpeed.max(maxSpeed, f.getSpeed());
+        return maxSpeed;
+    }
+
+    public OFPhysicalPort toOFPhysicalPort() {
+        OFPhysicalPort ofpp = new OFPhysicalPort();
+        ofpp.setPortNumber(this.getPortNumber());
+        ofpp.setHardwareAddress(this.getHardwareAddress());
+        ofpp.setName(this.getName());
+        ofpp.setConfig(EnumBitmaps.toBitmap(this.getConfig()));
+        int state = this.getStpState().getValue();
+        if (this.isLinkDown())
+            state |= OFPortState.OFPPS_LINK_DOWN.getValue();
+        ofpp.setState(state);
+        ofpp.setCurrentFeatures(EnumBitmaps.toBitmap(this.getCurrentFeatures()));
+        ofpp.setAdvertisedFeatures(
+                EnumBitmaps.toBitmap(this.getAdvertisedFeatures()));
+        ofpp.setSupportedFeatures(
+                EnumBitmaps.toBitmap(this.getSupportedFeatures()));
+        ofpp.setPeerFeatures(EnumBitmaps.toBitmap(this.getPeerFeatures()));
+        return ofpp;
+    }
+
+    /**
+     * Return a brief String describing this port containing the port number
+     * and port name
+     * @return
+     */
+    public String toBriefString() {
+        return String.format("%s (%d)", name, portNumber);
+    }
+
+
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime
+                 * result
+                 + ((advertisedFeatures == null) ? 0
+                                                : advertisedFeatures.hashCode());
+        result = prime * result + ((config == null) ? 0 : config.hashCode());
+        result = prime
+                 * result
+                 + ((currentFeatures == null) ? 0
+                                             : currentFeatures.hashCode());
+        result = prime * result + Arrays.hashCode(hardwareAddress);
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result
+                 + ((peerFeatures == null) ? 0 : peerFeatures.hashCode());
+        result = prime * result + portNumber;
+        result = prime * result + (portStateLinkDown ? 1231 : 1237);
+        result = prime * result
+                 + ((stpState == null) ? 0 : stpState.hashCode());
+        result = prime
+                 * result
+                 + ((supportedFeatures == null) ? 0
+                                               : supportedFeatures.hashCode());
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        ImmutablePort other = (ImmutablePort) obj;
+        if (portNumber != other.portNumber) return false;
+        if (name == null) {
+            if (other.name != null) return false;
+        } else if (!name.equalsIgnoreCase(other.name)) return false;
+        if (advertisedFeatures == null) {
+            if (other.advertisedFeatures != null) return false;
+        } else if (!advertisedFeatures.equals(other.advertisedFeatures))
+            return false;
+        if (config == null) {
+            if (other.config != null) return false;
+        } else if (!config.equals(other.config)) return false;
+        if (currentFeatures == null) {
+            if (other.currentFeatures != null) return false;
+        } else if (!currentFeatures.equals(other.currentFeatures))
+            return false;
+        if (!Arrays.equals(hardwareAddress, other.hardwareAddress))
+            return false;
+        if (peerFeatures == null) {
+            if (other.peerFeatures != null) return false;
+        } else if (!peerFeatures.equals(other.peerFeatures)) return false;
+        if (portStateLinkDown != other.portStateLinkDown) return false;
+        if (stpState != other.stpState) return false;
+        if (supportedFeatures == null) {
+            if (other.supportedFeatures != null) return false;
+        } else if (!supportedFeatures.equals(other.supportedFeatures))
+            return false;
+        return true;
+    }
+
+    /**
+     * Convert a Collection of OFPhysicalPorts to a list of ImmutablePorts.
+     * All OFPhysicalPorts in the Collection must be non-null and valid.
+     * No other checks (name / number uniqueness) are performed
+     * @param ports
+     * @return a list of {@link ImmutablePort}s. This is list is owned by
+     * the caller. The returned list is not thread-safe
+     * @throws NullPointerException if any OFPhysicalPort or important fields
+     * of any OFPhysicalPort are null
+     * @throws IllegalArgumentException
+     */
+    public static List<ImmutablePort>
+            immutablePortListOf(Collection<OFPhysicalPort> ports) {
+        if (ports == null) {
+            throw new NullPointerException("Port list must not be null");
+        }
+        ArrayList<ImmutablePort> immutablePorts =
+                new ArrayList<ImmutablePort>(ports.size());
+        for (OFPhysicalPort p: ports)
+            immutablePorts.add(fromOFPhysicalPort(p));
+        return immutablePorts;
+    }
+
+    /**
+     * Convert a Collection of ImmutablePort to a list of OFPhyscialPorts.
+     * All ImmutablePorts in the Collection must be non-null.
+     * No other checks (name / number uniqueness) are performed
+     * @param ports
+     * @return a list of {@link OFPhysicalPort}s. This is list is owned by
+     * the caller. The returned list is not thread-safe
+     * @throws NullPointerException if any {@link ImmutablePort} or the port
+     * list is null
+     * @throws IllegalArgumentException
+     */
+    public static List<OFPhysicalPort>
+            ofPhysicalPortListOf(Collection<ImmutablePort> ports) {
+        if (ports == null) {
+            throw new NullPointerException("Port list must not be null");
+        }
+        ArrayList<OFPhysicalPort> ofppList=
+                new ArrayList<OFPhysicalPort>(ports.size());
+        for (ImmutablePort p: ports) {
+            if (p == null)
+                throw new NullPointerException("Port must not be null");
+            ofppList.add(p.toOFPhysicalPort());
+        }
+        return ofppList;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder2 = new StringBuilder();
+        String linkState = (portStateLinkDown) ? "DOWN" : "UP";
+        builder2.append("Port [")
+                .append(name)
+                .append("(").append(portNumber).append(")")
+                .append(", hardwareAddress=")
+                .append(HexString.toHexString(hardwareAddress))
+                .append(", config=").append(config)
+                .append(", link=").append(linkState)
+                .append(", stpState=").append(stpState)
+                .append(", currentFeatures=").append(currentFeatures)
+                .append(", advertisedFeatures=").append(advertisedFeatures)
+                .append(", supportedFeatures=").append(supportedFeatures)
+                .append(", peerFeatures=").append(peerFeatures).append("]");
+        return builder2.toString();
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/LogicalOFMessageCategory.java b/src/main/java/net/floodlightcontroller/core/LogicalOFMessageCategory.java
deleted file mode 100644
index 514d3541cbfc06820205ad40e9f3499bf441ceba..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/LogicalOFMessageCategory.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package net.floodlightcontroller.core;
-
-import javax.annotation.Nonnull;
-
-import org.projectfloodlight.openflow.types.OFAuxId;
-
-/**
- * Immutable class for logical OF message category.
- * Applications should use these to define the OF Aux connections
- * that they desire.
- * @author Jason Parraga <Jason.Parraga@bigswitch.com>
- */
-public class LogicalOFMessageCategory {
-
-    public static final LogicalOFMessageCategory MAIN =  new LogicalOFMessageCategory("MAIN", OFAuxId.MAIN);
-
-    final private String name;
-    final private OFAuxId auxId;
-
-
-    public LogicalOFMessageCategory(@Nonnull String name, int auxId) {
-        this(name, OFAuxId.of(auxId));
-    }
-
-    public LogicalOFMessageCategory(@Nonnull String name, OFAuxId auxId) {
-        if (name == null)
-            throw new NullPointerException("name must not be null");
-        this.name = name;
-        this.auxId = auxId;
-    }
-
-    public OFAuxId getAuxId(){
-        return this.auxId;
-    }
-
-    public String getName(){
-        return this.name;
-    }
-
-    @Override
-    public String toString(){
-        return "LogicalOFMessageCategory [name=" + getName() + " OFAuxId=" + getAuxId() + "]";
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((auxId == null) ? 0 : auxId.hashCode());
-        result = prime * result + ((name == null) ? 0 : name.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (getClass() != obj.getClass()) return false;
-        LogicalOFMessageCategory other = (LogicalOFMessageCategory) obj;
-        if (auxId == null) {
-            if (other.auxId != null) return false;
-        } else if (!auxId.equals(other.auxId)) return false;
-        if (name == null) {
-            if (other.name != null) return false;
-        } else if (!name.equals(other.name)) return false;
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/Main.java b/src/main/java/net/floodlightcontroller/core/Main.java
index f57ed991a385aebd94dcb4a9d2e68f2e95dfa9f7..627a56c1477f2191abc11f2f8dbc5304128c0bd6 100644
--- a/src/main/java/net/floodlightcontroller/core/Main.java
+++ b/src/main/java/net/floodlightcontroller/core/Main.java
@@ -18,68 +18,48 @@ package net.floodlightcontroller.core;
 
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import net.floodlightcontroller.core.internal.CmdLineSettings;
-import net.floodlightcontroller.core.module.FloodlightModuleConfigFileNotFoundException;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.FloodlightModuleLoader;
 import net.floodlightcontroller.core.module.IFloodlightModuleContext;
+import net.floodlightcontroller.restserver.IRestApiService;
 
 /**
  * Host for the Floodlight main method
  * @author alexreimers
  */
 public class Main {
-	private static final Logger logger = LoggerFactory.getLogger(Main.class);
 
-	/**
-	 * Main method to load configuration and modules
-	 * @param args
-	 * @throws FloodlightModuleException 
-	 */
-	public static void main(String[] args) throws FloodlightModuleException {
-		try {
-			// Setup logger
-			System.setProperty("org.restlet.engine.loggerFacadeClass", 
-					"org.restlet.ext.slf4j.Slf4jLoggerFacade");
-
-			CmdLineSettings settings = new CmdLineSettings();
-			CmdLineParser parser = new CmdLineParser(settings);
-			try {
-				parser.parseArgument(args);
-			} catch (CmdLineException e) {
-				parser.printUsage(System.out);
-				System.exit(1);
-			}
-
-			// Load modules
-			FloodlightModuleLoader fml = new FloodlightModuleLoader();
-			try {
-				IFloodlightModuleContext moduleContext = fml.loadModulesFromConfig(settings.getModuleFile());
-				//TODO @Ryan I don't think we need this anymore... Run REST server
-				//IRestApiService restApi = moduleContext.getServiceImpl(IRestApiService.class);
-				//restApi.run();
-				// Run the main floodlight module
-				//IFloodlightProviderService controller =
-				//        moduleContext.getServiceImpl(IFloodlightProviderService.class);
-				// This call blocks, it has to be the last line in the main
-				//controller.run();
-			} catch (FloodlightModuleConfigFileNotFoundException e) {
-				// we really want to log the message, not the stack trace
-				logger.error("Could not read config file: {}", e.getMessage());
-				System.exit(1);
-			}
-			try {
-                fml.runModules(); // this should run the controller module and all modules
-            } catch (FloodlightModuleException e) {
-                logger.error("Failed to run controller modules", e);
-                System.exit(1);
-            }
-		} catch (Exception e) {
-			logger.error("Exception in main", e);
-			System.exit(1);
-		}
-	}
+    /**
+     * Main method to load configuration and modules
+     * @param args
+     * @throws FloodlightModuleException 
+     */
+    public static void main(String[] args) throws FloodlightModuleException {
+        // Setup logger
+        System.setProperty("org.restlet.engine.loggerFacadeClass", 
+                "org.restlet.ext.slf4j.Slf4jLoggerFacade");
+        
+        CmdLineSettings settings = new CmdLineSettings();
+        CmdLineParser parser = new CmdLineParser(settings);
+        try {
+            parser.parseArgument(args);
+        } catch (CmdLineException e) {
+            parser.printUsage(System.out);
+            System.exit(1);
+        }
+        
+        // Load modules
+        FloodlightModuleLoader fml = new FloodlightModuleLoader();
+        IFloodlightModuleContext moduleContext = fml.loadModulesFromConfig(settings.getModuleFile());
+        // Run REST server
+        IRestApiService restApi = moduleContext.getServiceImpl(IRestApiService.class);
+        restApi.run();
+        // Run the main floodlight module
+        IFloodlightProviderService controller =
+                moduleContext.getServiceImpl(IFloodlightProviderService.class);
+        // This call blocks, it has to be the last line in the main
+        controller.run();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/OFConnection.java b/src/main/java/net/floodlightcontroller/core/OFConnection.java
deleted file mode 100644
index ff4f529bf92c0e372967cdc5dd66fd507f34af53..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/OFConnection.java
+++ /dev/null
@@ -1,409 +0,0 @@
-/**
- *    Copyright 2012, 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.core;
-
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import javax.annotation.Nonnull;
-
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.util.Timeout;
-import org.jboss.netty.util.Timer;
-import org.jboss.netty.util.TimerTask;
-
-import java.util.Date;
-
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
-import net.floodlightcontroller.core.internal.Controller;
-import net.floodlightcontroller.core.internal.IOFConnectionListener;
-import net.floodlightcontroller.debugcounter.IDebugCounterService;
-
-import org.projectfloodlight.openflow.protocol.OFErrorMsg;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFRequest;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFAuxId;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Implementation of an openflow connection to switch. Encapsulates a
- * {@link Channel}, and provides message write and request/response handling
- * capabilities.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- */
-public class OFConnection implements IOFConnection, IOFConnectionBackend{
-    private static final Logger logger = LoggerFactory.getLogger(OFConnection.class);
-    private final DatapathId dpid;
-    private final OFFactory factory;
-    private final Channel channel;
-    private final OFAuxId auxId;
-    private final Timer timer;
-
-    private final Date connectedSince;
-
-    private final Map<Long, Deliverable<?>> xidDeliverableMap;
-
-    protected final static ThreadLocal<List<OFMessage>> localMsgBuffer =
-            new ThreadLocal<List<OFMessage>>();
-
-    private static final long DELIVERABLE_TIME_OUT = 60;
-    private static final TimeUnit DELIVERABLE_TIME_OUT_UNIT = TimeUnit.SECONDS;
-
-
-    private final OFConnectionCounters counters;
-    private IOFConnectionListener listener;
-
-    public OFConnection(@Nonnull DatapathId dpid,
-                        @Nonnull OFFactory factory,
-                        @Nonnull Channel channel,
-                        @Nonnull OFAuxId auxId,
-                        @Nonnull IDebugCounterService debugCounters,
-                        @Nonnull Timer timer) {
-        Preconditions.checkNotNull(dpid, "dpid");
-        Preconditions.checkNotNull(factory, "factory");
-        Preconditions.checkNotNull(channel, "channel");
-        Preconditions.checkNotNull(timer, "timer");
-        Preconditions.checkNotNull(debugCounters);
-
-        this.listener = NullConnectionListener.INSTANCE;
-        this.dpid = dpid;
-        this.factory = factory;
-        this.channel = channel;
-        this.auxId = auxId;
-        this.connectedSince = new Date();
-        this.xidDeliverableMap = new ConcurrentHashMap<>();
-        this.counters = new OFConnectionCounters(debugCounters, dpid, this.auxId);
-        this.timer = timer;
-    }
-
-    @Override
-    public void write(OFMessage m) {
-        if (!isConnected()) {
-            if (logger.isDebugEnabled())
-                logger.debug("{}: not connected - dropping message {}", this, m);
-            return;
-        }
-        if (logger.isTraceEnabled())
-            logger.trace("{}: send {}", this, m);
-        List<OFMessage> msgBuffer = localMsgBuffer.get();
-        if (msgBuffer == null) {
-            msgBuffer = new ArrayList<OFMessage>();
-            localMsgBuffer.set(msgBuffer);
-        }
-
-        counters.updateWriteStats(m);
-        msgBuffer.add(m);
-
-        if ((msgBuffer.size() >= Controller.BATCH_MAX_SIZE)
-                || ((m.getType() != OFType.PACKET_OUT) && (m.getType() != OFType.FLOW_MOD))) {
-            this.write(msgBuffer);
-            localMsgBuffer.set(null);
-        }
-    }
-
-    @Override
-    public <R extends OFMessage> ListenableFuture<R> writeRequest(OFRequest<R> request) {
-        if (!isConnected())
-            return Futures.immediateFailedFuture(new SwitchDisconnectedException(getDatapathId()));
-
-        DeliverableListenableFuture<R> future = new DeliverableListenableFuture<R>();
-        xidDeliverableMap.put(request.getXid(), future);
-        write(request);
-        return future;
-    }
-
-    @Override
-    @LogMessageDoc(level = "WARN",
-                   message = "Sending OF message that modifies switch "
-                           + "state while in the slave role: {switch}",
-                   explanation = "An application has sent a message to a switch "
-                           + "that is not valid when the switch is in a slave role",
-                   recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG)
-    public void write(Iterable<OFMessage> msglist) {
-        if (!isConnected()) {
-            if (logger.isDebugEnabled())
-                logger.debug(this.toString() + " : not connected - dropping {} element msglist {} ",
-                        Iterables.size(msglist),
-                        String.valueOf(msglist).substring(0, 80));
-            return;
-        }
-        for (OFMessage m : msglist) {
-            if (logger.isTraceEnabled())
-                logger.trace("{}: send {}", this, m);
-            counters.updateWriteStats(m);
-        }
-        this.channel.write(msglist);
-    }
-
-    // Notifies the connection object that the channel has been disconnected
-    public void disconnected() {
-        SwitchDisconnectedException exception = new SwitchDisconnectedException(getDatapathId());
-        for (Long xid : xidDeliverableMap.keySet()) {
-            // protect against other mechanisms running at the same time
-            // (timeout)
-            Deliverable<?> removed = xidDeliverableMap.remove(xid);
-            if (removed != null) {
-                removed.deliverError(exception);
-            }
-        }
-    }
-
-    @Override
-    public void disconnect() {
-        this.channel.disconnect();
-    }
-
-    @Override
-    public String toString() {
-        String channelString = (channel != null) ? String.valueOf(channel.getRemoteAddress()): "?";
-        return "OFConnection [" + getDatapathId() + "(" + getAuxId() + ")" + "@" + channelString + "]";
-    }
-
-    @Override
-    public Date getConnectedSince() {
-        return connectedSince;
-    }
-
-    @Override
-    public <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> writeStatsRequest(
-            OFStatsRequest<REPLY> request) {
-        if (!isConnected())
-            return Futures.immediateFailedFuture(new SwitchDisconnectedException(getDatapathId()));
-
-        final DeliverableListenableFuture<List<REPLY>> future =
-                new DeliverableListenableFuture<List<REPLY>>();
-
-        Deliverable<REPLY> deliverable = new Deliverable<REPLY>() {
-            private final List<REPLY> results = Collections
-                    .synchronizedList(new ArrayList<REPLY>());
-
-            @Override
-            public void deliver(REPLY reply) {
-                results.add(reply);
-                if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
-                    // done
-                    future.deliver(results);
-                }
-            }
-
-            @Override
-            public void deliverError(Throwable cause) {
-                future.deliverError(cause);
-            }
-
-            @Override
-            public boolean isDone() {
-                return future.isDone();
-            }
-
-            @Override
-            public boolean cancel(boolean mayInterruptIfRunning) {
-                return future.cancel(mayInterruptIfRunning);
-            }
-        };
-
-        registerDeliverable(request.getXid(), deliverable);
-        this.write(request);
-        return future;
-    }
-
-    private void registerDeliverable(long xid, Deliverable<?> deliverable) {
-        this.xidDeliverableMap.put(xid, deliverable);
-        timer.newTimeout(new TimeOutDeliverable(xid), DELIVERABLE_TIME_OUT, DELIVERABLE_TIME_OUT_UNIT);
-    }
-
-    public boolean handleGenericDeliverable(OFMessage reply) {
-        counters.updateReadStats(reply);
-        @SuppressWarnings("unchecked")
-        Deliverable<OFMessage> deliverable =
-                (Deliverable<OFMessage>) this.xidDeliverableMap.get(reply.getXid());
-        if (deliverable != null) {
-            if(reply instanceof OFErrorMsg) {
-                deliverable.deliverError(new OFErrorMsgException((OFErrorMsg) reply));
-            } else {
-                deliverable.deliver(reply);
-            }
-            if (deliverable.isDone())
-                this.xidDeliverableMap.remove(reply.getXid());
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public void cancelAllPendingRequests() {
-        /*
-         * we don't need to be synchronized here. Even if another thread
-         * modifies the map while we're cleaning up the future will eventually
-         * timeout
-         */
-        for (Deliverable<?> d : xidDeliverableMap.values()) {
-            d.cancel(true);
-        }
-        xidDeliverableMap.clear();
-    }
-
-    @Override
-    public boolean isConnected() {
-        return channel.isConnected();
-    }
-
-    @Override
-    public void flush() {
-        List<OFMessage> msglist = localMsgBuffer.get();
-        if ((msglist != null) && (msglist.size() > 0)) {
-            this.write(msglist);
-            localMsgBuffer.set(null);
-        }
-    }
-
-    @Override
-    public SocketAddress getRemoteInetAddress() {
-        return channel.getRemoteAddress();
-    }
-
-    @Override
-    public SocketAddress getLocalInetAddress() {
-        return channel.getLocalAddress();
-    }
-
-    public boolean deliverResponse(OFMessage m) {
-        if (handleGenericDeliverable(m))
-            return true;
-        else
-            return false;
-    }
-
-    @Override
-    public boolean isWritable() {
-        return channel.isWritable();
-    }
-
-    @Override
-    public DatapathId getDatapathId() {
-        return dpid;
-    }
-
-    @Override
-    public OFAuxId getAuxId() {
-        return auxId;
-    }
-
-    Set<Long> getPendingRequestIds() {
-        return ImmutableSet.copyOf(xidDeliverableMap.keySet());
-    }
-
-    @Override
-    public OFFactory getOFFactory() {
-        return this.factory;
-    }
-
-    /**
-     * Timeout class instantiated for deliverables. Will throw a timeout exception
-     * if proper responses are not received in time.
-     *
-     */
-    private class TimeOutDeliverable implements TimerTask {
-        private final long xid;
-
-        public TimeOutDeliverable(long xid) {
-            this.xid = xid;
-        }
-
-        @Override
-        public void run(Timeout timeout) throws Exception {
-            Deliverable<?> removed = xidDeliverableMap.remove(xid);
-            if (removed != null && !removed.isDone()) {
-                removed.deliverError(new TimeoutException(
-                        "timeout - did not receive answer for xid " + xid));
-            }
-
-        }
-    }
-
-    public IOFConnectionListener getListener() {
-        return listener;
-    }
-
-    /** set the connection listener
-     *  <p>
-     *  Note: this is assumed to be called from the Connection's IO Thread.
-     *
-     * @param listener
-     */
-    @Override
-    public void setListener(IOFConnectionListener listener) {
-        this.listener = listener;
-    }
-
-    public void messageReceived(OFMessage m) {
-        // Check if message was a response for a xid waiting at the switch
-        if(!deliverResponse(m)){
-            listener.messageReceived(this, m);
-        }
-    }
-
-    /** A dummy connection listener that just logs warn messages. Saves us a few null checks
-     * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
-     */
-    private static class NullConnectionListener implements IOFConnectionListener {
-        public final static NullConnectionListener INSTANCE = new NullConnectionListener();
-
-        private NullConnectionListener() { }
-
-        @Override
-        public void connectionClosed(IOFConnectionBackend connection) {
-            logger.warn("NullConnectionListener for {} - received connectionClosed", connection);
-        }
-
-        @Override
-        public void messageReceived(IOFConnectionBackend connection, OFMessage m) {
-            logger.warn("NullConnectionListener for {} - received messageReceived: {}", connection, m);
-        }
-
-        @Override
-        public boolean isSwitchHandshakeComplete(IOFConnectionBackend connection) {
-            return false;
-        }
-
-    }
-
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/OFConnectionCounters.java b/src/main/java/net/floodlightcontroller/core/OFConnectionCounters.java
deleted file mode 100644
index 403fb4bbda1c3bd0ec87c8423df624e45b69ab96..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/OFConnectionCounters.java
+++ /dev/null
@@ -1,710 +0,0 @@
-package net.floodlightcontroller.core;
-
-import net.floodlightcontroller.debugcounter.IDebugCounter;
-import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFAuxId;
-import org.python.google.common.base.Preconditions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Implementation of Counters for per-connection statistics for OpenFlow
- * messages.
- * @author Alok Shankar <alok@bigswitch.com>
- */
-public class OFConnectionCounters {
-    public static final String COUNTER_MODULE = OFConnectionCounters.class.getPackage().getName();
-
-    /**
-     * Counters for open flow message types
-     */
-    // Write Counters
-    //
-    private final IDebugCounter ctrWriteHello;
-    private final IDebugCounter ctrWriteError;
-    private final IDebugCounter ctrWriteEchoRequest;
-    private final IDebugCounter ctrWriteEchoReply;
-    private final IDebugCounter ctrWriteExperimenter;
-    private final IDebugCounter ctrWriteFeaturesRequest;
-    private final IDebugCounter ctrWriteFeaturesReply;
-    private final IDebugCounter ctrWriteGetConfigRequest;
-    private final IDebugCounter ctrWriteGetConfigReply;
-    private final IDebugCounter ctrWriteSetConfig;
-    private final IDebugCounter ctrWritePacketIn;
-    private final IDebugCounter ctrWritePacketOut;
-    private final IDebugCounter ctrWriteFlowRemoved;
-    private final IDebugCounter ctrWritePortStatus;
-    private final IDebugCounter ctrWriteFlowMod;
-    private final IDebugCounter ctrWritePortMod;
-    private final IDebugCounter ctrWriteStatsRequest;
-    private final IDebugCounter ctrWriteStatsReply;
-    private final IDebugCounter ctrWriteBarrierRequest;
-    private final IDebugCounter ctrWriteBarrierReply;
-    private final IDebugCounter ctrWriteGetAsyncReply;
-    private final IDebugCounter ctrWriteGetAsyncRequest;
-    private final IDebugCounter ctrWriteGroupMod;
-    private final IDebugCounter ctrWriteMeterMod;
-    private final IDebugCounter ctrWriteQueueGetConfigReply;
-    private final IDebugCounter ctrWriteQueueGetConfigRequest;
-    private final IDebugCounter ctrWriteRoleRequest;
-    private final IDebugCounter ctrWriteRoleReply;
-    private final IDebugCounter ctrWriteSetAsync;
-    private final IDebugCounter ctrWriteTableMod;
-
-    // Read Counters
-    //
-    private final IDebugCounter ctrReadHello;
-    private final IDebugCounter ctrReadError;
-    private final IDebugCounter ctrReadEchoRequest;
-    private final IDebugCounter ctrReadEchoReply;
-    private final IDebugCounter ctrReadExperimenter;
-    private final IDebugCounter ctrReadFeaturesRequest;
-    private final IDebugCounter ctrReadFeaturesReply;
-    private final IDebugCounter ctrReadGetConfigRequest;
-    private final IDebugCounter ctrReadGetConfigReply;
-    private final IDebugCounter ctrReadSetConfig;
-    private final IDebugCounter ctrReadPacketIn;
-    private final IDebugCounter ctrReadPacketOut;
-    private final IDebugCounter ctrReadFlowRemoved;
-    private final IDebugCounter ctrReadPortStatus;
-    private final IDebugCounter ctrReadFlowMod;
-    private final IDebugCounter ctrReadPortMod;
-    private final IDebugCounter ctrReadStatsRequest;
-    private final IDebugCounter ctrReadStatsReply;
-    private final IDebugCounter ctrReadBarrierRequest;
-    private final IDebugCounter ctrReadBarrierReply;
-    private final IDebugCounter ctrReadGetAsyncReply;
-    private final IDebugCounter ctrReadGetAsyncRequest;
-    private final IDebugCounter ctrReadGroupMod;
-    private final IDebugCounter ctrReadMeterMod;
-    private final IDebugCounter ctrReadQueueGetConfigReply;
-    private final IDebugCounter ctrReadQueueGetConfigRequest;
-    private final IDebugCounter ctrReadRoleRequest;
-    private final IDebugCounter ctrReadRoleReply;
-    private final IDebugCounter ctrReadSetAsync;
-    private final IDebugCounter ctrReadTableMod;
-
-    private static final Logger logger =
-            LoggerFactory.getLogger(OFConnectionCounters.class);
-
-    /**
-     * Utility function to create description string and do counter registration
-     * @param countersService
-     * @param stringId The string ID
-     * @param messageType Type of open flow message
-     * @return the registered DebugCounter
-     */
-    IDebugCounter registerCounterLocal(IDebugCounterService countersService,
-                                       String hierarchy,
-                                       String stringId,
-                                       String messageType){
-        String counterHierarchy = stringId + hierarchy + "/" + messageType;
-        String counterDescription = "Number of " + messageType +
-                                        " messages in this connection";
-
-        return countersService.registerCounter(COUNTER_MODULE, counterHierarchy,
-                                               counterDescription);
-    }
-
-    public OFConnectionCounters(IDebugCounterService counters,
-                                DatapathId dpid,
-                                OFAuxId auxId) {
-
-        Preconditions.checkNotNull(counters, "Counters must not be null");
-        Preconditions.checkNotNull(dpid, "dpid must not be null");
-        Preconditions.checkNotNull(auxId, "auxid must not be null");
-
-        String stringId = dpid.toString() +":" + auxId.toString();
-        String hierarchy = "/write";
-
-        // every level of the hierarchical counter has to be registered
-        // even if they are not used
-
-        counters.registerCounter(COUNTER_MODULE, stringId ,
-                                 "Counter for this connection");
-
-        registerCounterLocal(counters,
-                             hierarchy,
-                             stringId,
-                             "");
-
-        ctrWriteHello =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.HELLO.toString());
-        ctrWriteError =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ERROR.toString());
-        ctrWriteEchoRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ECHO_REQUEST.toString());
-        ctrWriteEchoReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ECHO_REPLY.toString());
-        ctrWriteExperimenter =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.EXPERIMENTER.toString());
-        ctrWriteFeaturesRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.FEATURES_REQUEST.toString());
-        ctrWriteFeaturesReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.FEATURES_REPLY.toString());
-        ctrWriteGetConfigRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GET_CONFIG_REQUEST.toString());
-        ctrWriteGetConfigReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GET_CONFIG_REPLY.toString());
-        ctrWriteSetConfig =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.SET_CONFIG.toString());
-        ctrWritePacketIn =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.PACKET_IN.toString());
-        ctrWritePacketOut =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.PACKET_OUT.toString());
-        ctrWriteFlowRemoved =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.FLOW_REMOVED.toString());
-        ctrWritePortStatus =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.PORT_STATUS.toString());
-        ctrWriteFlowMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.FLOW_MOD.toString());
-        ctrWritePortMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.PORT_MOD.toString());
-        ctrWriteStatsRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.STATS_REQUEST.toString());
-        ctrWriteStatsReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.STATS_REPLY.toString());
-        ctrWriteBarrierRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.BARRIER_REQUEST.toString());
-        ctrWriteBarrierReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.BARRIER_REPLY.toString());
-        ctrWriteGetAsyncReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GET_ASYNC_REPLY.toString());
-        ctrWriteGetAsyncRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GET_ASYNC_REQUEST.toString());
-        ctrWriteGroupMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GROUP_MOD.toString());
-        ctrWriteMeterMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.METER_MOD.toString());
-        ctrWriteQueueGetConfigReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.QUEUE_GET_CONFIG_REPLY.toString());
-        ctrWriteQueueGetConfigRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.QUEUE_GET_CONFIG_REQUEST.toString());
-        ctrWriteRoleReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ROLE_REPLY.toString());
-        ctrWriteRoleRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ROLE_REQUEST.toString());
-        ctrWriteSetAsync =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.SET_ASYNC.toString());
-        ctrWriteTableMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.TABLE_MOD.toString());
-
-        // Register Read Counters
-        //
-        hierarchy = "/read";
-
-        registerCounterLocal(counters,
-                             hierarchy,
-                             stringId,
-                             "");
-        ctrReadHello =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.HELLO.toString());
-        ctrReadError =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ERROR.toString());
-        ctrReadEchoRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ECHO_REQUEST.toString());
-        ctrReadEchoReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ECHO_REPLY.toString());
-        ctrReadExperimenter =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.EXPERIMENTER.toString());
-        ctrReadFeaturesRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.FEATURES_REQUEST.toString());
-        ctrReadFeaturesReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.FEATURES_REPLY.toString());
-        ctrReadGetConfigRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GET_CONFIG_REQUEST.toString());
-        ctrReadGetConfigReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GET_CONFIG_REPLY.toString());
-        ctrReadSetConfig =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.SET_CONFIG.toString());
-        ctrReadPacketIn =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.PACKET_IN.toString());
-        ctrReadPacketOut =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.PACKET_OUT.toString());
-        ctrReadFlowRemoved =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.FLOW_REMOVED.toString());
-        ctrReadPortStatus =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.PORT_STATUS.toString());
-        ctrReadFlowMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.FLOW_MOD.toString());
-        ctrReadPortMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.PORT_MOD.toString());
-        ctrReadStatsRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.STATS_REQUEST.toString());
-        ctrReadStatsReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.STATS_REPLY.toString());
-        ctrReadBarrierRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.BARRIER_REQUEST.toString());
-        ctrReadBarrierReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.BARRIER_REPLY.toString());
-        ctrReadGetAsyncReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GET_ASYNC_REPLY.toString());
-        ctrReadGetAsyncRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GET_ASYNC_REQUEST.toString());
-        ctrReadGroupMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.GROUP_MOD.toString());
-        ctrReadMeterMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.METER_MOD.toString());
-        ctrReadQueueGetConfigReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.QUEUE_GET_CONFIG_REPLY.toString());
-        ctrReadQueueGetConfigRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.QUEUE_GET_CONFIG_REQUEST.toString());
-        ctrReadRoleReply =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ROLE_REPLY.toString());
-        ctrReadRoleRequest =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.ROLE_REQUEST.toString());
-        ctrReadSetAsync =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.SET_ASYNC.toString());
-        ctrReadTableMod =
-                registerCounterLocal(counters,
-                                     hierarchy,
-                                     stringId,
-                                     OFType.TABLE_MOD.toString());
-    }
-
-   /**
-    * Update Write Counters for Open flow messages
-    * @param ofm openflow message
-    */
-   public void updateWriteStats(OFMessage ofm) {
-         switch(ofm.getType()){
-            case BARRIER_REPLY:
-                ctrWriteBarrierReply.increment();
-                break;
-
-            case BARRIER_REQUEST:
-                ctrWriteBarrierRequest.increment();
-                break;
-
-            case ECHO_REPLY:
-                ctrWriteEchoReply.increment();
-                break;
-
-            case ECHO_REQUEST:
-                ctrWriteEchoRequest.increment();
-                break;
-
-            case ERROR:
-                ctrWriteError.increment();
-                break;
-
-            case EXPERIMENTER:
-                ctrWriteExperimenter.increment();
-                break;
-
-            case FEATURES_REPLY:
-                ctrWriteFeaturesReply.increment();
-                break;
-
-            case FEATURES_REQUEST:
-                ctrWriteFeaturesRequest.increment();
-                break;
-
-            case FLOW_MOD:
-                ctrWriteFlowMod.increment();
-                break;
-
-            case FLOW_REMOVED:
-                ctrWriteFlowRemoved.increment();
-                break;
-
-            case GET_ASYNC_REPLY:
-                ctrWriteGetAsyncReply.increment();
-                break;
-
-            case GET_ASYNC_REQUEST:
-                ctrWriteGetAsyncRequest.increment();
-                break;
-
-            case GET_CONFIG_REPLY:
-                ctrWriteGetConfigReply.increment();
-                break;
-
-            case GET_CONFIG_REQUEST:
-                ctrWriteGetConfigRequest.increment();
-                break;
-
-            case GROUP_MOD:
-                ctrWriteGroupMod.increment();
-                break;
-
-            case HELLO:
-                ctrWriteHello.increment();
-                break;
-
-            case METER_MOD:
-                ctrWriteMeterMod.increment();
-                break;
-
-            case PACKET_IN:
-                ctrWritePacketIn.increment();
-                break;
-
-            case PACKET_OUT:
-                ctrWritePacketOut.increment();
-                break;
-
-            case PORT_MOD:
-                ctrWritePortMod.increment();
-                break;
-
-            case PORT_STATUS:
-                ctrWritePortStatus.increment();
-                break;
-
-            case QUEUE_GET_CONFIG_REPLY:
-                ctrWriteQueueGetConfigReply.increment();
-                break;
-
-            case QUEUE_GET_CONFIG_REQUEST:
-                ctrWriteQueueGetConfigRequest.increment();
-                break;
-
-            case ROLE_REPLY:
-                ctrWriteRoleReply.increment();
-                break;
-
-            case ROLE_REQUEST:
-                ctrWriteRoleRequest.increment();
-                break;
-
-            case SET_ASYNC:
-                ctrWriteSetAsync.increment();
-                break;
-
-            case SET_CONFIG:
-                ctrWriteSetConfig.increment();
-                break;
-
-            case STATS_REPLY:
-                ctrWriteStatsReply.increment();
-                break;
-
-            case STATS_REQUEST:
-                ctrWriteStatsRequest.increment();
-                break;
-
-            case TABLE_MOD:
-                ctrWriteTableMod.increment();
-                break;
-
-            default:
-                logger.warn(ofm.getType().toString() +
-                            ": Invalid OpenFlow Messaqe!");
-                break;
-         }
-    }
-
-   /**
-    * Update Read openflow counters for this connection
-    * @param ofm Open Flow Message
-    */
-   public void updateReadStats(OFMessage ofm){
-       switch(ofm.getType()){
-           case BARRIER_REPLY:
-               ctrReadBarrierReply.increment();
-               break;
-
-           case BARRIER_REQUEST:
-               ctrReadBarrierRequest.increment();
-               break;
-
-           case ECHO_REPLY:
-               ctrReadEchoReply.increment();
-               break;
-
-           case ECHO_REQUEST:
-               ctrReadEchoRequest.increment();
-               break;
-
-           case ERROR:
-               ctrReadError.increment();
-               break;
-
-           case EXPERIMENTER:
-               ctrReadExperimenter.increment();
-               break;
-
-           case FEATURES_REPLY:
-               ctrReadFeaturesReply.increment();
-               break;
-
-           case FEATURES_REQUEST:
-               ctrReadFeaturesRequest.increment();
-               break;
-
-           case FLOW_MOD:
-               ctrReadFlowMod.increment();
-               break;
-
-           case FLOW_REMOVED:
-               ctrReadFlowRemoved.increment();
-               break;
-
-           case GET_ASYNC_REPLY:
-               ctrReadGetAsyncReply.increment();
-               break;
-
-           case GET_ASYNC_REQUEST:
-               ctrReadGetAsyncRequest.increment();
-               break;
-
-           case GET_CONFIG_REPLY:
-               ctrReadGetConfigReply.increment();
-               break;
-
-           case GET_CONFIG_REQUEST:
-               ctrReadGetConfigRequest.increment();
-               break;
-
-           case GROUP_MOD:
-               ctrReadGroupMod.increment();
-               break;
-
-           case HELLO:
-               ctrReadHello.increment();
-               break;
-
-           case METER_MOD:
-               ctrReadMeterMod.increment();
-               break;
-
-           case PACKET_IN:
-               ctrReadPacketIn.increment();
-               break;
-
-           case PACKET_OUT:
-               ctrReadPacketOut.increment();
-               break;
-
-           case PORT_MOD:
-               ctrReadPortMod.increment();
-               break;
-
-           case PORT_STATUS:
-               ctrReadPortStatus.increment();
-               break;
-
-           case QUEUE_GET_CONFIG_REPLY:
-               ctrReadQueueGetConfigReply.increment();
-               break;
-
-           case QUEUE_GET_CONFIG_REQUEST:
-               ctrReadQueueGetConfigRequest.increment();
-               break;
-
-           case ROLE_REPLY:
-               ctrReadRoleReply.increment();
-               break;
-
-           case ROLE_REQUEST:
-               ctrReadRoleRequest.increment();
-               break;
-
-           case SET_ASYNC:
-               ctrReadSetAsync.increment();
-               break;
-
-           case SET_CONFIG:
-               ctrReadSetConfig.increment();
-               break;
-
-           case STATS_REPLY:
-               ctrReadStatsReply.increment();
-               break;
-
-           case STATS_REQUEST:
-               ctrReadStatsRequest.increment();
-               break;
-
-           case TABLE_MOD:
-               ctrReadTableMod.increment();
-               break;
-
-           default:
-               logger.warn(ofm.getType().toString() +
-                           ": Invalid OpenFlow Messaqe!");
-               break;
-        }
-   }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/OFErrorMsgException.java b/src/main/java/net/floodlightcontroller/core/OFErrorMsgException.java
deleted file mode 100644
index f990f0a451052dfac060673e5bca7b20d6e802ad..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/OFErrorMsgException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.floodlightcontroller.core;
-
-import org.projectfloodlight.openflow.protocol.OFErrorMsg;
-import org.projectfloodlight.openflow.protocol.OFRequest;
-
-/** raised/reported by Futures in @IOFConnection when a an
- *  {@link OFErrorMsg} is received in response to a {@link OFRequest}
- *  sent via {@link OFConnection#writeRequest(OFRequest)} or
- *  {@link OFConnection#writeStatsRequest(org.projectfloodlight.openflow.protocol.OFStatsRequest)}.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- */
-public class OFErrorMsgException extends Exception {
-    private static final long serialVersionUID = 1L;
-
-    private final OFErrorMsg errorMessage;
-
-    public OFErrorMsgException(final OFErrorMsg errorMessage) {
-        super("OF error received: " + errorMessage.toString());
-        this.errorMessage = errorMessage;
-    }
-
-    /** @return the received OFErrorMsg that caused the error to be raised.
-     */
-    public OFErrorMsg getErrorMessage() {
-        return errorMessage;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/OFMessageFilterManager.java b/src/main/java/net/floodlightcontroller/core/OFMessageFilterManager.java
index 9a0348767c6d7b952cb9496169d3477b180d6865..c5adf4470355476526cfe896c92195760d5e8d0f 100644
--- a/src/main/java/net/floodlightcontroller/core/OFMessageFilterManager.java
+++ b/src/main/java/net/floodlightcontroller/core/OFMessageFilterManager.java
@@ -29,12 +29,12 @@ import java.util.concurrent.ScheduledExecutorService;
 
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.jboss.netty.buffer.ChannelBuffers;
-import org.projectfloodlight.openflow.protocol.OFFlowMod;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFType;
+import org.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -226,9 +226,9 @@ public class OFMessageFilterManager
             OFPacketOut p = (OFPacketOut) m;
             
             // No MAC match if packetOut doesn't have the packet.
-            if (p.getData() == null) return null;
+            if (p.getPacketData() == null) return null;
             
-            eth.deserialize(p.getData(), 0, p.getData().length);
+            eth.deserialize(p.getPacketData(), 0, p.getPacketData().length);
         } else if (m.getType() == OFType.FLOW_MOD) {
             // flow-mod can't be matched by mac.
             return null;
diff --git a/src/main/java/net/floodlightcontroller/core/OFSwitch.java b/src/main/java/net/floodlightcontroller/core/OFSwitch.java
deleted file mode 100644
index 38b5ddaa6b2bb7a49a3a31deadb1b21cd2719a94..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/OFSwitch.java
+++ /dev/null
@@ -1,1131 +0,0 @@
-/**
-*    Copyright 2012, 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.core;
-
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import javax.annotation.Nonnull;
-
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
-import net.floodlightcontroller.core.internal.IOFSwitchManager;
-import net.floodlightcontroller.core.util.AppCookie;
-import net.floodlightcontroller.core.util.URIUtil;
-
-import org.projectfloodlight.openflow.protocol.OFActionType;
-import org.projectfloodlight.openflow.protocol.OFBsnControllerConnection;
-import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionState;
-import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionsReply;
-import org.projectfloodlight.openflow.protocol.OFCapabilities;
-import org.projectfloodlight.openflow.protocol.OFControllerRole;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFFlowWildcards;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFPortReason;
-import org.projectfloodlight.openflow.protocol.OFPortState;
-import org.projectfloodlight.openflow.protocol.OFPortStatus;
-import org.projectfloodlight.openflow.protocol.OFRequest;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFAuxId;
-import org.projectfloodlight.openflow.types.OFPort;
-
-import net.floodlightcontroller.util.LinkedHashSetWrapper;
-import net.floodlightcontroller.util.OrderedCollection;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListenableFuture;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-/**
- * This is the internal representation of an openflow switch.
- */
-public class OFSwitch implements IOFSwitchBackend {
-    protected static final Logger log =
-            LoggerFactory.getLogger(OFSwitch.class);
-
-    protected final ConcurrentMap<Object, Object> attributes;
-    protected final IOFSwitchManager switchManager;
-
-    /* Switch features from initial featuresReply */
-    protected Set<OFCapabilities> capabilities;
-    protected long buffers;
-    protected Set<OFActionType> actions;
-    protected short tables;
-    protected final DatapathId datapathId;
-
-    private boolean startDriverHandshakeCalled = false;
-    private final Map<OFAuxId, IOFConnectionBackend> connections;
-    private volatile Map<URI, Map<OFAuxId, OFBsnControllerConnection>> controllerConnections;
-    protected OFFactory factory;
-
-    /**
-     * Members hidden from subclasses
-     */
-    private final PortManager portManager;
-
-    private volatile boolean connected;
-
-    private volatile OFControllerRole role;
-
-    private boolean flowTableFull = false;
-
-    protected SwitchDescription description;
-
-    private GenTableMap genTableMap;
-
-    private SwitchStatus status;
-
-    public static final int OFSWITCH_APP_ID = ident(5);
-
-    static {
-        AppCookie.registerApp(OFSwitch.OFSWITCH_APP_ID, "switch");
-    }
-
-    public OFSwitch(IOFConnectionBackend connection, @Nonnull OFFactory factory, @Nonnull IOFSwitchManager switchManager,
-            @Nonnull DatapathId datapathId) {
-        if(connection == null)
-            throw new NullPointerException("connection must not be null");
-        if(!connection.getAuxId().equals(OFAuxId.MAIN))
-            throw new IllegalArgumentException("connection must be the main connection");
-        if(factory == null)
-            throw new NullPointerException("factory must not be null");
-        if(switchManager == null)
-            throw new NullPointerException("switchManager must not be null");
-
-        this.connected = true;
-        this.factory = factory;
-        this.switchManager = switchManager;
-        this.datapathId = datapathId;
-        this.attributes = new ConcurrentHashMap<Object, Object>();
-        this.role = null;
-        this.description = new SwitchDescription();
-        this.portManager = new PortManager();
-        this.genTableMap = GenTableMap.empty();
-        this.status = SwitchStatus.HANDSHAKE;
-
-        // Connections
-        this.connections = new ConcurrentHashMap<OFAuxId, IOFConnectionBackend>();
-        this.connections.put(connection.getAuxId(), connection);
-
-        // Switch's controller connection
-        this.controllerConnections = ImmutableMap.of();
-
-        // Defaults properties for an ideal switch
-        this.setAttribute(PROP_FASTWILDCARDS, EnumSet.allOf(OFFlowWildcards.class));
-        this.setAttribute(PROP_SUPPORTS_OFPP_FLOOD, Boolean.TRUE);
-        this.setAttribute(PROP_SUPPORTS_OFPP_TABLE, Boolean.TRUE);
-    }
-
-    private static int ident(int i) {
-        return i;
-    }
-
-    @Override
-    public OFFactory getOFFactory() {
-        return factory;
-    }
-
-    /**
-     * Manages the ports of this switch.
-     *
-     * Provides methods to query and update the stored ports. The class ensures
-     * that every port name and port number is unique. When updating ports
-     * the class checks if port number <-> port name mappings have change due
-     * to the update. If a new port P has number and port that are inconsistent
-     * with the previous mapping(s) the class will delete all previous ports
-     * with name or number of the new port and then add the new port.
-     *
-     * Port names are stored as-is but they are compared case-insensitive
-     *
-     * The methods that change the stored ports return a list of
-     * PortChangeEvents that represent the changes that have been applied
-     * to the port list so that IOFSwitchListeners can be notified about the
-     * changes.
-     *
-     * Implementation notes:
-     * - We keep several different representations of the ports to allow for
-     *   fast lookups
-     * - Ports are stored in unchangeable lists. When a port is modified new
-     *   data structures are allocated.
-     * - We use a read-write-lock for synchronization, so multiple readers are
-     *   allowed.
-     */
-    protected static class PortManager {
-        private final ReentrantReadWriteLock lock;
-        private List<OFPortDesc> portList;
-        private List<OFPortDesc> enabledPortList;
-        private List<OFPort> enabledPortNumbers;
-        private Map<OFPort,OFPortDesc> portsByNumber;
-        private Map<String,OFPortDesc> portsByName;
-
-        public PortManager() {
-            this.lock = new ReentrantReadWriteLock();
-            this.portList = Collections.emptyList();
-            this.enabledPortList = Collections.emptyList();
-            this.enabledPortNumbers = Collections.emptyList();
-            this.portsByName = Collections.emptyMap();
-            this.portsByNumber = Collections.emptyMap();
-        }
-
-        /**
-         * Set the internal data structure storing this switch's port
-         * to the ports specified by newPortsByNumber
-         *
-         * CALLER MUST HOLD WRITELOCK
-         *
-         * @param newPortsByNumber
-         * @throws IllegaalStateException if called without holding the
-         * writelock
-         */
-        private void updatePortsWithNewPortsByNumber(
-                Map<OFPort,OFPortDesc> newPortsByNumber) {
-            if (!lock.writeLock().isHeldByCurrentThread()) {
-                throw new IllegalStateException("Method called without " +
-                                                "holding writeLock");
-            }
-            Map<String,OFPortDesc> newPortsByName =
-                    new HashMap<String, OFPortDesc>();
-            List<OFPortDesc> newPortList =
-                    new ArrayList<OFPortDesc>();
-            List<OFPortDesc> newEnabledPortList =
-                    new ArrayList<OFPortDesc>();
-            List<OFPort> newEnabledPortNumbers = new ArrayList<OFPort>();
-
-            for(OFPortDesc p: newPortsByNumber.values()) {
-                newPortList.add(p);
-                newPortsByName.put(p.getName().toLowerCase(), p);
-                if (p.getState().contains(OFPortState.LIVE)) {
-                    newEnabledPortList.add(p);
-                    newEnabledPortNumbers.add(p.getPortNo());
-                }
-            }
-            portsByName = Collections.unmodifiableMap(newPortsByName);
-            portsByNumber =
-                    Collections.unmodifiableMap(newPortsByNumber);
-            enabledPortList =
-                    Collections.unmodifiableList(newEnabledPortList);
-            enabledPortNumbers =
-                    Collections.unmodifiableList(newEnabledPortNumbers);
-            portList = Collections.unmodifiableList(newPortList);
-        }
-
-        /**
-         * Handle a OFPortStatus delete message for the given port.
-         * Updates the internal port maps/lists of this switch and returns
-         * the PortChangeEvents caused by the delete. If the given port
-         * exists as it, it will be deleted. If the name<->number for the
-         * given port is inconsistent with the ports stored by this switch
-         * the method will delete all ports with the number or name of the
-         * given port.
-         *
-         * This method will increment error/warn counters and log
-         *
-         * @param delPort the port from the port status message that should
-         * be deleted.
-         * @return ordered collection of port changes applied to this switch
-         */
-        private OrderedCollection<PortChangeEvent>
-                handlePortStatusDelete(OFPortDesc delPort) {
-            OrderedCollection<PortChangeEvent> events =
-                    new LinkedHashSetWrapper<PortChangeEvent>();
-            lock.writeLock().lock();
-            try {
-                Map<OFPort,OFPortDesc> newPortByNumber =
-                        new HashMap<OFPort, OFPortDesc>(portsByNumber);
-                OFPortDesc prevPort =
-                        portsByNumber.get(delPort.getPortNo());
-                if (prevPort == null) {
-                    // so such port. Do we have a port with the name?
-                    prevPort = portsByName.get(delPort.getName());
-                    if (prevPort != null) {
-                        newPortByNumber.remove(prevPort.getPortNo());
-                        events.add(new PortChangeEvent(prevPort,
-                                                       PortChangeType.DELETE));
-                    }
-                } else if (prevPort.getName().equals(delPort.getName())) {
-                    // port exists with consistent name-number mapping
-                    newPortByNumber.remove(delPort.getPortNo());
-                    events.add(new PortChangeEvent(delPort,
-                                                   PortChangeType.DELETE));
-                } else {
-                    // port with same number exists but its name differs. This
-                    // is weird. The best we can do is to delete the existing
-                    // port(s) that have delPort's name and number.
-                    newPortByNumber.remove(delPort.getPortNo());
-                    events.add(new PortChangeEvent(prevPort,
-                                                   PortChangeType.DELETE));
-                    // is there another port that has delPort's name?
-                    prevPort = portsByName.get(delPort.getName().toLowerCase());
-                    if (prevPort != null) {
-                        newPortByNumber.remove(prevPort.getPortNo());
-                        events.add(new PortChangeEvent(prevPort,
-                                                       PortChangeType.DELETE));
-                    }
-                }
-                updatePortsWithNewPortsByNumber(newPortByNumber);
-                return events;
-            } finally {
-                lock.writeLock().unlock();
-            }
-        }
-
-        /**
-         * Handle a OFPortStatus message, update the internal data structures
-         * that store ports and return the list of OFChangeEvents.
-         *
-         * This method will increment error/warn counters and log
-         *
-         * @param ps
-         * @return
-         */
-        @SuppressFBWarnings(value="SF_SWITCH_FALLTHROUGH")
-        public OrderedCollection<PortChangeEvent> handlePortStatusMessage(OFPortStatus ps) {
-            if (ps == null) {
-                throw new NullPointerException("OFPortStatus message must " +
-                                               "not be null");
-            }
-            lock.writeLock().lock();
-            try {
-                OFPortDesc port = ps.getDesc();
-                OFPortReason reason = ps.getReason();
-                if (reason == null) {
-                    throw new IllegalArgumentException("Unknown PortStatus " +
-                            "reason code " + ps.getReason());
-                }
-
-                if (log.isDebugEnabled()) {
-                    log.debug("Handling OFPortStatus: {} for {}",
-                              reason, String.format("%s (%d)", port.getName(), port.getPortNo().getPortNumber()));
-                }
-
-                if (reason == OFPortReason.DELETE)
-                    return handlePortStatusDelete(port);
-
-                // We handle ADD and MODIFY the same way. Since OpenFlow
-                // doesn't specify what uniquely identifies a port the
-                // notion of ADD vs. MODIFY can also be hazy. So we just
-                // compare the new port to the existing ones.
-                Map<OFPort,OFPortDesc> newPortByNumber =
-                    new HashMap<OFPort, OFPortDesc>(portsByNumber);
-                OrderedCollection<PortChangeEvent> events = getSinglePortChanges(port);
-                for (PortChangeEvent e: events) {
-                    switch(e.type) {
-                        case DELETE:
-                            newPortByNumber.remove(e.port.getPortNo());
-                            break;
-                        case ADD:
-                            if (reason != OFPortReason.ADD) {
-                                // weird case
-                            }
-                            // fall through
-                        case DOWN:
-                        case OTHER_UPDATE:
-                        case UP:
-                            // update or add the port in the map
-                            newPortByNumber.put(e.port.getPortNo(), e.port);
-                            break;
-                    }
-                }
-                updatePortsWithNewPortsByNumber(newPortByNumber);
-                return events;
-            } finally {
-                lock.writeLock().unlock();
-            }
-
-        }
-
-        /**
-         * Given a new or modified port newPort, returns the list of
-         * PortChangeEvents to "transform" the current ports stored by
-         * this switch to include / represent the new port. The ports stored
-         * by this switch are <b>NOT</b> updated.
-         *
-         * This method acquires the readlock and is thread-safe by itself.
-         * Most callers will need to acquire the write lock before calling
-         * this method though (if the caller wants to update the ports stored
-         * by this switch)
-         *
-         * @param newPort the new or modified port.
-         * @return the list of changes
-         */
-        public OrderedCollection<PortChangeEvent>
-                getSinglePortChanges(OFPortDesc newPort) {
-            lock.readLock().lock();
-            try {
-                OrderedCollection<PortChangeEvent> events =
-                        new LinkedHashSetWrapper<PortChangeEvent>();
-                // Check if we have a port by the same number in our
-                // old map.
-                OFPortDesc prevPort =
-                        portsByNumber.get(newPort.getPortNo());
-                if (newPort.equals(prevPort)) {
-                    // nothing has changed
-                    return events;
-                }
-
-                if (prevPort != null &&
-                        prevPort.getName().equals(newPort.getName())) {
-                    // A simple modify of a exiting port
-                    // A previous port with this number exists and it's name
-                    // also matches the new port. Find the differences
-                    if (prevPort.getState().contains(OFPortState.LIVE) && !newPort.getState().contains(OFPortState.LIVE)) {
-                        events.add(new PortChangeEvent(newPort,
-                                                       PortChangeType.DOWN));
-                    } else if (!prevPort.getState().contains(OFPortState.LIVE) && newPort.getState().contains(OFPortState.LIVE)) {
-                        events.add(new PortChangeEvent(newPort,
-                                                       PortChangeType.UP));
-                    } else {
-                        events.add(new PortChangeEvent(newPort,
-                                   PortChangeType.OTHER_UPDATE));
-                    }
-                    return events;
-                }
-
-                if (prevPort != null) {
-                    // There exists a previous port with the same port
-                    // number but the port name is different (otherwise we would
-                    // never have gotten here)
-                    // Remove the port. Name-number mapping(s) have changed
-                    events.add(new PortChangeEvent(prevPort,
-                                                   PortChangeType.DELETE));
-                }
-
-                // We now need to check if there exists a previous port sharing
-                // the same name as the new/updated port.
-                prevPort = portsByName.get(newPort.getName().toLowerCase());
-                if (prevPort != null) {
-                    // There exists a previous port with the same port
-                    // name but the port number is different (otherwise we
-                    // never have gotten here).
-                    // Remove the port. Name-number mapping(s) have changed
-                    events.add(new PortChangeEvent(prevPort,
-                                                   PortChangeType.DELETE));
-                }
-
-                // We always need to add the new port. Either no previous port
-                // existed or we just deleted previous ports with inconsistent
-                // name-number mappings
-                events.add(new PortChangeEvent(newPort, PortChangeType.ADD));
-                return events;
-            } finally {
-                lock.readLock().unlock();
-            }
-        }
-
-        /**
-         * Compare the current ports of this switch to the newPorts list and
-         * return the changes that would be applied to transfort the current
-         * ports to the new ports. No internal data structures are updated
-         * see {@link #compareAndUpdatePorts(List, boolean)}
-         *
-         * @param newPorts the list of new ports
-         * @return The list of differences between the current ports and
-         * newPortList
-         */
-        public OrderedCollection<PortChangeEvent>
-                comparePorts(Collection<OFPortDesc> newPorts) {
-            return compareAndUpdatePorts(newPorts, false);
-        }
-
-        /**
-         * Compare the current ports of this switch to the newPorts list and
-         * return the changes that would be applied to transform the current
-         * ports to the new ports. No internal data structures are updated
-         * see {@link #compareAndUpdatePorts(List, boolean)}
-         *
-         * @param newPorts the list of new ports
-         * @return The list of differences between the current ports and
-         * newPortList
-         */
-        public OrderedCollection<PortChangeEvent>
-                updatePorts(Collection<OFPortDesc> newPorts) {
-            return compareAndUpdatePorts(newPorts, true);
-        }
-
-        /**
-         * Compare the current ports stored in this switch instance with the
-         * new port list given and return the differences in the form of
-         * PortChangeEvents. If the doUpdate flag is true, newPortList will
-         * replace the current list of this switch (and update the port maps)
-         *
-         * Implementation note:
-         * Since this method can optionally modify the current ports and
-         * since it's not possible to upgrade a read-lock to a write-lock
-         * we need to hold the write-lock for the entire operation. If this
-         * becomes a problem and if compares() are common we can consider
-         * splitting in two methods but this requires lots of code duplication
-         *
-         * @param newPorts the list of new ports.
-         * @param doUpdate If true the newPortList will replace the current
-         * port list for this switch. If false this switch will not be changed.
-         * @return The list of differences between the current ports and
-         * newPorts
-         * @throws NullPointerException if newPortsList is null
-         * @throws IllegalArgumentException if either port names or port numbers
-         * are duplicated in the newPortsList.
-         */
-        private OrderedCollection<PortChangeEvent> compareAndUpdatePorts(
-                Collection<OFPortDesc> newPorts,
-                boolean doUpdate) {
-            if (newPorts == null) {
-                throw new NullPointerException("newPortsList must not be null");
-            }
-            lock.writeLock().lock();
-            try {
-                OrderedCollection<PortChangeEvent> events =
-                        new LinkedHashSetWrapper<PortChangeEvent>();
-
-                Map<OFPort,OFPortDesc> newPortsByNumber =
-                        new HashMap<OFPort, OFPortDesc>();
-                Map<String,OFPortDesc> newPortsByName =
-                        new HashMap<String, OFPortDesc>();
-                List<OFPortDesc> newEnabledPortList =
-                        new ArrayList<OFPortDesc>();
-                List<OFPort> newEnabledPortNumbers =
-                        new ArrayList<OFPort>();
-                List<OFPortDesc> newPortsList =
-                        new ArrayList<OFPortDesc>(newPorts);
-
-                for (OFPortDesc p: newPortsList) {
-                    if (p == null) {
-                        throw new NullPointerException("portList must not " +
-                                "contain null values");
-                    }
-
-                    // Add the port to the new maps and lists and check
-                    // that every port is unique
-                    OFPortDesc duplicatePort;
-                    duplicatePort = newPortsByNumber.put(p.getPortNo(), p);
-                    if (duplicatePort != null) {
-                        String msg = String.format("Cannot have two ports " +
-                                "with the same number: %s <-> %s",
-                                String.format("%s (%d)", p.getName(), p.getPortNo().getPortNumber()),
-                                String.format("%s (%d)", duplicatePort.getName(), duplicatePort.getPortNo().getPortNumber()));
-                        throw new IllegalArgumentException(msg);
-                    }
-                    duplicatePort =
-                            newPortsByName.put(p.getName().toLowerCase(), p);
-                    if (duplicatePort != null) {
-                        String msg = String.format("Cannot have two ports " +
-                                "with the same name: %s <-> %s",
-                                String.format("%s (%d)", p.getName(), p.getPortNo().getPortNumber()),
-                                String.format("%s (%d)", duplicatePort.getName(), duplicatePort.getPortNo().getPortNumber()));
-                        throw new IllegalArgumentException(msg);
-                    }
-                    if (p.getState().contains(OFPortState.LIVE)) {
-                        newEnabledPortList.add(p);
-                        newEnabledPortNumbers.add(p.getPortNo());
-                    }
-
-                    // get changes
-                    events.addAll(getSinglePortChanges(p));
-                }
-                // find deleted ports
-                // We need to do this after looping through all the new ports
-                // to we can handle changed name<->number mappings correctly
-                // We could pull it into the loop of we address this but
-                // it's probably not worth it
-                for (OFPortDesc oldPort: this.portList) {
-                    if (!newPortsByNumber.containsKey(oldPort.getPortNo())) {
-                        PortChangeEvent ev =
-                                new PortChangeEvent(oldPort,
-                                                    PortChangeType.DELETE);
-                        events.add(ev);
-                    }
-                }
-
-
-                if (doUpdate) {
-                    portsByName = Collections.unmodifiableMap(newPortsByName);
-                    portsByNumber =
-                            Collections.unmodifiableMap(newPortsByNumber);
-                    enabledPortList =
-                            Collections.unmodifiableList(newEnabledPortList);
-                    enabledPortNumbers =
-                            Collections.unmodifiableList(newEnabledPortNumbers);
-                    portList = Collections.unmodifiableList(newPortsList);
-                }
-                return events;
-            } finally {
-                lock.writeLock().unlock();
-            }
-        }
-
-        public OFPortDesc getPort(String name) {
-            if (name == null) {
-                throw new NullPointerException("Port name must not be null");
-            }
-            lock.readLock().lock();
-            try {
-                return portsByName.get(name.toLowerCase());
-            } finally {
-                lock.readLock().unlock();
-            }
-        }
-
-        public OFPortDesc getPort(OFPort portNumber) {
-            lock.readLock().lock();
-            try {
-                return portsByNumber.get(portNumber);
-            } finally {
-                lock.readLock().unlock();
-            }
-        }
-
-        public List<OFPortDesc> getPorts() {
-            lock.readLock().lock();
-            try {
-                return portList;
-            } finally {
-                lock.readLock().unlock();
-            }
-        }
-
-        public List<OFPortDesc> getEnabledPorts() {
-            lock.readLock().lock();
-            try {
-                return enabledPortList;
-            } finally {
-                lock.readLock().unlock();
-            }
-        }
-
-        public List<OFPort> getEnabledPortNumbers() {
-            lock.readLock().lock();
-            try {
-                return enabledPortNumbers;
-            } finally {
-                lock.readLock().unlock();
-            }
-        }
-    }
-
-    @Override
-    public boolean attributeEquals(String name, Object other) {
-        Object attr = this.attributes.get(name);
-        if (attr == null)
-            return false;
-        return attr.equals(other);
-    }
-
-    @Override
-    public Object getAttribute(String name) {
-        // returns null if key doesn't exist
-        return this.attributes.get(name);
-    }
-
-    @Override
-    public void setAttribute(String name, Object value) {
-        this.attributes.put(name, value);
-        return;
-    }
-
-    @Override
-    public Object removeAttribute(String name) {
-        return this.attributes.remove(name);
-    }
-
-    @Override
-    public boolean hasAttribute(String name) {
-        return this.attributes.containsKey(name);
-    }
-
-    @Override
-    public void registerConnection(IOFConnectionBackend connection) {
-        this.connections.put(connection.getAuxId(), connection);
-    }
-
-
-    @Override
-    public ImmutableList<IOFConnection> getConnections() {
-        return ImmutableList.<IOFConnection> copyOf(this.connections.values());
-    }
-
-    @Override
-    public void removeConnections() {
-        this.connections.clear();
-    }
-
-    @Override
-    public void removeConnection(IOFConnectionBackend connection) {
-        this.connections.remove(connection.getAuxId());
-    }
-
-    @Override
-    public void write(OFMessage m) {
-        connections.get(OFAuxId.MAIN).write(m);
-    }
-
-    /**
-     * Gets a connection specified by aux Id.
-     * @param auxId the specified aux id for the connection desired.
-     * @return the aux connection specified by the auxId
-     */
-    public IOFConnection getConnection(OFAuxId auxId) {
-        IOFConnection connection = this.connections.get(auxId);
-        if(connection == null){
-            throw new IllegalArgumentException("OF Connection for " + this + " with " + auxId + " does not exist.");
-        }
-        return connection;
-    }
-
-    public IOFConnection getConnection(LogicalOFMessageCategory category) {
-        if(switchManager.isCategoryRegistered(category)){
-            return getConnection(category.getAuxId());
-        }
-        else{
-            throw new IllegalArgumentException(category + " is not registered with the floodlight provider service.");
-        }
-    }
-
-    @Override
-    public void write(OFMessage m, LogicalOFMessageCategory category) {
-        this.getConnection(category).write(m);
-    }
-
-    @Override
-    public void write(Iterable<OFMessage> msglist, LogicalOFMessageCategory category) {
-        this.getConnection(category).write(msglist);
-    }
-
-    @Override
-    public OFConnection getConnectionByCategory(LogicalOFMessageCategory category){
-        return (OFConnection) this.getConnection(category);
-    }
-
-    @Override
-    public <R extends OFMessage> ListenableFuture<R> writeRequest(OFRequest<R> request, LogicalOFMessageCategory category) {
-        return getConnection(category).writeRequest(request);
-    }
-
-    @Override
-    public <R extends OFMessage> ListenableFuture<R> writeRequest(OFRequest<R> request) {
-        return connections.get(OFAuxId.MAIN).writeRequest(request);
-    }
-
-    @Override
-    @LogMessageDoc(level="WARN",
-                   message="Sending OF message that modifies switch " +
-                           "state while in the slave role: {switch}",
-                   explanation="An application has sent a message to a switch " +
-                           "that is not valid when the switch is in a slave role",
-                   recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    public void write(Iterable<OFMessage> msglist) {
-        connections.get(OFAuxId.MAIN).write(msglist);
-    }
-
-    @Override
-    public void disconnect() {
-
-        // Iterate through connections and perform cleanup
-        for(Entry<OFAuxId, IOFConnectionBackend> entry : this.connections.entrySet()){
-            entry.getValue().disconnect();
-            this.connections.remove(entry.getKey());
-        }
-
-        connected = false;
-    }
-
-    @Override
-    public void setFeaturesReply(OFFeaturesReply featuresReply) {
-        if (portManager.getPorts().isEmpty() && featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0) {
-            /* ports are updated via port status message, so we
-             * only fill in ports on initial connection.
-             */
-            List<OFPortDesc> OFPortDescs = featuresReply.getPorts();
-            portManager.updatePorts(OFPortDescs);
-        }
-        this.capabilities = featuresReply.getCapabilities();
-        this.buffers = featuresReply.getNBuffers();
-
-        if (featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0 ) {
-            // FIXME:LOJI: OF1.3 has per table actions. This needs to be modeled / handled here
-            this.actions = featuresReply.getActions();
-        }
-        this.tables = featuresReply.getNTables();
-    }
-
-    @Override
-    public void setPortDescStats(OFPortDescStatsReply reply) {
-        /* ports are updated via port status message, so we
-         * only fill in ports on initial connection.
-         */
-        List<OFPortDesc> OFPortDescs = reply.getEntries();
-        portManager.updatePorts(OFPortDescs);
-    }
-
-    @Override
-    public Collection<OFPortDesc> getEnabledPorts() {
-        return portManager.getEnabledPorts();
-    }
-
-    @Override
-    public Collection<OFPort> getEnabledPortNumbers() {
-        return portManager.getEnabledPortNumbers();
-    }
-
-    @Override
-    public OFPortDesc getPort(OFPort portNumber) {
-        return portManager.getPort(portNumber);
-    }
-
-    @Override
-    public OFPortDesc getPort(String portName) {
-        return portManager.getPort(portName);
-    }
-
-    @Override
-    public OrderedCollection<PortChangeEvent>
-            processOFPortStatus(OFPortStatus ps) {
-        return portManager.handlePortStatusMessage(ps);
-    }
-
-    @Override
-    public Collection<OFPortDesc> getSortedPorts() {
-        // FIXME: Hopefully BigDB will handle this automatically soon (or not
-        // have the sorting requirement), in which case we could get rid of this
-        List<OFPortDesc> sortedPorts =
-                new ArrayList<OFPortDesc>(portManager.getPorts());
-        Collections.sort(sortedPorts, new Comparator<OFPortDesc>() {
-            @Override
-            public int compare(OFPortDesc o1, OFPortDesc o2) {
-                String name1 = o1.getName();
-                String name2 = o2.getName();
-                return name1.compareToIgnoreCase(name2);
-            }
-        });
-        return sortedPorts;
-    }
-
-    @Override
-    public Collection<OFPortDesc> getPorts() {
-        return portManager.getPorts();
-    }
-
-    @Override
-    public OrderedCollection<PortChangeEvent>
-            comparePorts(Collection<OFPortDesc> ports) {
-        return portManager.comparePorts(ports);
-    }
-
-    @Override
-    public OrderedCollection<PortChangeEvent>
-            setPorts(Collection<OFPortDesc> ports) {
-        return portManager.updatePorts(ports);
-    }
-
-    @Override
-    public boolean portEnabled(OFPort portNumber) {
-        OFPortDesc p = portManager.getPort(portNumber);
-        if (p == null) return false;
-        return p.getState().contains(OFPortState.LIVE);
-    }
-
-    @Override
-    public boolean portEnabled(String portName) {
-        OFPortDesc p = portManager.getPort(portName);
-        if (p == null) return false;
-        return p.getState().contains(OFPortState.LIVE);
-    }
-
-    @Override
-    public DatapathId getId() {
-        if (datapathId == null)
-            throw new RuntimeException("Features reply has not yet been set");
-        return datapathId;
-    }
-
-    @Override
-    public String getStringId() {
-        // FIXME: Should get rid of this
-        return getId().toString();
-    }
-
-    /* (non-Javadoc)
-     * @see java.lang.Object#toString()
-     */
-    @Override
-    public String toString() {
-        return "OFSwitchBase DPID[" + ((datapathId != null) ? datapathId.toString() : "?") + "]";
-    }
-
-    @Override
-    public ConcurrentMap<Object, Object> getAttributes() {
-        return this.attributes;
-    }
-
-    @Override
-    public Date getConnectedSince() {
-        return this.connections.get(OFAuxId.MAIN).getConnectedSince();
-    }
-
-    @Override
-    public <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> writeStatsRequest(OFStatsRequest<REPLY> request) {
-        return connections.get(OFAuxId.MAIN).writeStatsRequest(request);
-    }
-
-    @Override
-    public <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> writeStatsRequest(OFStatsRequest<REPLY> request, LogicalOFMessageCategory category) {
-        return getConnection(category).writeStatsRequest(request);
-    }
-
-    @Override
-    public void cancelAllPendingRequests() {
-        for(Entry<OFAuxId, IOFConnectionBackend> entry : this.connections.entrySet()){
-            entry.getValue().cancelAllPendingRequests();
-        }
-    }
-
-    // If any connections are down consider a switch disconnected
-    @Override
-    public boolean isConnected() {
-        return connected;
-    }
-
-    @Override
-    public boolean isActive() {
-        // no lock needed since we use volatile
-        return isConnected() && this.role == OFControllerRole.ROLE_MASTER;
-    }
-
-    @Override
-    public OFControllerRole getControllerRole() {
-        return role;
-    }
-
-    @Override
-    public void setControllerRole(OFControllerRole role) {
-        this.role = role;
-    }
-
-    @Override
-    public void flush() {
-        for(Entry<OFAuxId, IOFConnectionBackend> entry : this.connections.entrySet()){
-            entry.getValue().flush();
-        }
-    }
-
-    /**
-     * Get the IP Address for the switch
-     * @return the inet address
-     */
-    @Override
-    public SocketAddress getInetAddress() {
-        return connections.get(OFAuxId.MAIN).getRemoteInetAddress();
-    }
-
-    @Override
-    public long getBuffers() {
-        return buffers;
-    }
-
-
-    @Override
-    public Set<OFActionType> getActions() {
-        return actions;
-    }
-
-
-    @Override
-    public Set<OFCapabilities> getCapabilities() {
-        return capabilities;
-    }
-
-
-    @Override
-    public short getTables() {
-        return tables;
-    }
-
-    @Override
-    public SwitchDescription getSwitchDescription() {
-        return description;
-    }
-
-    @Override
-    @LogMessageDoc(level="WARN",
-        message="Switch {switch} flow table is full",
-        explanation="The controller received flow table full " +
-                "message from the switch, could be caused by increased " +
-                "traffic pattern",
-                recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    public void setTableFull(boolean isFull) {
-        if (isFull && !flowTableFull) {
-            switchManager.addSwitchEvent(this.datapathId,
-                    "SWITCH_FLOW_TABLE_FULL " +
-                    "Table full error from switch", false);
-            log.warn("Switch {} flow table is full", datapathId.toString());
-        }
-        flowTableFull = isFull;
-    }
-
-    @Override
-    public void startDriverHandshake() {
-        if (startDriverHandshakeCalled)
-            throw new SwitchDriverSubHandshakeAlreadyStarted();
-        startDriverHandshakeCalled = true;
-    }
-
-    @Override
-    public boolean isDriverHandshakeComplete() {
-        if (!startDriverHandshakeCalled)
-            throw new SwitchDriverSubHandshakeNotStarted();
-        return true;
-    }
-
-    @Override
-    public void processDriverHandshakeMessage(OFMessage m) {
-        if (startDriverHandshakeCalled)
-            throw new SwitchDriverSubHandshakeCompleted(m);
-        else
-            throw new SwitchDriverSubHandshakeNotStarted();
-    }
-
-    @Override
-    public GenTableMap getGenTableMap() {
-        return genTableMap;
-    }
-
-    @Override
-    public void setGenTableMap(GenTableMap map) {
-        this.genTableMap = map;
-    }
-
-    @Override
-    public void setSwitchProperties(SwitchDescription description) {
-        this.description = description;
-    }
-
-
-    @Override
-    public SwitchStatus getStatus() {
-        return status;
-    }
-
-    @Override
-    public void setStatus(SwitchStatus switchStatus) {
-        this.status = switchStatus;
-    }
-
-    /**
-     * Can the port be turned on without forming a new loop?
-     * <p>
-     * <b>FIXME</b> - This API is deprecated and will be removed soon. The
-     * property is currently not implemented by the platform, so this method
-     * always returns false. Whether or not a port is safe to use is dependent
-     * on the application strategy for forwarding traffic.
-     *
-     * @param port_num the port number to be tested
-     * @return always false for now.
-     */
-    @Deprecated
-    @Override
-    public boolean isFastPort(OFPort port_num) {
-        return false;
-    }
-
-    @Override
-    public void updateControllerConnections(OFBsnControllerConnectionsReply controllerCxnsReply) {
-
-        // Instantiate clean map, can't use a builder here since we need to call temp.get()
-        Map<URI,Map<OFAuxId, OFBsnControllerConnection>> temp = new ConcurrentHashMap<URI,Map<OFAuxId, OFBsnControllerConnection>>();
-
-        List<OFBsnControllerConnection> controllerCxnUpdates = controllerCxnsReply.getConnections();
-        for(OFBsnControllerConnection update : controllerCxnUpdates) {
-            URI uri = URI.create(update.getUri());
-
-            Map<OFAuxId, OFBsnControllerConnection> cxns = temp.get(uri);
-
-            // Add to nested map
-            if(cxns != null){
-                cxns.put(update.getAuxiliaryId(), update);
-            } else{
-                cxns = new ConcurrentHashMap<OFAuxId, OFBsnControllerConnection>();
-                cxns.put(update.getAuxiliaryId(), update);
-                temp.put(uri, cxns);
-            }
-        }
-
-        this.controllerConnections = ImmutableMap.<URI,Map<OFAuxId, OFBsnControllerConnection>>copyOf(temp);
-    }
-
-    @Override
-    public boolean hasAnotherMaster() {
-
-        //TODO: refactor get connection to not throw illegal arg exceptions
-        IOFConnection mainCxn = this.getConnection(OFAuxId.MAIN);
-
-        if(mainCxn != null) {
-
-            // Determine the local URI
-            InetSocketAddress address = (InetSocketAddress) mainCxn.getLocalInetAddress();
-            URI localURI = URIUtil.createURI(address.getHostName(), address.getPort());
-
-            for(Entry<URI,Map<OFAuxId, OFBsnControllerConnection>> entry : this.controllerConnections.entrySet()) {
-
-                // Don't check our own controller connections
-                URI uri = entry.getKey();
-                if(!localURI.equals(uri)){
-
-                    // We only care for the MAIN connection
-                    Map<OFAuxId, OFBsnControllerConnection> cxns = this.controllerConnections.get(uri);
-                    OFBsnControllerConnection controllerCxn = cxns.get(OFAuxId.MAIN);
-
-                    if(controllerCxn != null) {
-                        // If the controller id disconnected or not master we know it is not connected
-                        if(controllerCxn.getState() == OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED
-                                && controllerCxn.getRole() == OFControllerRole.ROLE_MASTER){
-                            return true;
-                        }
-                    } else {
-                        log.warn("Unable to find controller connection with aux id "
-                                + "MAIN for switch {} on controller with URI {}.",
-                                  this, uri);
-                    }
-                }
-            }
-        }
-       return false;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java b/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..1fb321baddd352b137c78e68b99fab388766fd27
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java
@@ -0,0 +1,1579 @@
+/**
+*    Copyright 2012, 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.core;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
+import net.floodlightcontroller.core.internal.Controller;
+import net.floodlightcontroller.core.internal.OFFeaturesReplyFuture;
+import net.floodlightcontroller.core.internal.OFStatisticsFuture;
+import net.floodlightcontroller.core.util.AppCookie;
+import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
+import net.floodlightcontroller.debugcounter.IDebugCounter;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
+import net.floodlightcontroller.debugcounter.NullDebugCounter;
+import net.floodlightcontroller.devicemanager.SwitchPort;
+import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.routing.ForwardingBase;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.util.LinkedHashSetWrapper;
+import net.floodlightcontroller.util.MACAddress;
+import net.floodlightcontroller.util.OrderedCollection;
+import net.floodlightcontroller.util.TimedCache;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+
+import org.jboss.netty.channel.Channel;
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPortStatus;
+import org.openflow.protocol.OFPortStatus.OFPortReason;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFStatisticsReply;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.protocol.statistics.OFTableStatistics;
+import org.openflow.util.HexString;
+import org.openflow.util.U16;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is the internal representation of an openflow switch.
+ */
+public abstract class OFSwitchBase implements IOFSwitch {
+    // TODO: should we really do logging in the class or should we throw
+    // exception that can then be handled by callers?
+    protected static final Logger log = LoggerFactory.getLogger(OFSwitchBase.class);
+
+    protected ConcurrentMap<Object, Object> attributes;
+    protected IFloodlightProviderService floodlightProvider;
+    protected IThreadPoolService threadPool;
+    protected IDebugCounterService debugCounters;
+    // FIXME: Don't use java.util.Date
+    protected volatile Date connectedSince;
+
+    /* Switch features from initial featuresReply */
+    protected int capabilities;
+    protected int buffers;
+    protected int actions;
+    protected byte tables;
+    protected long datapathId;
+    protected String stringId;
+
+    protected short accessFlowPriority;
+    protected short coreFlowPriority;
+
+    private boolean startDriverHandshakeCalled = false;
+    protected Channel channel;
+
+    /**
+     * Members hidden from subclasses
+     */
+    private final AtomicInteger transactionIdSource;
+    private final Map<Integer,OFStatisticsFuture> statsFutureMap;
+    private final Map<Integer, IOFMessageListener> iofMsgListenersMap;
+    private final Map<Integer,OFFeaturesReplyFuture> featuresFutureMap;
+    private volatile boolean connected;
+    private volatile Role role;
+    private final TimedCache<Long> timedCache;
+    private final ConcurrentMap<Short, AtomicLong> portBroadcastCacheHitMap;
+
+    private final PortManager portManager;
+
+    // Private members for throttling
+    private boolean writeThrottleEnabled = false;
+    protected boolean packetInThrottleEnabled = false; // used by test
+    private int packetInRateThresholdHigh =
+            Integer.parseInt(System.getProperty("input_threshold", "1000"));
+    private int packetInRateThresholdLow = 1;
+    private int packetInRatePerMacThreshold = 50;
+    private int packetInRatePerPortThreshold = 100;
+    private long messageCount = 0;
+    private long messageCountUniqueOFMatch = 0;
+    private long lastMessageTime;
+    private int currentRate = 0;
+    private TimedCache<OFMatch> ofMatchCache;
+    private TimedCache<Long> macCache;
+    private TimedCache<Long> macBlockedCache;
+    private TimedCache<Short> portCache;
+    private TimedCache<Short> portBlockedCache;
+    private boolean flowTableFull = false;
+
+    protected OFDescriptionStatistics description;
+
+    private boolean debugCountersRegistered;
+    @SuppressWarnings("unused")
+    private IDebugCounter ctrSwitch, ctrSwitchPktin, ctrSwitchWrite;
+    private IDebugCounter ctrSwitchPktinDrops, ctrSwitchWriteDrops;
+
+    private static final String PACKAGE = OFSwitchBase.class.getPackage().getName();
+
+
+    protected final static ThreadLocal<Map<IOFSwitch,List<OFMessage>>> local_msg_buffer =
+            new ThreadLocal<Map<IOFSwitch,List<OFMessage>>>() {
+        @Override
+        protected Map<IOFSwitch,List<OFMessage>> initialValue() {
+            return new HashMap<IOFSwitch,List<OFMessage>>();
+        }
+    };
+
+    public static final int OFSWITCH_APP_ID = 5;
+    static {
+        AppCookie.registerApp(OFSwitchBase.OFSWITCH_APP_ID, "switch");
+    }
+
+    public OFSwitchBase() {
+        this.stringId = null;
+        this.attributes = new ConcurrentHashMap<Object, Object>();
+        this.connectedSince = null;
+        this.transactionIdSource = new AtomicInteger();
+        this.connected = false;
+        this.statsFutureMap = new ConcurrentHashMap<Integer,OFStatisticsFuture>();
+        this.featuresFutureMap = new ConcurrentHashMap<Integer,OFFeaturesReplyFuture>();
+        this.iofMsgListenersMap = new ConcurrentHashMap<Integer,IOFMessageListener>();
+        this.role = null;
+        this.timedCache = new TimedCache<Long>(100, 5*1000 );  // 5 seconds interval
+        this.portBroadcastCacheHitMap = new ConcurrentHashMap<Short, AtomicLong>();
+        this.description = new OFDescriptionStatistics();
+        this.lastMessageTime = System.currentTimeMillis();
+
+        this.portManager = new PortManager();
+
+        // Defaults properties for an ideal switch
+        this.setAttribute(PROP_FASTWILDCARDS, OFMatch.OFPFW_ALL);
+        this.setAttribute(PROP_SUPPORTS_OFPP_FLOOD, Boolean.valueOf(true));
+        this.setAttribute(PROP_SUPPORTS_OFPP_TABLE, Boolean.valueOf(true));
+        if (packetInRateThresholdHigh == 0) {
+            packetInRateThresholdHigh = Integer.MAX_VALUE;
+        } else {
+            packetInRateThresholdLow = packetInRateThresholdHigh / 2;
+        }
+    }
+
+
+
+    /**
+     * Manages the ports of this switch.
+     *
+     * Provides methods to query and update the stored ports. The class ensures
+     * that every port name and port number is unique. When updating ports
+     * the class checks if port number <-> port name mappings have change due
+     * to the update. If a new port P has number and port that are inconsistent
+     * with the previous mapping(s) the class will delete all previous ports
+     * with name or number of the new port and then add the new port.
+     *
+     * Port names are stored as-is but they are compared case-insensitive
+     *
+     * The methods that change the stored ports return a list of
+     * PortChangeEvents that represent the changes that have been applied
+     * to the port list so that IOFSwitchListeners can be notified about the
+     * changes.
+     *
+     * Implementation notes:
+     * - We keep several different representations of the ports to allow for
+     *   fast lookups
+     * - Ports are stored in unchangeable lists. When a port is modified new
+     *   data structures are allocated.
+     * - We use a read-write-lock for synchronization, so multiple readers are
+     *   allowed.
+     */
+    protected class PortManager {
+        private final ReentrantReadWriteLock lock;
+        private List<ImmutablePort> portList;
+        private List<ImmutablePort> enabledPortList;
+        private List<Short> enabledPortNumbers;
+        private Map<Short,ImmutablePort> portsByNumber;
+        private Map<String,ImmutablePort> portsByName;
+
+
+
+
+        public PortManager() {
+            this.lock = new ReentrantReadWriteLock();
+            this.portList = Collections.emptyList();
+            this.enabledPortList = Collections.emptyList();
+            this.enabledPortNumbers = Collections.emptyList();
+            this.portsByName = Collections.emptyMap();
+            this.portsByNumber = Collections.emptyMap();
+        }
+
+        /**
+         * Set the internal data structure storing this switch's port
+         * to the ports specified by newPortsByNumber
+         *
+         * CALLER MUST HOLD WRITELOCK
+         *
+         * @param newPortsByNumber
+         * @throws IllegaalStateException if called without holding the
+         * writelock
+         */
+        private void updatePortsWithNewPortsByNumber(
+                Map<Short,ImmutablePort> newPortsByNumber) {
+            if (!lock.writeLock().isHeldByCurrentThread()) {
+                throw new IllegalStateException("Method called without " +
+                                                "holding writeLock");
+            }
+            Map<String,ImmutablePort> newPortsByName =
+                    new HashMap<String, ImmutablePort>();
+            List<ImmutablePort> newPortList =
+                    new ArrayList<ImmutablePort>();
+            List<ImmutablePort> newEnabledPortList =
+                    new ArrayList<ImmutablePort>();
+            List<Short> newEnabledPortNumbers = new ArrayList<Short>();
+
+            for(ImmutablePort p: newPortsByNumber.values()) {
+                newPortList.add(p);
+                newPortsByName.put(p.getName().toLowerCase(), p);
+                if (p.isEnabled()) {
+                    newEnabledPortList.add(p);
+                    newEnabledPortNumbers.add(p.getPortNumber());
+                }
+            }
+            portsByName = Collections.unmodifiableMap(newPortsByName);
+            portsByNumber =
+                    Collections.unmodifiableMap(newPortsByNumber);
+            enabledPortList =
+                    Collections.unmodifiableList(newEnabledPortList);
+            enabledPortNumbers =
+                    Collections.unmodifiableList(newEnabledPortNumbers);
+            portList = Collections.unmodifiableList(newPortList);
+        }
+
+        /**
+         * Handle a OFPortStatus delete message for the given port.
+         * Updates the internal port maps/lists of this switch and returns
+         * the PortChangeEvents caused by the delete. If the given port
+         * exists as it, it will be deleted. If the name<->number for the
+         * given port is inconsistent with the ports stored by this switch
+         * the method will delete all ports with the number or name of the
+         * given port.
+         *
+         * This method will increment error/warn counters and log
+         *
+         * @param delPort the port from the port status message that should
+         * be deleted.
+         * @return ordered collection of port changes applied to this switch
+         */
+        private OrderedCollection<PortChangeEvent>
+                handlePortStatusDelete(ImmutablePort delPort) {
+            lock.writeLock().lock();
+            OrderedCollection<PortChangeEvent> events =
+                    new LinkedHashSetWrapper<PortChangeEvent>();
+            try {
+                Map<Short,ImmutablePort> newPortByNumber =
+                        new HashMap<Short, ImmutablePort>(portsByNumber);
+                ImmutablePort prevPort =
+                        portsByNumber.get(delPort.getPortNumber());
+                if (prevPort == null) {
+                    // so such port. Do we have a port with the name?
+                    prevPort = portsByName.get(delPort.getName());
+                    if (prevPort != null) {
+                        newPortByNumber.remove(prevPort.getPortNumber());
+                        events.add(new PortChangeEvent(prevPort,
+                                                       PortChangeType.DELETE));
+                    }
+                } else if (prevPort.getName().equals(delPort.getName())) {
+                    // port exists with consistent name-number mapping
+                    newPortByNumber.remove(delPort.getPortNumber());
+                    events.add(new PortChangeEvent(delPort,
+                                                   PortChangeType.DELETE));
+                } else {
+                    // port with same number exists but its name differs. This
+                    // is weird. The best we can do is to delete the existing
+                    // port(s) that have delPort's name and number.
+                    newPortByNumber.remove(delPort.getPortNumber());
+                    events.add(new PortChangeEvent(prevPort,
+                                                   PortChangeType.DELETE));
+                    // is there another port that has delPort's name?
+                    prevPort = portsByName.get(delPort.getName().toLowerCase());
+                    if (prevPort != null) {
+                        newPortByNumber.remove(prevPort.getPortNumber());
+                        events.add(new PortChangeEvent(prevPort,
+                                                       PortChangeType.DELETE));
+                    }
+                }
+                updatePortsWithNewPortsByNumber(newPortByNumber);
+                return events;
+            } finally {
+                lock.writeLock().unlock();
+            }
+        }
+
+        /**
+         * Handle a OFPortStatus message, update the internal data structures
+         * that store ports and return the list of OFChangeEvents.
+         *
+         * This method will increment error/warn counters and log
+         *
+         * @param ps
+         * @return
+         */
+        public OrderedCollection<PortChangeEvent> handlePortStatusMessage(OFPortStatus ps) {
+            if (ps == null) {
+                throw new NullPointerException("OFPortStatus message must " +
+                                               "not be null");
+            }
+            lock.writeLock().lock();
+            try {
+                ImmutablePort port =
+                        ImmutablePort.fromOFPhysicalPort(ps.getDesc());
+                OFPortReason reason = OFPortReason.fromReasonCode(ps.getReason());
+                if (reason == null) {
+                    throw new IllegalArgumentException("Unknown PortStatus " +
+                            "reason code " + ps.getReason());
+                }
+
+                if (log.isDebugEnabled()) {
+                    log.debug("Handling OFPortStatus: {} for {}",
+                              reason, port.toBriefString());
+                }
+
+                if (reason == OFPortReason.OFPPR_DELETE)
+                        return handlePortStatusDelete(port);
+
+                // We handle ADD and MODIFY the same way. Since OpenFlow
+                // doesn't specify what uniquely identifies a port the
+                // notion of ADD vs. MODIFY can also be hazy. So we just
+                // compare the new port to the existing ones.
+                Map<Short,ImmutablePort> newPortByNumber =
+                    new HashMap<Short, ImmutablePort>(portsByNumber);
+                OrderedCollection<PortChangeEvent> events = getSinglePortChanges(port);
+                for (PortChangeEvent e: events) {
+                    switch(e.type) {
+                        case DELETE:
+                            newPortByNumber.remove(e.port.getPortNumber());
+                            break;
+                        case ADD:
+                            if (reason != OFPortReason.OFPPR_ADD) {
+                                // weird case
+                            }
+                            // fall through
+                        case DOWN:
+                        case OTHER_UPDATE:
+                        case UP:
+                            // update or add the port in the map
+                            newPortByNumber.put(e.port.getPortNumber(), e.port);
+                            break;
+                    }
+                }
+                updatePortsWithNewPortsByNumber(newPortByNumber);
+                return events;
+            } finally {
+                lock.writeLock().unlock();
+            }
+
+        }
+
+        /**
+         * Given a new or modified port newPort, returns the list of
+         * PortChangeEvents to "transform" the current ports stored by
+         * this switch to include / represent the new port. The ports stored
+         * by this switch are <b>NOT</b> updated.
+         *
+         * This method acquires the readlock and is thread-safe by itself.
+         * Most callers will need to acquire the write lock before calling
+         * this method though (if the caller wants to update the ports stored
+         * by this switch)
+         *
+         * @param newPort the new or modified port.
+         * @return the list of changes
+         */
+        public OrderedCollection<PortChangeEvent>
+                getSinglePortChanges(ImmutablePort newPort) {
+            lock.readLock().lock();
+            try {
+                OrderedCollection<PortChangeEvent> events =
+                        new LinkedHashSetWrapper<PortChangeEvent>();
+                // Check if we have a port by the same number in our
+                // old map.
+                ImmutablePort prevPort =
+                        portsByNumber.get(newPort.getPortNumber());
+                if (newPort.equals(prevPort)) {
+                    // nothing has changed
+                    return events;
+                }
+
+                if (prevPort != null &&
+                        prevPort.getName().equals(newPort.getName())) {
+                    // A simple modify of a exiting port
+                    // A previous port with this number exists and it's name
+                    // also matches the new port. Find the differences
+                    if (prevPort.isEnabled() && !newPort.isEnabled()) {
+                        events.add(new PortChangeEvent(newPort,
+                                                       PortChangeType.DOWN));
+                    } else if (!prevPort.isEnabled() && newPort.isEnabled()) {
+                        events.add(new PortChangeEvent(newPort,
+                                                       PortChangeType.UP));
+                    } else {
+                        events.add(new PortChangeEvent(newPort,
+                                   PortChangeType.OTHER_UPDATE));
+                    }
+                    return events;
+                }
+
+                if (prevPort != null) {
+                    // There exists a previous port with the same port
+                    // number but the port name is different (otherwise we would
+                    // never have gotten here)
+                    // Remove the port. Name-number mapping(s) have changed
+                    events.add(new PortChangeEvent(prevPort,
+                                                   PortChangeType.DELETE));
+                }
+
+                // We now need to check if there exists a previous port sharing
+                // the same name as the new/updated port.
+                prevPort = portsByName.get(newPort.getName().toLowerCase());
+                if (prevPort != null) {
+                    // There exists a previous port with the same port
+                    // name but the port number is different (otherwise we
+                    // never have gotten here).
+                    // Remove the port. Name-number mapping(s) have changed
+                    events.add(new PortChangeEvent(prevPort,
+                                                   PortChangeType.DELETE));
+                }
+
+                // We always need to add the new port. Either no previous port
+                // existed or we just deleted previous ports with inconsistent
+                // name-number mappings
+                events.add(new PortChangeEvent(newPort, PortChangeType.ADD));
+                return events;
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        /**
+         * Compare the current ports of this switch to the newPorts list and
+         * return the changes that would be applied to transfort the current
+         * ports to the new ports. No internal data structures are updated
+         * see {@link #compareAndUpdatePorts(List, boolean)}
+         *
+         * @param newPorts the list of new ports
+         * @return The list of differences between the current ports and
+         * newPortList
+         */
+        public OrderedCollection<PortChangeEvent>
+                comparePorts(Collection<ImmutablePort> newPorts) {
+            return compareAndUpdatePorts(newPorts, false);
+        }
+
+        /**
+         * Compare the current ports of this switch to the newPorts list and
+         * return the changes that would be applied to transform the current
+         * ports to the new ports. No internal data structures are updated
+         * see {@link #compareAndUpdatePorts(List, boolean)}
+         *
+         * @param newPorts the list of new ports
+         * @return The list of differences between the current ports and
+         * newPortList
+         */
+        public OrderedCollection<PortChangeEvent>
+                updatePorts(Collection<ImmutablePort> newPorts) {
+            return compareAndUpdatePorts(newPorts, true);
+        }
+
+        /**
+         * Compare the current ports stored in this switch instance with the
+         * new port list given and return the differences in the form of
+         * PortChangeEvents. If the doUpdate flag is true, newPortList will
+         * replace the current list of this switch (and update the port maps)
+         *
+         * Implementation note:
+         * Since this method can optionally modify the current ports and
+         * since it's not possible to upgrade a read-lock to a write-lock
+         * we need to hold the write-lock for the entire operation. If this
+         * becomes a problem and if compares() are common we can consider
+         * splitting in two methods but this requires lots of code duplication
+         *
+         * @param newPorts the list of new ports.
+         * @param doUpdate If true the newPortList will replace the current
+         * port list for this switch. If false this switch will not be changed.
+         * @return The list of differences between the current ports and
+         * newPorts
+         * @throws NullPointerException if newPortsList is null
+         * @throws IllegalArgumentException if either port names or port numbers
+         * are duplicated in the newPortsList.
+         */
+        private OrderedCollection<PortChangeEvent> compareAndUpdatePorts(
+                Collection<ImmutablePort> newPorts,
+                boolean doUpdate) {
+            if (newPorts == null) {
+                throw new NullPointerException("newPortsList must not be null");
+            }
+            lock.writeLock().lock();
+            try {
+                OrderedCollection<PortChangeEvent> events =
+                        new LinkedHashSetWrapper<PortChangeEvent>();
+
+                Map<Short,ImmutablePort> newPortsByNumber =
+                        new HashMap<Short, ImmutablePort>();
+                Map<String,ImmutablePort> newPortsByName =
+                        new HashMap<String, ImmutablePort>();
+                List<ImmutablePort> newEnabledPortList =
+                        new ArrayList<ImmutablePort>();
+                List<Short> newEnabledPortNumbers =
+                        new ArrayList<Short>();
+                List<ImmutablePort> newPortsList =
+                        new ArrayList<ImmutablePort>(newPorts);
+
+                for (ImmutablePort p: newPortsList) {
+                    if (p == null) {
+                        throw new NullPointerException("portList must not " +
+                                "contain null values");
+                    }
+
+                    // Add the port to the new maps and lists and check
+                    // that every port is unique
+                    ImmutablePort duplicatePort;
+                    duplicatePort = newPortsByNumber.put(p.getPortNumber(), p);
+                    if (duplicatePort != null) {
+                        String msg = String.format("Cannot have two ports " +
+                                "with the same number: %s <-> %s",
+                                p.toBriefString(),
+                                duplicatePort.toBriefString());
+                        throw new IllegalArgumentException(msg);
+                    }
+                    duplicatePort =
+                            newPortsByName.put(p.getName().toLowerCase(), p);
+                    if (duplicatePort != null) {
+                        String msg = String.format("Cannot have two ports " +
+                                "with the same name: %s <-> %s",
+                                p.toBriefString(),
+                                duplicatePort.toBriefString());
+                        throw new IllegalArgumentException(msg);
+                    }
+                    if (p.isEnabled()) {
+                        newEnabledPortList.add(p);
+                        newEnabledPortNumbers.add(p.getPortNumber());
+                    }
+
+                    // get changes
+                    events.addAll(getSinglePortChanges(p));
+                }
+                // find deleted ports
+                // We need to do this after looping through all the new ports
+                // to we can handle changed name<->number mappings correctly
+                // We could pull it into the loop of we address this but
+                // it's probably not worth it
+                for (ImmutablePort oldPort: this.portList) {
+                    if (!newPortsByNumber.containsKey(oldPort.getPortNumber())) {
+                        PortChangeEvent ev =
+                                new PortChangeEvent(oldPort,
+                                                    PortChangeType.DELETE);
+                        events.add(ev);
+                    }
+                }
+
+
+                if (doUpdate) {
+                    portsByName = Collections.unmodifiableMap(newPortsByName);
+                    portsByNumber =
+                            Collections.unmodifiableMap(newPortsByNumber);
+                    enabledPortList =
+                            Collections.unmodifiableList(newEnabledPortList);
+                    enabledPortNumbers =
+                            Collections.unmodifiableList(newEnabledPortNumbers);
+                    portList = Collections.unmodifiableList(newPortsList);
+                }
+                return events;
+            } finally {
+                lock.writeLock().unlock();
+            }
+        }
+
+        public ImmutablePort getPort(String name) {
+            if (name == null) {
+                throw new NullPointerException("Port name must not be null");
+            }
+            lock.readLock().lock();
+            try {
+                return portsByName.get(name.toLowerCase());
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        public ImmutablePort getPort(Short portNumber) {
+            lock.readLock().lock();
+            try {
+                return portsByNumber.get(portNumber);
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        public List<ImmutablePort> getPorts() {
+            lock.readLock().lock();
+            try {
+                return portList;
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        public List<ImmutablePort> getEnabledPorts() {
+            lock.readLock().lock();
+            try {
+                return enabledPortList;
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        public List<Short> getEnabledPortNumbers() {
+            lock.readLock().lock();
+            try {
+                return enabledPortNumbers;
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+    }
+
+
+    @Override
+    public boolean attributeEquals(String name, Object other) {
+        Object attr = this.attributes.get(name);
+        if (attr == null)
+            return false;
+        return attr.equals(other);
+    }
+
+
+    @Override
+    public Object getAttribute(String name) {
+        // returns null if key doesn't exist
+        return this.attributes.get(name);
+    }
+
+    @Override
+    public void setAttribute(String name, Object value) {
+        this.attributes.put(name, value);
+        return;
+    }
+
+    @Override
+    public Object removeAttribute(String name) {
+        return this.attributes.remove(name);
+    }
+
+    @Override
+    public boolean hasAttribute(String name) {
+        return this.attributes.containsKey(name);
+    }
+
+    @Override
+    @JsonIgnore
+    public void setChannel(Channel channel) {
+        this.channel = channel;
+    }
+
+    // For driver subclass to set throttling
+    protected void enableWriteThrottle(boolean enable) {
+        this.writeThrottleEnabled = enable;
+    }
+
+    @Override
+    public boolean isWriteThrottleEnabled() {
+        return this.writeThrottleEnabled;
+    }
+
+    @Override
+    @LogMessageDocs({
+        @LogMessageDoc(level="WARN",
+                message="Drop throttled OF message to switch {switch}",
+                explanation="The controller is sending more messages" +
+                "than the switch can handle. Some messages are dropped" +
+                "to prevent switch outage",
+                recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+    })
+    public void writeThrottled(OFMessage m, FloodlightContext bc)
+            throws IOException {
+        if (channel == null || !isConnected())
+            return;
+        /**
+         * By default, channel uses an unbounded send queue. Enable throttling
+         * prevents the queue from growing big.
+         *
+         * channel.isWritable() returns true when queue length is less than
+         * high water mark (64 kbytes). Once exceeded, isWritable() becomes
+         * false after queue length drops below low water mark (32 kbytes).
+         */
+        if (!writeThrottleEnabled || channel.isWritable()) {
+            write(m, bc);
+        } else {
+            // Let logback duplicate filtering take care of excessive logs
+            ctrSwitchWriteDrops.updateCounterNoFlush();
+            log.warn("Drop throttled OF message to switch {}", this);
+        }
+    }
+
+    @Override
+    public void writeThrottled(List<OFMessage> msglist, FloodlightContext bc)
+            throws IOException {
+        if (!writeThrottleEnabled || channel.isWritable()) {
+            write(msglist, bc);
+        } else {
+            // Let logback duplicate filtering take care of excessive logs
+            ctrSwitchWriteDrops.updateCounterNoFlush(msglist.size());
+            log.warn("Drop throttled OF messages to switch {}", this);
+        }
+    }
+
+    @Override
+    public void write(OFMessage m, FloodlightContext bc) {
+        if (channel == null || !isConnected())
+            return;
+            //throws IOException {
+        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        List<OFMessage> msg_buffer = msg_buffer_map.get(this);
+        if (msg_buffer == null) {
+            msg_buffer = new ArrayList<OFMessage>();
+            msg_buffer_map.put(this, msg_buffer);
+        }
+
+        this.floodlightProvider.handleOutgoingMessage(this, m, bc);
+        msg_buffer.add(m);
+
+        if ((msg_buffer.size() >= Controller.BATCH_MAX_SIZE) ||
+            ((m.getType() != OFType.PACKET_OUT) && (m.getType() != OFType.FLOW_MOD))) {
+            this.write(msg_buffer);
+            msg_buffer.clear();
+        }
+    }
+    @Override
+    @LogMessageDoc(level="WARN",
+                   message="Sending OF message that modifies switch " +
+                           "state while in the slave role: {switch}",
+                   explanation="An application has sent a message to a switch " +
+                           "that is not valid when the switch is in a slave role",
+                   recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+    public void write(List<OFMessage> msglist,
+                      FloodlightContext bc) {
+        if (channel == null || !isConnected())
+            return;
+        for (OFMessage m : msglist) {
+            if (role == Role.SLAVE) {
+                switch (m.getType()) {
+                    case PACKET_OUT:
+                    case FLOW_MOD:
+                    case PORT_MOD:
+                        log.warn("Sending OF message that modifies switch " +
+                                 "state while in the slave role: {}",
+                                 m.getType().name());
+                        break;
+                    default:
+                        break;
+                }
+            }
+            this.floodlightProvider.handleOutgoingMessage(this, m, bc);
+        }
+        this.write(msglist);
+    }
+
+    /**
+     * Not callable by writers, but allow IOFSwitch implementation to override
+     * @param msglist
+     * @throws IOException
+     */
+    protected void write(List<OFMessage> msglist) {
+        if (channel == null || !isConnected())
+            return;
+        this.channel.write(msglist);
+    }
+
+    @Override
+    public void disconnectOutputStream() {
+        if (channel == null)
+            return;
+        channel.close();
+    }
+
+    @Override
+    @JsonIgnore
+    public void setFeaturesReply(OFFeaturesReply featuresReply) {
+        if (stringId == null) {
+            /* ports are updated via port status message, so we
+             * only fill in ports on initial connection.
+             */
+            List<ImmutablePort> immutablePorts = ImmutablePort
+                    .immutablePortListOf(featuresReply.getPorts());
+            portManager.updatePorts(immutablePorts);
+        }
+        this.datapathId = featuresReply.getDatapathId();
+        this.stringId = HexString.toHexString(featuresReply.getDatapathId());
+        this.capabilities = featuresReply.getCapabilities();
+        this.buffers = featuresReply.getBuffers();
+        this.actions = featuresReply.getActions();
+        this.tables = featuresReply.getTables();
+}
+
+    @Override
+    @JsonIgnore
+    public Collection<ImmutablePort> getEnabledPorts() {
+        return portManager.getEnabledPorts();
+    }
+
+    @Override
+    @JsonIgnore
+    public Collection<Short> getEnabledPortNumbers() {
+        return portManager.getEnabledPortNumbers();
+    }
+
+    @Override
+    public ImmutablePort getPort(short portNumber) {
+        return portManager.getPort(portNumber);
+    }
+
+    @Override
+    public ImmutablePort getPort(String portName) {
+        return portManager.getPort(portName);
+    }
+
+    @Override
+    @JsonIgnore
+    public OrderedCollection<PortChangeEvent>
+            processOFPortStatus(OFPortStatus ps) {
+        return portManager.handlePortStatusMessage(ps);
+    }
+
+    @Override
+    @JsonProperty("ports")
+    public Collection<ImmutablePort> getPorts() {
+        return portManager.getPorts();
+    }
+
+    @Override
+    public OrderedCollection<PortChangeEvent>
+            comparePorts(Collection<ImmutablePort> ports) {
+        return portManager.comparePorts(ports);
+    }
+
+    @Override
+    @JsonIgnore
+    public OrderedCollection<PortChangeEvent>
+            setPorts(Collection<ImmutablePort> ports) {
+        return portManager.updatePorts(ports);
+    }
+
+    @Override
+    public boolean portEnabled(short portNumber) {
+        ImmutablePort p = portManager.getPort(portNumber);
+        if (p == null) return false;
+        return p.isEnabled();
+    }
+
+    @Override
+    public boolean portEnabled(String portName) {
+        ImmutablePort p = portManager.getPort(portName);
+        if (p == null) return false;
+        return p.isEnabled();
+    }
+
+    @Override
+    @JsonSerialize(using=DPIDSerializer.class)
+    @JsonProperty("dpid")
+    public long getId() {
+        if (this.stringId == null)
+            throw new RuntimeException("Features reply has not yet been set");
+        return this.datapathId;
+    }
+
+    @JsonIgnore
+    @Override
+    public String getStringId() {
+        return stringId;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        String channelString =
+                (channel != null) ? channel.getRemoteAddress().toString() :
+                                    "?";
+        return "OFSwitchBase [" + channelString + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
+    }
+
+    @Override
+    public ConcurrentMap<Object, Object> getAttributes() {
+        return this.attributes;
+    }
+
+    @Override
+    public Date getConnectedSince() {
+        return connectedSince;
+    }
+
+    @JsonIgnore
+    @Override
+    public int getNextTransactionId() {
+        return this.transactionIdSource.incrementAndGet();
+    }
+
+    @Override
+    public void sendStatsQuery(OFStatisticsRequest request, int xid,
+                                IOFMessageListener caller) throws IOException {
+        request.setXid(xid);
+        this.iofMsgListenersMap.put(xid, caller);
+        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        msglist.add(request);
+        this.write(msglist);
+        return;
+    }
+
+    @Override
+    public Future<List<OFStatistics>> queryStatistics(OFStatisticsRequest request) throws IOException {
+        request.setXid(getNextTransactionId());
+        OFStatisticsFuture future = new OFStatisticsFuture(threadPool, this, request.getXid());
+        this.statsFutureMap.put(request.getXid(), future);
+        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        msglist.add(request);
+        this.write(msglist);
+        return future;
+    }
+
+    @Override
+    public void deliverStatisticsReply(OFStatisticsReply reply) {
+        checkForTableStats(reply);
+        OFStatisticsFuture future = this.statsFutureMap.get(reply.getXid());
+        if (future != null) {
+            future.deliverFuture(this, reply);
+            // The future will ultimately unregister itself and call
+            // cancelStatisticsReply
+            return;
+        }
+        /* Transaction id was not found in statsFutureMap.check the other map */
+        IOFMessageListener caller = this.iofMsgListenersMap.get(reply.getXid());
+        if (caller != null) {
+            caller.receive(this, reply, null);
+        }
+    }
+
+    @LogMessageDocs({
+        @LogMessageDoc(level="INFO",
+            message="Switch {switch} flow table is full",
+            explanation="The switch flow table at least 98% full, " +
+                    "this requires attention if using reactive flow setup"),
+        @LogMessageDoc(level="INFO",
+            message="Switch {switch} flow table capacity back to normal",
+            explanation="The switch flow table is less than 90% full")
+    })
+    private void checkForTableStats(OFStatisticsReply statReply) {
+        if (statReply.getStatisticType() != OFStatisticsType.TABLE) {
+            return;
+        }
+        List<? extends OFStatistics> stats = statReply.getStatistics();
+        // Assume a single table only
+        OFStatistics stat = stats.get(0);
+        if (stat instanceof OFTableStatistics) {
+            OFTableStatistics tableStat = (OFTableStatistics) stat;
+            int activeCount = tableStat.getActiveCount();
+            int maxEntry = tableStat.getMaximumEntries();
+            log.debug("Switch {} active entries {} max entries {}",
+                    new Object[] { this.stringId, activeCount, maxEntry});
+            int percentFull = activeCount * 100 / maxEntry;
+            if (flowTableFull && percentFull < 90) {
+                log.info("Switch {} flow table capacity is back to normal",
+                        toString());
+                floodlightProvider.addSwitchEvent(this.datapathId,
+                        "SWITCH_FLOW_TABLE_NORMAL < 90% full", false);
+            } else if (percentFull >= 98) {
+                log.info("Switch {} flow table is almost full", toString());
+                floodlightProvider.addSwitchEvent(this.datapathId,
+                        "SWITCH_FLOW_TABLE_ALMOST_FULL >= 98% full", false);
+            }
+        }
+    }
+
+
+    @Override
+    public void cancelStatisticsReply(int transactionId) {
+        if (null ==  this.statsFutureMap.remove(transactionId)) {
+            this.iofMsgListenersMap.remove(transactionId);
+        }
+    }
+
+    @Override
+    public void cancelAllStatisticsReplies() {
+        /* we don't need to be synchronized here. Even if another thread
+         * modifies the map while we're cleaning up the future will eventuall
+         * timeout */
+        for (OFStatisticsFuture f : statsFutureMap.values()) {
+            f.cancel(true);
+        }
+        statsFutureMap.clear();
+        iofMsgListenersMap.clear();
+    }
+
+
+    /**
+     * @param floodlightProvider the floodlightProvider to set
+     */
+    @JsonIgnore
+    public void setFloodlightProvider(
+            IFloodlightProviderService floodlightProvider) {
+        this.floodlightProvider = floodlightProvider;
+    }
+
+    @Override
+    @JsonIgnore
+    public void setThreadPoolService(IThreadPoolService tp) {
+        this.threadPool = tp;
+    }
+
+    @Override
+    @JsonIgnore
+    public void setDebugCounterService(IDebugCounterService debugCounters)
+            throws CounterException {
+        this.debugCounters = debugCounters;
+        registerOverloadCounters();
+    }
+
+    @JsonIgnore
+    @Override
+    public boolean isConnected() {
+        // no lock needed since we use volatile
+        return connected;
+    }
+
+    @JsonIgnore
+    @Override
+    public boolean isActive() {
+        // no lock needed since we use volatile
+        return isConnected() && this.role == Role.MASTER;
+    }
+
+    @Override
+    @JsonIgnore
+    public void setConnected(boolean connected) {
+        // No lock needed since we use volatile
+        if (connected && this.connectedSince == null)
+            this.connectedSince = new Date();
+        else if (!connected)
+            this.connectedSince = null;
+        this.connected = connected;
+    }
+
+    @Override
+    public Role getHARole() {
+        return role;
+    }
+
+    @JsonIgnore
+    @Override
+    public void setHARole(Role role) {
+        this.role = role;
+    }
+
+    @LogMessageDoc(level="INFO",
+            message="Switch {switch} flow cleared",
+            explanation="The switch flow table has been cleared, " +
+                    "this normally happens on switch connection")
+    @Override
+    public void clearAllFlowMods() {
+        if (channel == null || !isConnected())
+            return;
+        // Delete all pre-existing flows
+        log.info("Clearing all flows on switch {}", this);
+        OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
+        OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory()
+            .getMessage(OFType.FLOW_MOD))
+                .setMatch(match)
+            .setCommand(OFFlowMod.OFPFC_DELETE)
+            .setOutPort(OFPort.OFPP_NONE)
+            .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
+        fm.setXid(getNextTransactionId());
+        OFMessage barrierMsg = floodlightProvider.getOFMessageFactory().getMessage(
+                OFType.BARRIER_REQUEST);
+        barrierMsg.setXid(getNextTransactionId());
+        List<OFMessage> msglist = new ArrayList<OFMessage>(2);
+        msglist.add(fm);
+        msglist.add(barrierMsg);
+        channel.write(msglist);
+    }
+
+    @Override
+    public boolean updateBroadcastCache(Long entry, Short port) {
+        if (timedCache.update(entry)) {
+            AtomicLong count = portBroadcastCacheHitMap.get(port);
+            if(count == null) {
+                AtomicLong newCount = new AtomicLong(0);
+                AtomicLong retrieved;
+                if((retrieved = portBroadcastCacheHitMap.putIfAbsent(port, newCount)) == null ) {
+                    count = newCount;
+                } else {
+                    count = retrieved;
+                }
+            }
+            count.incrementAndGet();
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    @JsonIgnore
+    public Map<Short, Long> getPortBroadcastHits() {
+        Map<Short, Long> res = new HashMap<Short, Long>();
+        for (Map.Entry<Short, AtomicLong> entry : portBroadcastCacheHitMap.entrySet()) {
+            res.put(entry.getKey(), entry.getValue().get());
+        }
+        return res;
+    }
+
+    @Override
+    public void flush() {
+        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        List<OFMessage> msglist = msg_buffer_map.get(this);
+        if ((msglist != null) && (msglist.size() > 0)) {
+            /* ============================ BIG CAVEAT ===============================
+             * This code currently works, but relies on undocumented behavior of
+             * netty.
+             *
+             * The method org.jboss.netty.channel.Channel.write(Object)
+             * (invoked from this.write(List<OFMessage> msg) is currently
+             * documented to be <emph>asynchronous</emph>. If the method /were/ truely
+             * asynchronous, this would break our code (because we are clearing the
+             * msglist right after calling write.
+             *
+             * For now, Netty actually invokes the conversion pipeline before doing
+             * anything asynchronous, so we are safe. But we should probably change
+             * that behavior.
+             */
+            this.write(msglist);
+            msglist.clear();
+        }
+    }
+
+    public static void flush_all() {
+        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        for (IOFSwitch sw : msg_buffer_map.keySet()) {
+            sw.flush();
+        }
+    }
+
+
+    /**
+     * Get the IP Address for the switch
+     * @return the inet address
+     */
+    @Override
+    @JsonSerialize(using=ToStringSerializer.class)
+    public SocketAddress getInetAddress() {
+        if (channel == null)
+            return null;
+        return channel.getRemoteAddress();
+    }
+
+    @Override
+    public Future<OFFeaturesReply> querySwitchFeaturesReply()
+            throws IOException {
+        OFMessage request =
+                floodlightProvider.getOFMessageFactory().
+                    getMessage(OFType.FEATURES_REQUEST);
+        request.setXid(getNextTransactionId());
+        OFFeaturesReplyFuture future =
+                new OFFeaturesReplyFuture(threadPool, this, request.getXid());
+        this.featuresFutureMap.put(request.getXid(), future);
+        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        msglist.add(request);
+        this.write(msglist);
+        return future;
+    }
+
+    @Override
+    public void deliverOFFeaturesReply(OFMessage reply) {
+        OFFeaturesReplyFuture future = this.featuresFutureMap.get(reply.getXid());
+        if (future != null) {
+            future.deliverFuture(this, reply);
+            // The future will ultimately unregister itself and call
+            // cancelFeaturesReply
+            return;
+        }
+        log.error("Switch {}: received unexpected featureReply", this);
+    }
+
+    @Override
+    public void cancelFeaturesReply(int transactionId) {
+        this.featuresFutureMap.remove(transactionId);
+    }
+
+
+    @Override
+    public int getBuffers() {
+        return buffers;
+    }
+
+
+    @Override
+    public int getActions() {
+        return actions;
+    }
+
+
+    @Override
+    public int getCapabilities() {
+        return capabilities;
+    }
+
+
+    @Override
+    public byte getTables() {
+        return tables;
+    }
+
+    @Override
+    public OFDescriptionStatistics getDescriptionStatistics() {
+        return new OFDescriptionStatistics(description);
+    }
+
+
+    @Override
+    public void setFloodlightProvider(Controller controller) {
+        floodlightProvider = controller;
+    }
+
+
+    /**
+     * For switch drivers to set thresholds, all rates in per second
+     * @param pktInHigh - above this start throttling
+     * @param pktInLow  - below this stop throttling
+     * @param pktInPerMac  - block host if unique pktIn rate reaches this
+     * @param pktInPerPort - block port if unique pktIn rate reaches this
+     */
+    @JsonIgnore
+    protected void setInputThrottleThresholds(int pktInHigh, int pktInLow,
+            int pktInPerMac, int pktInPerPort) {
+        packetInRateThresholdHigh = pktInHigh;
+        packetInRateThresholdLow = pktInLow;
+        packetInRatePerMacThreshold = pktInPerMac;
+        packetInRatePerPortThreshold = pktInPerPort;
+    }
+
+    /**
+     * Return if switch has exceeded the high threshold of packet in rate.
+     * @return
+     */
+    @Override
+    public boolean isOverloaded() {
+        return packetInThrottleEnabled;
+    }
+
+    /**
+     * Determine if this message should be dropped.
+     *
+     * We compute the current rate by taking a timestamp every 100 messages.
+     * Could change to a more complex scheme if more accuracy is needed.
+     *
+     * Enable throttling if the rate goes above packetInRateThresholdHigh
+     * Disable throttling when the rate drops below packetInRateThresholdLow
+     *
+     * While throttling is enabled, we do the following:
+     *  - Remove duplicate packetIn's mapped to the same OFMatch
+     *  - After filtering, if packetIn rate per host (mac) is above
+     *    packetInRatePerMacThreshold, push a flow mod to block mac on port
+     *  - After filtering, if packetIn rate per port is above
+     *    packetInRatePerPortThreshold, push a flow mod to block port
+     *  - Allow blocking flow mods have a hard timeout and expires automatically
+     *
+     * TODO: keep a history of all events related in input throttling
+     *
+     * @param ofm
+     * @return
+     */
+    @Override
+    public boolean inputThrottled(OFMessage ofm) {
+        if (ofm.getType() != OFType.PACKET_IN) {
+            return false;
+        }
+        ctrSwitchPktin.updateCounterNoFlush();
+        // Compute current packet in rate
+        messageCount++;
+        if (messageCount % 1000 == 0) {
+            long now = System.currentTimeMillis();
+            if (now != lastMessageTime) {
+                currentRate = (int) (1000000 / (now - lastMessageTime));
+                lastMessageTime = now;
+            } else {
+                currentRate = Integer.MAX_VALUE;
+            }
+        }
+        if (!packetInThrottleEnabled) {
+            if (currentRate <= packetInRateThresholdHigh) {
+                return false; // most common case
+            }
+            enablePacketInThrottle();
+        } else if (currentRate < packetInRateThresholdLow) {
+            disablePacketInThrottle();
+            return false;
+        }
+
+        // Now we are in the slow path where we need to do filtering
+        // First filter based on OFMatch
+        OFPacketIn pin = (OFPacketIn)ofm;
+        OFMatch match = new OFMatch();
+        match.loadFromPacket(pin.getPacketData(), pin.getInPort());
+        if (ofMatchCache.update(match)) {
+           ctrSwitchPktinDrops.updateCounterNoFlush();
+            return true;
+        }
+
+        // We have packet in with a distinct flow, check per mac rate
+        messageCountUniqueOFMatch++;
+        if ((messageCountUniqueOFMatch % packetInRatePerMacThreshold) == 1) {
+            checkPerSourceMacRate(pin);
+        }
+
+        // Check per port rate
+        if ((messageCountUniqueOFMatch % packetInRatePerPortThreshold) == 1) {
+            checkPerPortRate(pin);
+        }
+        return false;
+    }
+
+    /**
+     * We rely on the fact that packet in processing is single threaded
+     * per packet-in, so no locking is necessary.
+     */
+    private void disablePacketInThrottle() {
+        ofMatchCache = null;
+        macCache = null;
+        macBlockedCache = null;
+        portCache = null;
+        portBlockedCache = null;
+        packetInThrottleEnabled = false;
+        floodlightProvider.addSwitchEvent(this.datapathId,
+                "SWITCH_OVERLOAD_THROTTLE_DISABLED ==>" +
+                "Pktin rate " + currentRate + "/s", false);
+        log.info("Packet in rate is {}, disable throttling on {}",
+                currentRate, this);
+    }
+
+    private void enablePacketInThrottle() {
+        ofMatchCache = new TimedCache<OFMatch>(2048, 5000); // 5 second interval
+        macCache = new TimedCache<Long>(64, 1000 );  // remember last second
+        macBlockedCache = new TimedCache<Long>(256, 5000 );  // 5 second interval
+        portCache = new TimedCache<Short>(16, 1000 );  // rememeber last second
+        portBlockedCache = new TimedCache<Short>(64, 5000 );  // 5 second interval
+        packetInThrottleEnabled = true;
+        messageCountUniqueOFMatch = 0;
+        floodlightProvider.addSwitchEvent(this.datapathId,
+                "SWITCH_OVERLOAD_THROTTLE_ENABLED ==>" +
+                "Pktin rate " + currentRate + "/s", false);
+        log.info("Packet in rate is {}, enable throttling on {}",
+                currentRate, this);
+    }
+
+    private void registerOverloadCounters() throws CounterException {
+        if (debugCountersRegistered) {
+            return;
+        }
+        if (debugCounters == null) {
+            log.error("Debug Counter Service not found");
+            debugCounters = new NullDebugCounter();
+            debugCountersRegistered = true;
+        }
+        // every level of the hierarchical counter has to be registered
+        // even if they are not used
+        ctrSwitch = debugCounters.registerCounter(
+                                   PACKAGE , stringId,
+                                   "Counter for this switch",
+                                   CounterType.ALWAYS_COUNT);
+        ctrSwitchPktin = debugCounters.registerCounter(
+                                   PACKAGE, stringId + "/pktin",
+                                   "Packet in counter for this switch",
+                                   CounterType.ALWAYS_COUNT);
+        ctrSwitchWrite = debugCounters.registerCounter(
+                                   PACKAGE, stringId + "/write",
+                                   "Write counter for this switch",
+                                   CounterType.ALWAYS_COUNT);
+        ctrSwitchPktinDrops = debugCounters.registerCounter(
+                                   PACKAGE, stringId + "/pktin/drops",
+                                   "Packet in throttle drop count",
+                                   CounterType.ALWAYS_COUNT,
+                                   IDebugCounterService.CTR_MDATA_WARN);
+        ctrSwitchWriteDrops = debugCounters.registerCounter(
+                                   PACKAGE, stringId + "/write/drops",
+                                   "Switch write throttle drop count",
+                                   CounterType.ALWAYS_COUNT,
+                                   IDebugCounterService.CTR_MDATA_WARN);
+    }
+
+    /**
+     * Check if we have sampled this mac in the last second.
+     * Since we check every packetInRatePerMacThreshold packets,
+     * the presence of the mac in the macCache means the rate is
+     * above the threshold in a statistical sense.
+     *
+     * Take care not to block topology probing packets. Also don't
+     * push blocking flow mod if we have already done so within the
+     * last 5 seconds.
+     *
+     * @param pin
+     * @return
+     */
+    private void checkPerSourceMacRate(OFPacketIn pin) {
+        byte[] data = pin.getPacketData();
+        byte[] mac = Arrays.copyOfRange(data, 6, 12);
+        MACAddress srcMac = MACAddress.valueOf(mac);
+        short ethType = (short) (((data[12] & 0xff) << 8) + (data[13] & 0xff));
+        if (ethType != Ethernet.TYPE_LLDP && ethType != Ethernet.TYPE_BSN &&
+                macCache.update(srcMac.toLong())) {
+            // Check if we already pushed a flow in the last 5 seconds
+            if (macBlockedCache.update(srcMac.toLong())) {
+                return;
+            }
+            // write out drop flow per srcMac
+            int port = pin.getInPort();
+            SwitchPort swPort = new SwitchPort(getId(), port);
+            ForwardingBase.blockHost(floodlightProvider,
+                    swPort, srcMac.toLong(), (short) 5,
+                    AppCookie.makeCookie(OFSWITCH_APP_ID, 0));
+            floodlightProvider.addSwitchEvent(this.datapathId,
+                    "SWITCH_PORT_BLOCKED_TEMPORARILY " +
+                    "OFPort " + port + " mac " + srcMac, false);
+            log.info("Excessive packet in from {} on {}, block host for 5 sec",
+                    srcMac.toString(), swPort);
+        }
+    }
+
+    /**
+     * Works in a similar way as checkPerSourceMacRate().
+     *
+     * TODO Don't block ports with links?
+     *
+     * @param pin
+     * @return
+     */
+    private void checkPerPortRate(OFPacketIn pin) {
+        Short port = pin.getInPort();
+        if (portCache.update(port)) {
+            // Check if we already pushed a flow in the last 5 seconds
+            if (portBlockedCache.update(port)) {
+                return;
+            }
+            // write out drop flow per port
+            SwitchPort swPort = new SwitchPort(getId(), port);
+            ForwardingBase.blockHost(floodlightProvider,
+                    swPort, -1L, (short) 5,
+                    AppCookie.makeCookie(OFSWITCH_APP_ID, 1));
+            floodlightProvider.addSwitchEvent(this.datapathId,
+                    "SWITCH_PORT_BLOCKED_TEMPORARILY " +
+                    "OFPort " + port, false);
+            log.info("Excessive packet in from {}, block port for 5 sec",
+                    swPort);
+        }
+    }
+
+    @Override
+    @JsonIgnore
+    @LogMessageDoc(level="WARN",
+        message="Switch {switch} flow table is full",
+        explanation="The controller received flow table full " +
+                "message from the switch, could be caused by increased " +
+                "traffic pattern",
+                recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+    public void setTableFull(boolean isFull) {
+        if (isFull && !flowTableFull) {
+            floodlightProvider.addSwitchEvent(this.datapathId,
+                    "SWITCH_FLOW_TABLE_FULL " +
+                    "Table full error from switch", false);
+            log.warn("Switch {} flow table is full", stringId);
+        }
+        flowTableFull = isFull;
+    }
+
+
+    @Override
+    public short getAccessFlowPriority() {
+        return accessFlowPriority;
+    }
+
+
+    @Override
+    public short getCoreFlowPriority() {
+        return coreFlowPriority;
+    }
+
+
+    @Override
+    public void setAccessFlowPriority(short accessFlowPriority) {
+        this.accessFlowPriority = accessFlowPriority;
+    }
+
+
+    @Override
+    public void setCoreFlowPriority(short coreFlowPriority) {
+        this.coreFlowPriority = coreFlowPriority;
+    }
+
+    @Override
+    public void startDriverHandshake() {
+        if (startDriverHandshakeCalled)
+            throw new SwitchDriverSubHandshakeAlreadyStarted();
+        startDriverHandshakeCalled = true;
+    }
+
+    @Override
+    public boolean isDriverHandshakeComplete() {
+        if (!startDriverHandshakeCalled)
+            throw new SwitchDriverSubHandshakeNotStarted();
+        return true;
+    }
+
+    @Override
+    public void processDriverHandshakeMessage(OFMessage m) {
+        if (startDriverHandshakeCalled)
+            throw new SwitchDriverSubHandshakeCompleted(m);
+        else
+            throw new SwitchDriverSubHandshakeNotStarted();
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/PortChangeEvent.java b/src/main/java/net/floodlightcontroller/core/PortChangeEvent.java
deleted file mode 100644
index cca90d3a35d8c1988c00f69282be51e8d123d65c..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/PortChangeEvent.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package net.floodlightcontroller.core;
-
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-
-
-/**
- * Describes a change of an open flow port
- */
-public class PortChangeEvent {
-    public final OFPortDesc port;
-    public final PortChangeType type;
-    /**
-     * @param port
-     * @param type
-     */
-    public PortChangeEvent(OFPortDesc port,
-                           PortChangeType type) {
-        this.port = port;
-        this.type = type;
-    }
-    /* (non-Javadoc)
-     * @see java.lang.Object#hashCode()
-     */
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((port == null) ? 0 : port.hashCode());
-        result = prime * result + ((type == null) ? 0 : type.hashCode());
-        return result;
-    }
-    /* (non-Javadoc)
-     * @see java.lang.Object#equals(java.lang.Object)
-     */
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (getClass() != obj.getClass()) return false;
-        PortChangeEvent other = (PortChangeEvent) obj;
-        if (port == null) {
-            if (other.port != null) return false;
-        } else if (!port.equals(other.port)) return false;
-        if (type != other.type) return false;
-        return true;
-    }
-    /* (non-Javadoc)
-     * @see java.lang.Object#toString()
-     */
-    @Override
-    public String toString() {
-        return "[" + type + " " + String.format("%s (%d)", port.getName(), port.getPortNo()) + "]";
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/PortChangeType.java b/src/main/java/net/floodlightcontroller/core/PortChangeType.java
deleted file mode 100644
index 178d27b7603eebaa1c8400160843fd4e5d04be33..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/PortChangeType.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package net.floodlightcontroller.core;
-
-/**
- * the type of change that happened to an open flow port
- */
-public enum PortChangeType {
-    ADD, OTHER_UPDATE, DELETE, UP, DOWN,
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/RoleInfo.java b/src/main/java/net/floodlightcontroller/core/RoleInfo.java
index 31ec6464c95932a094717a02b18f400d98764d8f..1e6c186f759e2d7b81b529f91438d3b37210f46e 100644
--- a/src/main/java/net/floodlightcontroller/core/RoleInfo.java
+++ b/src/main/java/net/floodlightcontroller/core/RoleInfo.java
@@ -16,34 +16,67 @@
 
 package net.floodlightcontroller.core;
 
+import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.TimeZone;
+
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 
 public class RoleInfo {
-    private final HARole role;
-    private final String roleChangeDescription;
-    private final Date roleChangeDateTime;
+    protected String role;
+    protected String roleChangeDescription;
+    protected Date roleChangeDateTime;
 
-    public RoleInfo(HARole role, String description, Date dt) {
-        this.role = role;
+    public RoleInfo() {
+    }
+
+    public RoleInfo(RoleInfo o) {
+        role = o.role;
+        roleChangeDescription = o.roleChangeDescription;
+        roleChangeDateTime = (Date)o.roleChangeDateTime.clone();
+    }
+
+    public RoleInfo(String role) {
+        setRole(role);
+    }
+
+    public RoleInfo(Role role, String description) {
+        this.role = (role != null) ? role.name() : "DISABLED";
+        this.roleChangeDescription = description;
+    }
+
+    public RoleInfo(Role role, String description, Date dt) {
+        this.role = (role != null) ? role.name() : "DISABLED";
         this.roleChangeDescription = description;
         this.roleChangeDateTime = dt;
     }
 
-    public HARole getRole() {
+    public String getRole() {
         return role;
     }
 
+    public void setRole(String role) {
+        this.role = role;
+    }
+
     @JsonProperty(value="change-description")
     public String getRoleChangeDescription() {
         return roleChangeDescription;
     }
-
+    @JsonProperty(value="change-description")
+    public void setRoleChangeDescription(String roleChangeDescription) {
+        this.roleChangeDescription = roleChangeDescription;
+    }
     @JsonProperty(value="change-date-time")
-    public Date getRoleChangeDateTime() {
-        return roleChangeDateTime;
+    public String getRoleChangeDateTime() {
+        SimpleDateFormat formatter =
+                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+        formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
+        return roleChangeDateTime == null ?
+                  "" : formatter.format(roleChangeDateTime);
     }
 
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDescription.java b/src/main/java/net/floodlightcontroller/core/SwitchDescription.java
deleted file mode 100644
index 57697d70916554da6cb73881b1237fadcd863101..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/SwitchDescription.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package net.floodlightcontroller.core;
-
-import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
-
-/**
- * Encapsulates the switch information return from the description stats request
- *
- * @author Rob Vaterlaus <rob.vaterlaus@bigswitch.com>
- */
-public class SwitchDescription {
-
-    public static class Builder {
-
-        private String manufacturerDescription;
-        private String hardwareDescription;
-        private String softwareDescription;
-        private String serialNumber;
-        private String datapathDescription;
-
-        public Builder() {
-            manufacturerDescription = "";
-            hardwareDescription = "";
-            softwareDescription = "";
-            serialNumber = "";
-            datapathDescription = "";
-        }
-
-        public Builder setManufacturerDescription(String manufacturerDescription) {
-            this.manufacturerDescription = manufacturerDescription;
-            return this;
-        }
-
-        public Builder setHardwareDescription(String hardwareDescription) {
-            this.hardwareDescription = hardwareDescription;
-            return this;
-        }
-
-        public Builder setSoftwareDescription(String softwareDescription) {
-            this.softwareDescription = softwareDescription;
-            return this;
-        }
-
-        public Builder setSerialNumber(String serialNumber) {
-            this.serialNumber = serialNumber;
-            return this;
-        }
-
-        public Builder setDatapathDescription(String datapathDescription) {
-            this.datapathDescription = datapathDescription;
-            return this;
-        }
-
-        public SwitchDescription build() {
-            return new SwitchDescription(manufacturerDescription,
-                    hardwareDescription, softwareDescription, serialNumber,
-                    datapathDescription);
-        }
-    }
-
-    private final String manufacturerDescription;
-    private final String hardwareDescription;
-    private final String softwareDescription;
-    private final String serialNumber;
-    private final String datapathDescription;
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    // FIXME: Should make this private
-    public SwitchDescription() {
-        this("", "", "", "", "");
-    }
-
-    // FIXME: Should make this private
-    public SwitchDescription(String manufacturerDescription,
-            String hardwareDescription, String softwareDescription,
-            String serialNumber, String datapathDescription) {
-        this.manufacturerDescription = manufacturerDescription;
-        this.hardwareDescription = hardwareDescription;
-        this.softwareDescription = softwareDescription;
-        this.serialNumber = serialNumber;
-        this.datapathDescription = datapathDescription;
-    }
-
-    public SwitchDescription(OFDescStatsReply descStatsReply) {
-        this(descStatsReply.getMfrDesc(), descStatsReply.getHwDesc(),
-                descStatsReply.getSwDesc(), descStatsReply.getSerialNum(),
-                descStatsReply.getDpDesc());
-    }
-
-    public String getManufacturerDescription() {
-        return manufacturerDescription;
-    }
-
-    public String getHardwareDescription() {
-        return hardwareDescription;
-    }
-
-    public String getSoftwareDescription() {
-        return softwareDescription;
-    }
-
-    public String getSerialNumber() {
-        return serialNumber;
-    }
-
-    public String getDatapathDescription() {
-        return datapathDescription;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime
-                * result
-                + ((datapathDescription == null) ? 0 : datapathDescription
-                        .hashCode());
-        result = prime
-                * result
-                + ((hardwareDescription == null) ? 0 : hardwareDescription
-                        .hashCode());
-        result = prime
-                * result
-                + ((manufacturerDescription == null) ? 0
-                        : manufacturerDescription.hashCode());
-        result = prime * result
-                + ((serialNumber == null) ? 0 : serialNumber.hashCode());
-        result = prime
-                * result
-                + ((softwareDescription == null) ? 0 : softwareDescription
-                        .hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        SwitchDescription other = (SwitchDescription) obj;
-        if (datapathDescription == null) {
-            if (other.datapathDescription != null)
-                return false;
-        } else if (!datapathDescription.equals(other.datapathDescription))
-            return false;
-        if (hardwareDescription == null) {
-            if (other.hardwareDescription != null)
-                return false;
-        } else if (!hardwareDescription.equals(other.hardwareDescription))
-            return false;
-        if (manufacturerDescription == null) {
-            if (other.manufacturerDescription != null)
-                return false;
-        } else if (!manufacturerDescription
-                .equals(other.manufacturerDescription))
-            return false;
-        if (serialNumber == null) {
-            if (other.serialNumber != null)
-                return false;
-        } else if (!serialNumber.equals(other.serialNumber))
-            return false;
-        if (softwareDescription == null) {
-            if (other.softwareDescription != null)
-                return false;
-        } else if (!softwareDescription.equals(other.softwareDescription))
-            return false;
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return "SwitchDescription [manufacturerDescription=" + manufacturerDescription
-                + ", hardwareDescription=" + hardwareDescription + ", softwareDescription="
-                + softwareDescription + ", serialNumber=" + serialNumber
-                + ", datapathDescription=" + datapathDescription + "]";
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDisconnectedException.java b/src/main/java/net/floodlightcontroller/core/SwitchDisconnectedException.java
deleted file mode 100644
index 21b74ec7470071ee2fee36333c0316fd3381b5d7..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/SwitchDisconnectedException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package net.floodlightcontroller.core;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-
-public class SwitchDisconnectedException extends Exception {
-    private static final long serialVersionUID = 1L;
-
-    private final DatapathId id;
-
-    public SwitchDisconnectedException(DatapathId id) {
-        super(genMessage(id));
-        this.id = id;
-    }
-
-    private static String genMessage(DatapathId id) {
-        return String.format("Switch %s disconnected", id);
-    }
-
-    public DatapathId getId() {
-        return id;
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeAlreadyStarted.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeAlreadyStarted.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb5541bf960694a1961882c24bf79e2536b41644
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeAlreadyStarted.java
@@ -0,0 +1,15 @@
+package net.floodlightcontroller.core;
+
+/**
+ * Thrown when IOFSwitch.startDriverHandshake() is called more than once.
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeAlreadyStarted extends
+    SwitchDriverSubHandshakeException {
+    private static final long serialVersionUID = -5491845708752443501L;
+
+    public SwitchDriverSubHandshakeAlreadyStarted() {
+        super();
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeCompleted.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeCompleted.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed39b5f44bc34597b41d3fc848d2b3410c7943b4
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeCompleted.java
@@ -0,0 +1,19 @@
+package net.floodlightcontroller.core;
+
+import org.openflow.protocol.OFMessage;
+
+/**
+ * Indicates that a message was passed to a switch driver's subhandshake
+ * handling code but the driver has already completed the sub-handshake
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeCompleted
+        extends SwitchDriverSubHandshakeException {
+    private static final long serialVersionUID = -8817822245846375995L;
+
+    public SwitchDriverSubHandshakeCompleted(OFMessage m) {
+        super("Sub-Handshake is already complete but received message " +
+              m.getType());
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeException.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c0c87390468b304db6865c04a228d7e351a73dc
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeException.java
@@ -0,0 +1,27 @@
+package net.floodlightcontroller.core;
+
+/**
+ * Base class for exception thrown by switch driver sub-handshake processing
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeException extends RuntimeException {
+    private static final long serialVersionUID = -6257836781419604438L;
+
+    protected SwitchDriverSubHandshakeException() {
+        super();
+    }
+
+    protected SwitchDriverSubHandshakeException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+    }
+
+    protected SwitchDriverSubHandshakeException(String arg0) {
+        super(arg0);
+    }
+
+    protected SwitchDriverSubHandshakeException(Throwable arg0) {
+        super(arg0);
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeNotStarted.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeNotStarted.java
new file mode 100644
index 0000000000000000000000000000000000000000..67ec68be2c1540f56db63632a0e82757cb92a719
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeNotStarted.java
@@ -0,0 +1,16 @@
+package net.floodlightcontroller.core;
+
+/**
+ * Thrown when a switch driver's sub-handshake has not been started but an
+ * operation requiring the sub-handshake has been attempted.
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeNotStarted extends
+    SwitchDriverSubHandshakeException {
+    private static final long serialVersionUID = -5491845708752443501L;
+
+    public SwitchDriverSubHandshakeNotStarted() {
+        super();
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeStateException.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeStateException.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f49aea7ab60c9a58d77f7753f617b25015e4346
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeStateException.java
@@ -0,0 +1,16 @@
+package net.floodlightcontroller.core;
+
+/**
+ * Thrown when a switch driver's sub-handshake state-machine receives an
+ * unexpected OFMessage and/or is in an invald state
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeStateException extends
+    SwitchDriverSubHandshakeException {
+    private static final long serialVersionUID = -8249926069195147051L;
+
+    public SwitchDriverSubHandshakeStateException(String msg) {
+        super(msg);
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchSyncRepresentation.java b/src/main/java/net/floodlightcontroller/core/SwitchSyncRepresentation.java
index ea583510844a32655d7019afe2a10d620a02c892..6284ba3c38785c2e5dc21421d012147f74c165ed 100644
--- a/src/main/java/net/floodlightcontroller/core/SwitchSyncRepresentation.java
+++ b/src/main/java/net/floodlightcontroller/core/SwitchSyncRepresentation.java
@@ -2,20 +2,16 @@ package net.floodlightcontroller.core;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import net.floodlightcontroller.util.EnumBitmaps;
+import net.floodlightcontroller.util.MACAddress;
 
-import net.floodlightcontroller.core.SwitchDescription;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.util.HexString;
-import org.projectfloodlight.openflow.protocol.OFCapabilities;
-import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.protocol.OFPhysicalPort.OFPortState;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import org.openflow.util.HexString;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -31,11 +27,27 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class SwitchSyncRepresentation {
     public static class SyncedPort {
         @JsonProperty
-        public OFPortDesc port;
+        public short portNumber;
+        @JsonProperty
+        public long hardwareAddress;
+        @JsonProperty
+        public String name;
+        @JsonProperty
+        public int config;
+        @JsonProperty
+        public int state;
+        @JsonProperty
+        public int currentFeatures;
+        @JsonProperty
+        public int advertisedFeatures;
+        @JsonProperty
+        public int supportedFeatures;
+        @JsonProperty
+        public int peerFeatures;
 
-        /*public static SyncedPort fromImmutablePort(OFPortDesc p) {
+        public static SyncedPort fromImmutablePort(ImmutablePort p) {
             SyncedPort rv = new SyncedPort();
-            rv.port = OFPortDesc.of(p.getPortNumber());
+            rv.portNumber = p.getPortNumber();
             if (p.getHardwareAddress() == null) {
                 rv.hardwareAddress = 0;
             } else {
@@ -54,38 +66,32 @@ public class SwitchSyncRepresentation {
                     EnumBitmaps.toBitmap(p.getSupportedFeatures());
             rv.peerFeatures = EnumBitmaps.toBitmap(p.getPeerFeatures());
             return rv;
-        }*/
-
-        public static SyncedPort fromOFPortDesc(OFPortDesc ofpd) {
-	            SyncedPort sp = new SyncedPort();
-	            sp.port = ofpd;
-	            return sp;
-        } 
-        
-        public OFPortDesc toOFPortDesc(OFFactory factory) {
-        	OFPortDesc.Builder builder = factory.buildPortDesc();
-            builder.setPortNo(port.getPortNo());
-            builder.setHwAddr(port.getHwAddr());
-            builder.setName(port.getName());
-            builder.setConfig(port.getConfig());
-            builder.setState(port.getState());
-            builder.setCurr(port.getCurr());
-            builder.setAdvertised(port.getAdvertised());
-            builder.setSupported(port.getSupported());
-            builder.setPeer(port.getPeer());
-            return builder.build();
+        }
+
+        public OFPhysicalPort toOFPhysicalPort() {
+            OFPhysicalPort p = new OFPhysicalPort();
+            p.setPortNumber(portNumber);
+            p.setHardwareAddress(MACAddress.valueOf(hardwareAddress).toBytes());
+            p.setName(name);
+            p.setConfig(config);
+            p.setState(state);
+            p.setCurrentFeatures(currentFeatures);
+            p.setAdvertisedFeatures(advertisedFeatures);
+            p.setSupportedFeatures(supportedFeatures);
+            p.setPeerFeatures(peerFeatures);
+            return p;
         }
     }
 
     // From FeaturesReply
-    private final DatapathId dpid;
-    private final long buffers;
-    private final short tables;
-    private final Set<OFCapabilities> capabilities;
-    private final Set<OFActionType> actions;
+    private final long dpid;
+    private final int buffers;
+    private final byte tables;
+    private final int capabilities;
+    private final int actions;
     private final List<SyncedPort> ports;
 
-    // From OFDescStatsReply
+    // From OFDescriptionStatistics
     private final String manufacturerDescription;
     private final String hardwareDescription;
     private final String softwareDescription;
@@ -109,11 +115,11 @@ public class SwitchSyncRepresentation {
      */
     @JsonCreator
     public SwitchSyncRepresentation(
-            @JsonProperty("dpid") DatapathId dpid,
+            @JsonProperty("dpid") long dpid,
             @JsonProperty("buffers") int buffers,
             @JsonProperty("tables") byte tables,
-            @JsonProperty("capabilities") Set<OFCapabilities> capabilities,
-            @JsonProperty("actions") Set<OFActionType> actions,
+            @JsonProperty("capabilities") int capabilities,
+            @JsonProperty("actions") int actions,
             @JsonProperty("ports") List<SyncedPort> ports,
             @JsonProperty("manufacturerDescription") String manufacturerDescription,
             @JsonProperty("hardwareDescription") String hardwareDescription,
@@ -141,7 +147,7 @@ public class SwitchSyncRepresentation {
         this.actions = sw.getActions();
         this.ports = toSyncedPortList(sw.getPorts());
 
-        SwitchDescription d = sw.getSwitchDescription();
+        OFDescriptionStatistics d = sw.getDescriptionStatistics();
         this.manufacturerDescription = d.getManufacturerDescription();
         this.hardwareDescription = d.getHardwareDescription();
         this.softwareDescription = d.getSoftwareDescription();
@@ -150,13 +156,14 @@ public class SwitchSyncRepresentation {
     }
 
     public SwitchSyncRepresentation(OFFeaturesReply fr,
-                                    SwitchDescription d) {
+                                    OFDescriptionStatistics d) {
         this.dpid = fr.getDatapathId();
-        this.buffers = fr.getNBuffers();
-        this.tables = fr.getNTables();
+        this.buffers = fr.getBuffers();
+        this.tables = fr.getTables();
         this.capabilities = fr.getCapabilities();
         this.actions = fr.getActions();
-        this.ports = toSyncedPortList(fr.getPorts());
+        this.ports = toSyncedPortList(
+                ImmutablePort.immutablePortListOf(fr.getPorts()));
 
         this.manufacturerDescription = d.getManufacturerDescription();
         this.hardwareDescription = d.getHardwareDescription();
@@ -165,73 +172,65 @@ public class SwitchSyncRepresentation {
         this.datapathDescription = d.getDatapathDescription();
     }
 
-    private static List<SyncedPort> toSyncedPortList(Collection<OFPortDesc> ports) {
+    private static List<SyncedPort> toSyncedPortList(Collection<ImmutablePort> ports) {
         List<SyncedPort> rv = new ArrayList<SyncedPort>(ports.size());
-        for (OFPortDesc p: ports) {
-            rv.add(SyncedPort.fromOFPortDesc(p));
+        for (ImmutablePort p: ports) {
+            rv.add(SyncedPort.fromImmutablePort(p));
         }
         return rv;
     }
 
-    private static List<OFPortDesc> toOFPortDescList(OFFactory factory, Collection<SyncedPort> ports) {
-        List<OFPortDesc> rv = new ArrayList<OFPortDesc>(ports.size());
+    private static List<OFPhysicalPort> toOFPhysicalPortList(Collection<SyncedPort> ports) {
+        List<OFPhysicalPort> rv = new ArrayList<OFPhysicalPort>(ports.size());
         for (SyncedPort p: ports) {
-            rv.add(p.toOFPortDesc(factory));
+            rv.add(p.toOFPhysicalPort());
         }
         return rv;
 
     }
 
     @JsonIgnore
-    public OFFeaturesReply getFeaturesReply(OFFactory factory) {
-    	/**
-         * FIXME Icky work around; if a null actions got written to storage
-         * then fake up an empty one so the builder() doesn't throw
-         * a NPE.  Need to root cause why someone would write a null actions.
-         * This code will all be removed shortly -- needed to unblock BVS team.
-         */
-        Set<OFActionType> workAroundActions;
-        if (actions != null)
-            workAroundActions = actions;
-        else
-            workAroundActions = Collections.<OFActionType> emptySet();
-
-        OFFeaturesReply featuresReply = factory.buildFeaturesReply()
-                .setXid(0)
-                .setDatapathId(dpid)
-                .setNBuffers(buffers)
-                .setNTables(tables)
-                .setCapabilities(capabilities)
-                .setActions(workAroundActions)
-                .setPorts(toOFPortDescList(factory, ports))
-                .build();
-        return featuresReply;
+    public OFFeaturesReply getFeaturesReply() {
+        OFFeaturesReply fr = new OFFeaturesReply();
+        fr.setDatapathId(dpid);
+        fr.setBuffers(buffers);
+        fr.setTables(tables);
+        fr.setCapabilities(capabilities);
+        fr.setActions(actions);
+        fr.setPorts(toOFPhysicalPortList(ports));
+        return fr;
     }
 
     @JsonIgnore
-    public SwitchDescription getDescription() {
-    	return new SwitchDescription(manufacturerDescription,
-                hardwareDescription, softwareDescription, softwareDescription,
-                datapathDescription);
+    public OFDescriptionStatistics getDescription() {
+        OFDescriptionStatistics desc = new OFDescriptionStatistics();
+        desc.setManufacturerDescription(manufacturerDescription);
+        desc.setHardwareDescription(hardwareDescription);
+        desc.setSoftwareDescription(softwareDescription);
+        desc.setSerialNumber(serialNumber);
+        desc.setDatapathDescription(datapathDescription);
+        return desc;
     }
 
-    public DatapathId getDpid() {
+
+
+    public long getDpid() {
         return dpid;
     }
 
-    public long getBuffers() {
+    public int getBuffers() {
         return buffers;
     }
 
-    public short getTables() {
+    public byte getTables() {
         return tables;
     }
 
-    public Set<OFCapabilities> getCapabilities() {
+    public int getCapabilities() {
         return capabilities;
     }
 
-    public Set<OFActionType> getActions() {
+    public int getActions() {
         return actions;
     }
 
@@ -262,7 +261,7 @@ public class SwitchSyncRepresentation {
     @Override
     public String toString() {
         String dpidString;
-        dpidString = HexString.toHexString(dpid.getLong());
+        dpidString = HexString.toHexString(dpid);
         return "SwitchSyncRepresentation [DPID=" + dpidString + "]";
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d6227d108b6a1279056b450622c05750f77e90c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -0,0 +1,2696 @@
+/**
+*    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.core.internal;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Stack;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.HAListenerTypeMarker;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IHAListener;
+import net.floodlightcontroller.core.IInfoProvider;
+import net.floodlightcontroller.core.IListener.Command;
+import net.floodlightcontroller.core.IOFMessageListener;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitch.PortChangeEvent;
+import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
+import net.floodlightcontroller.core.IOFSwitchDriver;
+import net.floodlightcontroller.core.IOFSwitchListener;
+import net.floodlightcontroller.core.IReadyForReconcileListener;
+import net.floodlightcontroller.core.ImmutablePort;
+import net.floodlightcontroller.core.OFSwitchBase;
+import net.floodlightcontroller.core.RoleInfo;
+import net.floodlightcontroller.core.SwitchSyncRepresentation;
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.util.ListenerDispatcher;
+import net.floodlightcontroller.core.web.CoreWebRoutable;
+import net.floodlightcontroller.counter.ICounterStoreService;
+import net.floodlightcontroller.debugcounter.IDebugCounter;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
+import net.floodlightcontroller.debugevent.IDebugEventService;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
+import net.floodlightcontroller.debugevent.IEventUpdater;
+import net.floodlightcontroller.debugevent.NullDebugEvent;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
+import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
+import net.floodlightcontroller.notification.INotificationManager;
+import net.floodlightcontroller.notification.NotificationManagerFactory;
+import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
+import net.floodlightcontroller.restserver.IRestApiService;
+import net.floodlightcontroller.storage.IResultSet;
+import net.floodlightcontroller.storage.IStorageSourceListener;
+import net.floodlightcontroller.storage.IStorageSourceService;
+import net.floodlightcontroller.storage.StorageException;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.util.LoadMonitor;
+import net.floodlightcontroller.util.TimedCache;
+
+import org.jboss.netty.bootstrap.ServerBootstrap;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.group.ChannelGroup;
+import org.jboss.netty.channel.group.DefaultChannelGroup;
+import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import org.openflow.util.HexString;
+import org.openflow.vendor.nicira.OFNiciraVendorExtensions;
+import org.sdnplatform.sync.IClosableIterator;
+import org.sdnplatform.sync.IStoreClient;
+import org.sdnplatform.sync.IStoreListener;
+import org.sdnplatform.sync.ISyncService;
+import org.sdnplatform.sync.ISyncService.Scope;
+import org.sdnplatform.sync.Versioned;
+import org.sdnplatform.sync.error.ObsoleteVersionException;
+import org.sdnplatform.sync.error.SyncException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.bigswitch.floodlight.vendor.OFVendorActions;
+
+
+
+/**
+ * The main controller class.  Handles all setup and network listeners
+ */
+public class Controller implements IFloodlightProviderService,
+            IStorageSourceListener, IInfoProvider {
+
+    protected static final Logger log = LoggerFactory.getLogger(Controller.class);
+    protected static final INotificationManager notifier =
+            NotificationManagerFactory.getNotificationManager(Controller.class);
+
+    static final String ERROR_DATABASE =
+            "The controller could not communicate with the system database.";
+    static final String SWITCH_SYNC_STORE_NAME =
+            Controller.class.getCanonicalName() + ".stateStore";
+
+    protected BasicFactory factory;
+    protected ConcurrentMap<OFType,
+                            ListenerDispatcher<OFType,IOFMessageListener>>
+                                messageListeners;
+
+    // OFSwitch driver binding map and order
+    private ISwitchDriverRegistry driverRegistry;
+
+    // The controllerNodeIPsCache maps Controller IDs to their IP address.
+    // It's only used by handleControllerNodeIPsChanged
+    protected HashMap<String, String> controllerNodeIPsCache;
+
+    protected Set<IOFSwitchListener> switchListeners;
+    protected ListenerDispatcher<HAListenerTypeMarker,IHAListener> haListeners;
+    protected Set<IReadyForReconcileListener> readyForReconcileListeners;
+    protected Map<String, List<IInfoProvider>> providerMap;
+    protected BlockingQueue<IUpdate> updates;
+
+    // Module dependencies
+    private IRestApiService restApi;
+    private ICounterStoreService counterStore = null;
+    private IDebugCounterService debugCounters;
+    protected IDebugEventService debugEvents;
+    private IStorageSourceService storageSource;
+    private IPktInProcessingTimeService pktinProcTime;
+    private IThreadPoolService threadPool;
+    private ScheduledExecutorService ses;
+    private ISyncService syncService;
+    private IStoreClient<Long, SwitchSyncRepresentation> storeClient;
+
+    // Configuration options
+    protected String openFlowHost = null;
+    protected int openFlowPort = 6633;
+    protected int workerThreads = 0;
+
+
+    // This controller's current role that modules can use/query to decide
+    // if they should operate in master or slave mode.
+    // TODO: potentially we need to get rid of this field and modules must
+    // then rely on the role notifications alone...
+    protected volatile Role notifiedRole;
+
+    private static final String
+            INITIAL_ROLE_CHANGE_DESCRIPTION = "Controller startup.";
+    private RoleManager roleManager;
+    private SwitchManager switchManager;
+
+    private static final int DEFAULT_CONSOLIDATE_STORE_TIME_DELAY_MS =
+            15*1000; // 15s
+    private int consolidateStoreTimeDelayMs =
+            DEFAULT_CONSOLIDATE_STORE_TIME_DELAY_MS;
+
+
+    // Flag to always flush flow table on switch reconnect (HA or otherwise)
+    private boolean alwaysClearFlowsOnSwActivate = false;
+    private TimedCache<Long> swConnectCache;
+
+    // Storage table names
+    protected static final String CONTROLLER_TABLE_NAME = "controller_controller";
+    protected static final String CONTROLLER_ID = "id";
+
+    protected static final String SWITCH_CONFIG_TABLE_NAME = "controller_switchconfig";
+    protected static final String SWITCH_CONFIG_CORE_SWITCH = "core_switch";
+
+    protected static final String CONTROLLER_INTERFACE_TABLE_NAME = "controller_controllerinterface";
+    protected static final String CONTROLLER_INTERFACE_ID = "id";
+    protected static final String CONTROLLER_INTERFACE_CONTROLLER_ID = "controller_id";
+    protected static final String CONTROLLER_INTERFACE_TYPE = "type";
+    protected static final String CONTROLLER_INTERFACE_NUMBER = "number";
+    protected static final String CONTROLLER_INTERFACE_DISCOVERED_IP = "discovered_ip";
+
+    // FIXME: don't use "forwardingconfig" as table name
+    private static final String FLOW_PRIORITY_TABLE_NAME = "controller_forwardingconfig";
+    private static final String FLOW_COLUMN_PRIMARY_KEY = "id";
+    private static final String FLOW_VALUE_PRIMARY_KEY = "forwarding";
+    private static final String FLOW_COLUMN_ACCESS_PRIORITY = "access_priority";
+    private static final String FLOW_COLUMN_CORE_PRIORITY = "core_priority";
+    private static final String[] FLOW_COLUMN_NAMES = new String[] {
+            FLOW_COLUMN_PRIMARY_KEY,
+            FLOW_COLUMN_ACCESS_PRIORITY,
+            FLOW_COLUMN_CORE_PRIORITY
+    };
+
+    private static final short DEFAULT_ACCESS_PRIORITY = 10;
+    private static final short DEFAULT_CORE_PRIORITY = 1000;
+    private short accessPriority = DEFAULT_ACCESS_PRIORITY;
+    private short corePriority = DEFAULT_CORE_PRIORITY;
+
+
+    // Perf. related configuration
+    protected static final int SEND_BUFFER_SIZE = 128 * 1024;
+    public static final int BATCH_MAX_SIZE = 100;
+    protected static final boolean ALWAYS_DECODE_ETH = true;
+
+    // Set of port name prefixes that will be classified as uplink ports,
+    // hence will not be autoportfast.
+    Set<String> uplinkPortPrefixSet;
+
+    @Override
+    public Set<String> getUplinkPortPrefixSet() {
+        return uplinkPortPrefixSet;
+    }
+
+    public void setUplinkPortPrefixSet(Set<String> prefixSet) {
+        this.uplinkPortPrefixSet = prefixSet;
+    }
+
+    // Event IDs for debug events
+    protected IEventUpdater<SwitchEvent> evSwitch;
+
+    // Load monitor for overload protection
+    protected final boolean overload_drop =
+        Boolean.parseBoolean(System.getProperty("overload_drop", "false"));
+    protected final LoadMonitor loadmonitor = new LoadMonitor(log);
+
+    private class NotificationSwitchListener implements IOFSwitchListener {
+
+        @Override
+        public void switchAdded(long switchId) {
+            notifier.postNotification("Switch " + HexString.toHexString(switchId) + " connected.");
+        }
+
+        @Override
+        public void switchRemoved(long switchId) {
+            notifier.postNotification("Switch " + HexString.toHexString(switchId) + " disconnected.");
+        }
+
+        @Override
+        public void switchActivated(long switchId) {
+        }
+
+        @Override
+        public void switchPortChanged(long switchId, ImmutablePort port,
+                                      PortChangeType type) {
+            String msg = String.format("Switch %s port %s changed: %s",
+                                       HexString.toHexString(switchId),
+                                       port.getName(),
+                                       type.toString());
+            notifier.postNotification(msg);
+        }
+
+        @Override
+        public void switchChanged(long switchId) {
+        }
+    }
+    public static class Counters {
+        public static final String prefix = Controller.class.getPackage().getName();
+        public IDebugCounter setRoleEqual;
+        public IDebugCounter setSameRole;
+        public IDebugCounter setRoleMaster;
+        public IDebugCounter remoteStoreNotification;
+        public IDebugCounter invalidPortsChanged;
+        public IDebugCounter invalidSwitchActivatedWhileSlave;
+        public IDebugCounter invalidStoreEventWhileMaster;
+        public IDebugCounter switchDisconnectedWhileSlave;
+        public IDebugCounter switchActivated;
+        public IDebugCounter errorSameSwitchReactivated; // err
+        public IDebugCounter switchWithSameDpidActivated; // warn
+        public IDebugCounter newSwitchActivated;   // new switch
+        public IDebugCounter syncedSwitchActivated;
+        public IDebugCounter readyForReconcile;
+        public IDebugCounter newSwitchFromStore;
+        public IDebugCounter updatedSwitchFromStore;
+        public IDebugCounter switchDisconnected;
+        public IDebugCounter syncedSwitchRemoved;
+        public IDebugCounter unknownSwitchRemovedFromStore;
+        public IDebugCounter consolidateStoreRunCount;
+        public IDebugCounter consolidateStoreInconsistencies;
+        public IDebugCounter storeSyncError;
+        public IDebugCounter switchesNotReconnectingToNewMaster;
+        public IDebugCounter switchPortChanged;
+        public IDebugCounter switchOtherChange;
+        public IDebugCounter dispatchMessageWhileSlave;
+        public IDebugCounter dispatchMessage;  // does this cnt make sense? more specific?? per type? count stops?
+        public IDebugCounter controllerNodeIpsChanged;
+        public IDebugCounter messageReceived;
+        public IDebugCounter messageInputThrottled;
+        public IDebugCounter switchDisconnectReadTimeout;
+        public IDebugCounter switchDisconnectHandshakeTimeout;
+        public IDebugCounter switchDisconnectIOError;
+        public IDebugCounter switchDisconnectParseError;
+        public IDebugCounter switchDisconnectSwitchStateException;
+        public IDebugCounter rejectedExecutionException;
+        public IDebugCounter switchDisconnectOtherException;
+        public IDebugCounter switchConnected;
+        public IDebugCounter unhandledMessage;
+        public IDebugCounter packetInWhileSwitchIsSlave;
+        public IDebugCounter epermErrorWhileSwitchIsMaster;
+        public IDebugCounter roleNotResentBecauseRolePending;
+        public IDebugCounter roleRequestSent;
+        public IDebugCounter roleReplyTimeout;
+        public IDebugCounter roleReplyReceived; // expected RoleReply received
+        public IDebugCounter roleReplyErrorUnsupported;
+        public IDebugCounter switchCounterRegistrationFailed;
+
+        void createCounters(IDebugCounterService debugCounters) throws CounterException {
+            setRoleEqual =
+                debugCounters.registerCounter(
+                            prefix, "set-role-equal",
+                            "Controller received a role request with role of "+
+                            "EQUAL which is unusual",
+                            CounterType.ALWAYS_COUNT);
+            setSameRole =
+                debugCounters.registerCounter(
+                            prefix, "set-same-role",
+                            "Controller received a role request for the same " +
+                            "role the controller already had",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            setRoleMaster =
+                debugCounters.registerCounter(
+                            prefix, "set-role-master",
+                            "Controller received a role request with role of " +
+                            "MASTER. This counter can be at most 1.",
+                            CounterType.ALWAYS_COUNT);
+
+            remoteStoreNotification =
+                debugCounters.registerCounter(
+                            prefix, "remote-store-notification",
+                            "Received a notification from the sync service " +
+                            "indicating that switch information has changed",
+                            CounterType.ALWAYS_COUNT);
+
+            invalidPortsChanged =
+                debugCounters.registerCounter(
+                            prefix, "invalid-ports-changed",
+                            "Received an unexpected ports changed " +
+                            "notification while the controller was in " +
+                            "SLAVE role.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            invalidSwitchActivatedWhileSlave =
+                debugCounters.registerCounter(
+                            prefix, "invalid-switch-activated-while-slave",
+                            "Received an unexpected switchActivated " +
+                            "notification while the controller was in " +
+                            "SLAVE role.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            invalidStoreEventWhileMaster =
+                debugCounters.registerCounter(
+                            prefix, "invalid-store-event-while-master",
+                            "Received an unexpected notification from " +
+                            "the sync store while the controller was in " +
+                            "MASTER role.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            switchDisconnectedWhileSlave =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnected-while-slave",
+                            "A switch disconnected and the controller was " +
+                            "in SLAVE role.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            switchActivated =
+                debugCounters.registerCounter(
+                            prefix, "switch-activated",
+                            "A switch connected to this controller is now " +
+                            "in MASTER role",
+                            CounterType.ALWAYS_COUNT);
+
+            errorSameSwitchReactivated = // err
+                debugCounters.registerCounter(
+                            prefix, "error-same-switch-reactivated",
+                            "A switch that was already in active state " +
+                            "was activated again. This indicates a " +
+                            "controller defect",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchWithSameDpidActivated = // warn
+                debugCounters.registerCounter(
+                            prefix, "switch-with-same-dpid-activated",
+                            "A switch with the same DPID as another switch " +
+                            "connected to the controller. This can be " +
+                            "caused by multiple switches configured with " +
+                            "the same DPID or by a switch reconnecting very " +
+                            "quickly.",
+                            CounterType.COUNT_ON_DEMAND,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            newSwitchActivated =   // new switch
+                debugCounters.registerCounter(
+                            prefix, "new-switch-activated",
+                            "A new switch has completed the handshake as " +
+                            "MASTER. The switch was not known to any other " +
+                            "controller in the cluster",
+                            CounterType.ALWAYS_COUNT);
+            syncedSwitchActivated =
+                debugCounters.registerCounter(
+                            prefix, "synced-switch-activated",
+                            "A switch has completed the handshake as " +
+                            "MASTER. The switch was known to another " +
+                            "controller in the cluster",
+                            CounterType.ALWAYS_COUNT);
+
+            readyForReconcile =
+                debugCounters.registerCounter(
+                            prefix, "ready-for-reconcile",
+                            "Controller is ready for flow reconciliation " +
+                            "after Slave to Master transition. Either all " +
+                            "previously known switches are now active " +
+                            "or they have timed out and have been removed." +
+                            "This counter will be 0 or 1.",
+                            CounterType.ALWAYS_COUNT);
+
+            newSwitchFromStore =
+                debugCounters.registerCounter(
+                            prefix, "new-switch-from-store",
+                            "A new switch has connected to another " +
+                            "another controller in the cluster. This " +
+                            "controller instance has received a sync store " +
+                            "notification for it.",
+                            CounterType.ALWAYS_COUNT);
+
+            updatedSwitchFromStore =
+                debugCounters.registerCounter(
+                            prefix, "updated-switch-from-store",
+                            "Information about a switch connected to " +
+                            "another controller instance was updated in " +
+                            "the sync store. This controller instance has " +
+                            "received a notification for it",
+                            CounterType.ALWAYS_COUNT);
+
+            switchDisconnected =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnected",
+                            "FIXME: switch has disconnected",
+                            CounterType.ALWAYS_COUNT);
+
+            syncedSwitchRemoved =
+                debugCounters.registerCounter(
+                            prefix, "synced-switch-removed",
+                            "A switch connected to another controller " +
+                            "instance has disconnected from the controller " +
+                            "cluster. This controller instance has " +
+                            "received a notification for it",
+                            CounterType.ALWAYS_COUNT);
+
+            unknownSwitchRemovedFromStore =
+                debugCounters.registerCounter(
+                            prefix, "unknown-switch-removed-from-store",
+                            "This controller instances has received a sync " +
+                            "store notification that a switch has " +
+                            "disconnected but this controller instance " +
+                            "did not have the any information about the " +
+                            "switch", // might be less than warning
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            consolidateStoreRunCount =
+                debugCounters.registerCounter(
+                            prefix, "consolidate-store-run-count",
+                            "This controller has transitioned from SLAVE " +
+                            "to MASTER and waited for switches to reconnect. " +
+                            "The controller has finished waiting and has " +
+                            "reconciled switch entries in the sync store " +
+                            "with live state",
+                            CounterType.ALWAYS_COUNT);
+
+            consolidateStoreInconsistencies =
+                    debugCounters.registerCounter(
+                                prefix, "consolidate-store-inconsistencies",
+                                "During switch sync store consolidation: " +
+                                "Number of switches that were in the store " +
+                                "but not otherwise known plus number of " +
+                                "switches that were in the store previously " +
+                                "but are now missing plus number of "  +
+                                "connected switches that were absent from " +
+                                "the store although this controller has " +
+                                "written them. A non-zero count " +
+                                "indicates a brief split-brain dual MASTER " +
+                                "situation during fail-over",
+                                CounterType.ALWAYS_COUNT);
+
+            storeSyncError =
+                debugCounters.registerCounter(
+                            prefix, "store-sync-error",
+                            "Number of times a sync store operation failed " +
+                            "due to a store sync exception or an entry in " +
+                            "in the store had invalid data.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchesNotReconnectingToNewMaster =
+                debugCounters.registerCounter(
+                            prefix, "switches-not-reconnecting-to-new-master",
+                            "Switches that were connected to another " +
+                            "controller instance in the cluster but that " +
+                            "did not reconnect to this controller after it " +
+                            "transitioned to MASTER", // might be less than warning
+                            CounterType.ALWAYS_COUNT);
+
+            switchPortChanged =
+                debugCounters.registerCounter(
+                            prefix, "switch-port-changed",
+                            "Number of times switch ports have changed",
+                            CounterType.ALWAYS_COUNT);
+            switchOtherChange =
+                debugCounters.registerCounter(
+                            prefix, "switch-other-change",
+                            "Number of times other information of a switch " +
+                            "has changed.",
+                            CounterType.ALWAYS_COUNT);
+
+            dispatchMessageWhileSlave =
+                debugCounters.registerCounter(
+                            prefix, "dispatch-message-while-slave",
+                            "Number of times an OF message was received " +
+                            "and supposed to be dispatched but the " +
+                            "controller was in SLAVE role and the message " +
+                            "was not dispatched",
+                            CounterType.ALWAYS_COUNT);
+
+            dispatchMessage =  // does this cnt make sense? more specific?? per type? count stops?
+                debugCounters.registerCounter(
+                            prefix, "dispatch-message",
+                            "Number of times an OF message was dispatched " +
+                            "to registered modules",
+                            CounterType.ALWAYS_COUNT);
+
+            controllerNodeIpsChanged =
+                debugCounters.registerCounter(
+                            prefix, "controller-nodes-ips-changed",
+                            "IP addresses of controller nodes have changed",
+                            CounterType.ALWAYS_COUNT);
+
+        //------------------------
+        // channel handler counters. Factor them out ??
+            messageReceived =
+                debugCounters.registerCounter(
+                            prefix, "message-received",
+                            "Number of OpenFlow messages received. Some of " +
+                            "these might be throttled",
+                            CounterType.ALWAYS_COUNT);
+            messageInputThrottled =
+                debugCounters.registerCounter(
+                            prefix, "message-input-throttled",
+                            "Number of OpenFlow messages that were " +
+                            "throttled due to high load from the sender",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+        // TODO: more counters in messageReceived ??
+
+            switchDisconnectReadTimeout =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-read-timeout",
+                            "Number of times a switch was disconnected due " +
+                            "due the switch failing to send OpenFlow " +
+                            "messages or responding to OpenFlow ECHOs",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+            switchDisconnectHandshakeTimeout =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-handshake-timeout",
+                            "Number of times a switch was disconnected " +
+                            "because it failed to complete the handshake " +
+                            "in time.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+            switchDisconnectIOError =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-io-error",
+                            "Number of times a switch was disconnected " +
+                            "due to IO errors on the switch connection.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+            switchDisconnectParseError =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-parse-error",
+                           "Number of times a switch was disconnected " +
+                           "because it sent an invalid packet that could " +
+                           "not be parsed",
+                           CounterType.ALWAYS_COUNT,
+                           IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchDisconnectSwitchStateException =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-switch-state-exception",
+                            "Number of times a switch was disconnected " +
+                            "because it sent messages that were invalid " +
+                            "given the switch connection's state.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+            rejectedExecutionException =
+                debugCounters.registerCounter(
+                            prefix, "rejected-execution-exception",
+                            "TODO",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchDisconnectOtherException =
+                debugCounters.registerCounter(
+                            prefix,  "switch-disconnect-other-exception",
+                            "Number of times a switch was disconnected " +
+                            "due to an exceptional situation not covered " +
+                            "by other counters",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchConnected =
+                debugCounters.registerCounter(
+                            prefix, "switch-connected",
+                            "Number of times a new switch connection was " +
+                            "established",
+                            CounterType.ALWAYS_COUNT);
+
+            unhandledMessage =
+                debugCounters.registerCounter(
+                            prefix, "unhandled-message",
+                            "Number of times an OpenFlow message was " +
+                            "received that the controller ignored because " +
+                            "it was inapproriate given the switch " +
+                            "connection's state.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+                            // might be less than warning
+
+            packetInWhileSwitchIsSlave =
+                debugCounters.registerCounter(
+                            prefix, "packet-in-while-switch-is-slave",
+                            "Number of times a packet in was received " +
+                            "from a switch that was in SLAVE role. " +
+                            "Possibly inidicates inconsistent roles.",
+                            CounterType.ALWAYS_COUNT);
+            epermErrorWhileSwitchIsMaster =
+                debugCounters.registerCounter(
+                            prefix, "eperm-error-while-switch-is-master",
+                            "Number of times a permission error was " +
+                            "received while the switch was in MASTER role. " +
+                            "Possibly inidicates inconsistent roles.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            roleNotResentBecauseRolePending =
+                debugCounters.registerCounter(
+                            prefix, "role-not-resent-because-role-pending",
+                            "The controller tried to reestablish a role " +
+                            "with a switch but did not do so because a " +
+                            "previous role request was still pending",
+                            CounterType.ALWAYS_COUNT);
+            roleRequestSent =
+                debugCounters.registerCounter(
+                            prefix, "role-request-sent",
+                            "Number of times the controller sent a role " +
+                            "request to a switch.",
+                            CounterType.ALWAYS_COUNT);
+            roleReplyTimeout =
+                debugCounters.registerCounter(
+                            prefix, "role-reply-timeout",
+                            "Number of times a role request message did not " +
+                            "receive the expected reply from a switch",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            roleReplyReceived = // expected RoleReply received
+                debugCounters.registerCounter(
+                            prefix, "role-reply-received",
+                            "Number of times the controller received the " +
+                            "expected role reply message from a switch",
+                            CounterType.ALWAYS_COUNT);
+
+            roleReplyErrorUnsupported =
+                debugCounters.registerCounter(
+                            prefix, "role-reply-error-unsupported",
+                            "Number of times the controller received an " +
+                            "error from a switch in response to a role " +
+                            "request indicating that the switch does not " +
+                            "support roles.",
+                            CounterType.ALWAYS_COUNT);
+
+            switchCounterRegistrationFailed =
+                debugCounters.registerCounter(prefix,
+                            "switch-counter-registration-failed",
+                            "Number of times the controller failed to " +
+                            "register per-switch debug counters",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+        }
+    }
+
+    private Counters counters;
+
+    Counters getCounters() {
+        return this.counters;
+    }
+
+    /**
+     * A utility class to manage the <i>controller roles</i>.
+     *
+     * A utility class to manage the <i>controller roles</i>  as opposed
+     * to the switch roles. The class manages the controllers current role,
+     * handles role change requests, and maintains the list of connected
+     * switch(-channel) so it can notify the switches of role changes.
+     *
+     * We need to ensure that every connected switch is always send the
+     * correct role. Therefore, switch add, sending of the intial role, and
+     * changing role need to use mutexes to ensure this. This has the ugly
+     * side-effect of requiring calls between controller and OFChannelHandler
+     *
+     * This class is fully thread safe. Its method can safely be called from
+     * any thread.
+     *
+     * @author gregor
+     *
+     */
+    private class RoleManager {
+        // This role represents the role that has been set by setRole. This
+        // role might or might now have been notified to listeners just yet.
+        // This is updated by setRole. doSetRole() will use this value as
+        private Role role;
+        private String roleChangeDescription;
+
+        // The current role info. This is updated /after/ dampening
+        // switches and
+        // listener notifications have been enqueued (but potentially before
+        // they have been dispatched)
+        private RoleInfo currentRoleInfo;
+        private final Set<OFChannelHandler> connectedChannelHandlers;
+
+        /**
+         * @param role initial role
+         * @param roleChangeDescription initial value of the change description
+         * @throws NullPointerException if role or roleChangeDescription is null
+         * @throws IllegalArgumentException if role is EQUAL
+         */
+        public RoleManager(Role role, String roleChangeDescription) {
+            if (role == null)
+                throw new NullPointerException("role must not be null");
+            if (role == Role.EQUAL)
+                throw new IllegalArgumentException("role must not be EQUAL");
+            if (roleChangeDescription == null) {
+                throw new NullPointerException("roleChangeDescription must " +
+                                               "not be null");
+            }
+
+            this.role = role;
+            this.roleChangeDescription = roleChangeDescription;
+            this.connectedChannelHandlers = new HashSet<OFChannelHandler>();
+            this.currentRoleInfo = new RoleInfo(this.role,
+                                           this.roleChangeDescription,
+                                           new Date());
+        }
+
+        /**
+         * Add a newly connected OFChannelHandler. The channel handler is added
+         * we send the current role to the channel handler. All subsequent role
+         * changes will be send to all connected
+         * @param h The OFChannelHandler to add
+         */
+        public synchronized void
+                addOFChannelHandlerAndSendRole(OFChannelHandler h) {
+            connectedChannelHandlers.add(h);
+            h.sendRoleRequest(this.role);
+        }
+
+        /**
+         * Remove OFChannelHandler. E.g., due do disconnect.
+         * @param h The OFChannelHandler to remove.
+         */
+        public synchronized void removeOFChannelHandler(OFChannelHandler h) {
+            connectedChannelHandlers.remove(h);
+        }
+
+        /**
+         * Re-assert a role for the given channel handler.
+         *
+         * The caller specifies the role that should be reasserted. We only
+         * reassert the role if the controller's current role matches the
+         * reasserted role and there is no role request for the reasserted role
+         * pending.
+         * @param h The OFChannelHandler on which we should reassert.
+         * @param role The role to reassert
+         */
+        public synchronized void reassertRole(OFChannelHandler h, Role role) {
+            // check if the requested reassertion actually makes sense
+            if (this.role != role)
+                return;
+            h.sendRoleRequestIfNotPending(this.role);
+        }
+
+        /**
+         * Set the controller's new role and notify switches.
+         *
+         * This method updates the controllers current role and notifies all
+         * connected switches of the new role is different from the current
+         * role. We dampen calls to this method. See class description for
+         * details.
+         *
+         * @param role The new role.
+         * @param roleChangeDescription A textual description of why the role
+         * was changed. For information purposes only.
+         * @throws NullPointerException if role or roleChangeDescription is null
+         */
+        public synchronized void setRole(Role role, String roleChangeDescription) {
+            if (role == null)
+                throw new NullPointerException("role must not be null");
+            if (roleChangeDescription == null) {
+                throw new NullPointerException("roleChangeDescription must " +
+                                               "not be null");
+            }
+            if (role == Role.EQUAL) {
+                counters.setRoleEqual.updateCounterWithFlush();
+                log.debug("Received role request for EQUAL, setting to MASTER"
+                          + " instead");
+                role = Role.MASTER;
+            }
+            if (role == this.role) {
+                counters.setSameRole.updateCounterWithFlush();
+                log.debug("Received role request for {} but controller is "
+                        + "already {}. Ignoring it.", role, this.role);
+                return;
+            }
+            if (this.role == Role.MASTER && role == Role.SLAVE) {
+                log.info("Received role request to transition from MASTER to "
+                          + " SLAVE (reason: {}). Terminating floodlight.",
+                          roleChangeDescription);
+                System.exit(0);
+            }
+
+            // At this point we are guaranteed that we will execute the code
+            // below exactly once during the lifetime of this process! And
+            // it will be a to MASTER transition
+            counters.setRoleMaster.updateCounterWithFlush();
+            log.info("Received role request for {} (reason: {})."
+                     + " Initiating transition", role, roleChangeDescription);
+
+            this.role = role;
+            this.roleChangeDescription = roleChangeDescription;
+
+            // TODO: we currently notify switches synchronously from the REST
+            // API handler. We could (should?) do this asynchronously.
+            currentRoleInfo = new RoleInfo(this.role,
+                                           this.roleChangeDescription,
+                                           new Date());
+            Controller.this.switchManager.setRole(this.role);
+            for (OFChannelHandler h: connectedChannelHandlers)
+                h.sendRoleRequest(this.role);
+
+            Controller.this.addUpdateToQueue(new HARoleUpdate(this.role));
+        }
+
+        /**
+         * Return the RoleInfo object describing the current role.
+         *
+         * Return the RoleInfo object describing the current role. The
+         * RoleInfo object is used by REST API users. We need to return
+         * a defensive copy.
+         * @return the current RoleInfo object
+         */
+        public synchronized RoleInfo getRoleInfo() {
+            return new RoleInfo(currentRoleInfo);
+        }
+    }
+
+
+    /**
+     * This is a utility class to encapsulate code that deals with switch
+     * life cycles. It interacts with the sync store to read/write switches
+     * to/from the store and it maintains the switch maps.
+     * @author gregor
+     *
+     */
+    private class SwitchManager implements IStoreListener<Long> {
+        private Role role;
+        private final ConcurrentHashMap<Long,IOFSwitch> activeSwitches;
+        private final ConcurrentHashMap<Long,IOFSwitch> syncedSwitches;
+
+        public SwitchManager(Role role) {
+            this.role = role;
+            this.activeSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
+            this.syncedSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
+       }
+
+        @Override
+        public void keysModified(Iterator<Long> keys, UpdateType type) {
+            if (type == UpdateType.LOCAL) {
+                // We only care for remote updates
+                return;
+            }
+            counters.remoteStoreNotification.updateCounterWithFlush();
+            while(keys.hasNext()) {
+                Long key = keys.next();
+                Versioned<SwitchSyncRepresentation> versionedSwitch = null;
+                try {
+                    versionedSwitch = storeClient.get(key);
+                } catch (SyncException e) {
+                    counters.storeSyncError.updateCounterWithFlush();
+                    log.error("Exception while retrieving switch " +
+                              HexString.toHexString(key) +
+                              " from sync store. Skipping", e);
+                    continue;
+                }
+                if (log.isTraceEnabled()) {
+                    log.trace("Reveiced switch store notification: key={}, " +
+                               "entry={}", key, versionedSwitch.getValue());
+                }
+                // versionedSwtich won't be null. storeClient.get() always
+                // returns a non-null or throws an exception
+                if (versionedSwitch.getValue() == null) {
+                    switchRemovedFromStore(key);
+                    continue;
+                }
+                SwitchSyncRepresentation storedSwitch =
+                        versionedSwitch.getValue();
+                IOFSwitch sw = getOFSwitchInstance(storedSwitch.getDescription());
+                sw.setFeaturesReply(storedSwitch.getFeaturesReply());
+                if (!key.equals(storedSwitch.getFeaturesReply().getDatapathId())) {
+                    counters.storeSyncError.updateCounterWithFlush();
+                    log.error("Inconsistent DPIDs from switch sync store: " +
+                              "key is {} but sw.getId() says {}. Ignoring",
+                              HexString.toHexString(key), sw.getStringId());
+                    continue;
+                }
+                switchAddedToStore(sw);
+            }
+        }
+
+
+        public synchronized void setRole(Role role) {
+            this.role = role;
+            Runnable consolidateStoreTask = new Runnable() {
+                @Override
+                public void run() {
+                    consolidateStore();
+                }
+            };
+            if ((role == Role.MASTER) &&
+                    this.syncedSwitches.isEmpty())
+                addUpdateToQueue(new ReadyForReconcileUpdate());
+
+            Controller.this.ses.schedule(consolidateStoreTask,
+                                         consolidateStoreTimeDelayMs,
+                                         TimeUnit.MILLISECONDS);
+        }
+
+        @LogMessageDocs({
+        @LogMessageDoc(level="ERROR",
+                message="Switch {switch} activated but was already active",
+                explanation="A switch that was already activated was " +
+                            "activated again. This should not happen.",
+                recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG
+                ),
+        @LogMessageDoc(level="WARN",
+                message="New switch added {switch} for already-added switch {switch}",
+                explanation="A switch with the same DPID as another switch " +
+                        "connected to the controller.  This can be caused by " +
+                        "multiple switches configured with the same DPID, or " +
+                        "by a switch reconnected very quickly after " +
+                        "disconnecting.",
+                recommendation="If this happens repeatedly, it is likely there " +
+                        "are switches with duplicate DPIDs on the network.  " +
+                        "Reconfigure the appropriate switches.  If it happens " +
+                        "very rarely, then it is likely this is a transient " +
+                        "network problem that can be ignored."
+                )
+        })
+        /**
+         * Called when a switch is activated, i.e., when it enters master
+         * role relative to this controller.
+         * @param sw
+         */
+        public synchronized void switchActivated(IOFSwitch sw) {
+            if (role != Role.MASTER) {
+                counters.invalidSwitchActivatedWhileSlave.updateCounterWithFlush();
+                return; // only react to switch connections when master
+                // FIXME: should we disconnect the switch? When can this happen?
+            }
+            Long dpid = sw.getId();
+            counters.switchActivated.updateCounterWithFlush();
+            IOFSwitch oldSw = this.activeSwitches.put(dpid, sw);
+            // Update event history
+            evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "connected"));
+
+            if (oldSw == sw)  {
+                // Note == for object equality, not .equals for value
+                // TODO: should we wipe the flow table if
+                // alwaysClearFlowsOnSwAdd is set? OTOH this case should
+                // really never happen.
+                counters.errorSameSwitchReactivated.updateCounterWithFlush();
+                log.error("Switch {} activated but was already active", sw);
+                addSwitchToStore(sw);
+                return;
+            }
+
+            if (oldSw != null) {
+                // This happens either when we have switches with duplicate
+                // DPIDs or when a switch reconnects before we saw the
+                // disconnect
+                counters.switchWithSameDpidActivated.updateCounterWithFlush();
+                log.warn("New switch added {} for already-added switch {}",
+                          sw, oldSw);
+                // We need to disconnect and remove the old switch
+                // TODO: we notify switch listeners that the switch has been
+                // removed and then we notify them that the new one has been
+                // added. One could argue that a switchChanged notification
+                // might be more appropriate in this case....
+                oldSw.cancelAllStatisticsReplies();
+                addUpdateToQueue(new SwitchUpdate(dpid,
+                                                  SwitchUpdateType.REMOVED));
+                oldSw.disconnectOutputStream();
+                // Add the new switch and clear FlowMods
+                // TODO: if this is the same switch re-connecting rather than
+                // a DPID collision it would make sense to not wipe the flow
+                // table.
+                sw.clearAllFlowMods();
+                addUpdateToQueue(new SwitchUpdate(dpid,
+                                                  SwitchUpdateType.ADDED));
+                addUpdateToQueue(new SwitchUpdate(dpid,
+                                                  SwitchUpdateType.ACTIVATED));
+                addSwitchToStore(sw);
+                return;
+            }
+
+            IOFSwitch storedSwitch = this.syncedSwitches.remove(sw.getId());
+            if (storedSwitch == null) {
+                // The switch isn't known to the controller cluster. We
+                // need to send a switchAdded notification and clear all
+                // flows.
+                if (!swConnectCache.update(sw.getId()))
+                    sw.clearAllFlowMods();
+                addUpdateToQueue(new SwitchUpdate(dpid,
+                                                  SwitchUpdateType.ADDED));
+                addUpdateToQueue(new SwitchUpdate(dpid,
+                                                  SwitchUpdateType.ACTIVATED));
+                counters.newSwitchActivated.updateCounterWithFlush();
+            } else {
+                // FIXME: switch was in store. check if ports or anything else
+                // has changed and send update.
+                if (alwaysClearFlowsOnSwActivate) {
+                    sw.clearAllFlowMods();
+                }
+                if (sw.attributeEquals(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true)) {
+                    // We have a stored switch and the newly activated switch
+                    // supports roles. This indicates that the switch was
+                    // previously connected as slave. Since we don't update
+                    // ports while slave, we need to set the ports on the
+                    // new switch from the ports on the stored switch
+                    // No need to send notifications, since we've dispatched
+                    // them as we receive them from the store
+                    sw.setPorts(storedSwitch.getPorts());
+                }
+                addUpdateToQueue(new SwitchUpdate(dpid,
+                                                  SwitchUpdateType.ACTIVATED));
+                sendNotificationsIfSwitchDiffers(storedSwitch, sw);
+                counters.syncedSwitchActivated.updateCounterWithFlush();
+                if (this.syncedSwitches.isEmpty()) {
+                    // we have just activated the last synced switch. I.e.,
+                    // all previously known switch are now active. Send
+                    // notification
+                    // update dispatcher will increment counter
+                    addUpdateToQueue(new ReadyForReconcileUpdate());
+                }
+            }
+            addSwitchToStore(sw);
+        }
+
+        /**
+         * Called when ports on the given switch have changed. Writes the
+         * updated switch to the sync store and queues a switch notification
+         * to listeners
+         * @param sw
+         */
+        public synchronized void switchPortsChanged(IOFSwitch sw,
+                                                    ImmutablePort port,
+                                                    PortChangeType type) {
+            if (role != Role.MASTER) {
+                counters.invalidPortsChanged.updateCounterWithFlush();
+                return;
+            }
+            if (!this.activeSwitches.containsKey(sw.getId())) {
+                counters.invalidPortsChanged.updateCounterWithFlush();
+                return;
+            }
+            // update switch in store
+            addSwitchToStore(sw);
+            // no need to count here. SwitchUpdate.dispatch will count
+            // the portchanged
+            SwitchUpdate update = new SwitchUpdate(sw.getId(),
+                                                   SwitchUpdateType.PORTCHANGED,
+                                                   port, type);
+            addUpdateToQueue(update);
+        }
+
+        /**
+         * Called when we receive a store notification about a new or updated
+         * switch.
+         * @param sw
+         */
+        private synchronized void switchAddedToStore(IOFSwitch sw) {
+            if (role != Role.SLAVE) {
+                counters.invalidStoreEventWhileMaster.updateCounterWithFlush();
+                return; // only read from store if slave
+            }
+            Long dpid = sw.getId();
+
+            IOFSwitch oldSw = syncedSwitches.put(dpid, sw);
+            if (oldSw == null)  {
+                counters.newSwitchFromStore.updateCounterWithFlush();
+                addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.ADDED));
+            } else {
+                // The switch already exists in storage, see if anything
+                // has changed
+                sendNotificationsIfSwitchDiffers(oldSw, sw);
+                counters.updatedSwitchFromStore.updateCounterWithFlush();
+            }
+        }
+
+        /**
+         * Called when we receive a store notification about a switch that
+         * has been removed from the sync store
+         * @param dpid
+         */
+        private synchronized void switchRemovedFromStore(long dpid) {
+            if (role != Role.SLAVE) {
+                counters.invalidStoreEventWhileMaster.updateCounterWithFlush();
+                return; // only read from store if slave
+            }
+            IOFSwitch oldSw = syncedSwitches.remove(dpid);
+            if (oldSw != null) {
+                counters.syncedSwitchRemoved.updateCounterWithFlush();
+                addUpdateToQueue(new SwitchUpdate(dpid,
+                                                  SwitchUpdateType.REMOVED));
+            } else {
+                // TODO: the switch was deleted (tombstone) before we ever
+                // knew about it (or was deleted repeatedly). Can this
+                // happen? When/how?
+                counters.unknownSwitchRemovedFromStore.updateCounterWithFlush();
+            }
+        }
+
+        public synchronized void switchDeactivated(IOFSwitch sw) {
+            // ignore. we don't handle MASTER -> SLAVE transitions. We
+            // expect a restart
+        }
+
+        /**
+         * Called when a switch disconnects
+         * @param sw
+         */
+        public synchronized void switchDisconnected(IOFSwitch sw) {
+            if (role == Role.SLAVE) {
+                counters.switchDisconnectedWhileSlave.updateCounterWithFlush();
+                return; // only react to switch connections when master
+            }
+            long dpid = sw.getId();
+            // Update event history
+            // TODO: this is asymmetric with respect to connect event
+            //       in switchActivated(). Should we have events on the
+            //       slave as well?
+            evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "disconnected"));
+            counters.switchDisconnected.updateCounterWithFlush();
+            IOFSwitch oldSw = this.activeSwitches.get(dpid);
+            if (oldSw != sw) {
+                // This can happen if the disconnected switch was inactive
+                // (SLAVE) then oldSw==null. Or if we previously had the
+                // "added switch for already added switch case".
+                // Either way we shouldn't notify or do anything else
+                log.debug("removeSwitch called for switch {} but have {} in"
+                          + " activeSwitches map. Ignoring", sw, oldSw);
+                return;
+            }
+            log.debug("removeSwitch {}", sw);
+            swConnectCache.update(sw.getId());
+            this.activeSwitches.remove(sw.getId());
+            removeSwitchFromStore(sw.getId());
+            // We cancel all outstanding statistics replies if the switch transition
+            // from active. In the future we might allow statistics requests
+            // from slave controllers. Then we need to move this cancelation
+            // to switch disconnect
+            sw.cancelAllStatisticsReplies();
+            addUpdateToQueue(new SwitchUpdate(sw.getId(),
+                                              SwitchUpdateType.REMOVED));
+        }
+
+        /**
+         * Write the given switch to the sync store.
+         * @param sw
+         */
+        private synchronized void addSwitchToStore(IOFSwitch sw) {
+            // Add to store
+            // FIXME: do we need to use a put that takes a versioned here?
+            // need to verify
+            try {
+                storeClient.put(sw.getId(), new SwitchSyncRepresentation(sw));
+            } catch (ObsoleteVersionException e) {
+                // FIXME: what's the right behavior here. Can the store client
+                // even throw this error? Should not since all local store
+                // access is synchronized
+            } catch (SyncException e) {
+                counters.storeSyncError.updateCounterWithFlush();
+                log.error("Could not write switch " + sw.getStringId() +
+                          " to sync store:", e);
+            }
+        }
+
+        /**
+         * Write the given switch to the sync store if it's not already
+         * there
+         * TODO: should this be merged with addSwitchToStore
+         * @param sw
+         * @return true if the switch was absent, false otherwise
+         */
+        private synchronized boolean addSwitchToStoreIfAbsent(IOFSwitch sw) {
+            try {
+                Versioned<SwitchSyncRepresentation> versionedSSr =
+                        storeClient.get(sw.getId());
+                if (versionedSSr.getValue() == null) {
+                    // switch is absent
+                    versionedSSr.setValue(new SwitchSyncRepresentation(sw));
+                    storeClient.put(sw.getId(), versionedSSr);
+                    return true;
+                } else {
+                    return false;
+                }
+            } catch (ObsoleteVersionException e) {
+                // FIXME: what's the right behavior here. Can the store client
+                // even throw this error? Should not since all local store
+                // access is synchronized
+            } catch (SyncException e) {
+                counters.storeSyncError.updateCounterWithFlush();
+                log.error("Could not write switch " + sw.getStringId() +
+                          " to sync store:", e);
+            }
+            return false;
+        }
+
+        /**
+         * Remove the given switch from the sync store.
+         * @param dpid
+         */
+        private synchronized void removeSwitchFromStore(long dpid) {
+            try {
+                storeClient.delete(dpid);
+            } catch (SyncException e) {
+                counters.storeSyncError.updateCounterWithFlush();
+                // ObsoleteVerisonException can't happend because all
+                // store modifications are synchronized
+                log.error("Could not remove switch " +
+                          HexString.toHexString(dpid) +
+                          " from sync store:", e);
+            }
+        }
+
+        /**
+         * Check if the two switches differ in their ports or in other
+         * fields and if they differ enqueue a switch update
+         * @param oldSw
+         * @param newSw
+         */
+        private synchronized void
+                sendNotificationsIfSwitchDiffers(IOFSwitch oldSw,
+                                                 IOFSwitch newSw) {
+            Collection<PortChangeEvent> portDiffs =
+                    oldSw.comparePorts(newSw.getPorts());
+            for (PortChangeEvent ev: portDiffs) {
+                SwitchUpdate update =
+                        new SwitchUpdate(newSw.getId(),
+                                         SwitchUpdateType.PORTCHANGED,
+                                         ev.port, ev.type);
+                addUpdateToQueue(update);
+            }
+        }
+        /**
+         * Remove all entries from the store that don't correspond to an
+         * active switch.
+         * TODO: is it a problem that this is fully synchronized
+         */
+        private synchronized void consolidateStore() {
+            if (role == Role.SLAVE)
+                return;
+            boolean shouldNotifyReadyForReconcile = false;
+            counters.consolidateStoreRunCount.updateCounterWithFlush();
+            log.info("Consolidating synced switches after MASTER transition");
+            IClosableIterator<Map.Entry<Long,Versioned<SwitchSyncRepresentation>>>
+                    iter = null;
+            try {
+                iter = storeClient.entries();
+            } catch (SyncException e) {
+                counters.storeSyncError.updateCounterWithFlush();
+                log.error("Failed to read switches from sync store", e);
+                return;
+            }
+            try {
+                while(iter.hasNext()) {
+                    Entry<Long, Versioned<SwitchSyncRepresentation>> entry =
+                            iter.next();
+                    if (!this.activeSwitches.containsKey(entry.getKey())) {
+                        removeSwitchFromStore(entry.getKey());
+                        if (this.syncedSwitches.remove(entry.getKey()) != null) {
+                            // a switch that's in the store and in synced
+                            // switches but that is not active. I.e., a
+                            // switch known to the old master that hasn't
+                            // reconnected to this controller.
+                            counters.switchesNotReconnectingToNewMaster
+                                    .updateCounterWithFlush();
+                            shouldNotifyReadyForReconcile = true;
+                            addUpdateToQueue(new SwitchUpdate(entry.getKey(),
+                                                     SwitchUpdateType.REMOVED));
+                        } else {
+                            // A switch was in the store but it's neither in
+                            // activeSwitches nor syncedSwitches. This could
+                            // happen if the old Master has added this entry
+                            // to the store after this controller has
+                            // stopped reacting to store notifications (due
+                            // to MASTER transition)
+                            counters.consolidateStoreInconsistencies
+                                    .updateCounterWithFlush();
+                        }
+                    }
+                }
+            } finally {
+                if (iter != null)
+                    iter.close();
+            }
+            // In general, syncedSwitches should now be empty. However,
+            // the old Master could have removed a switch from the store
+            // after this controller has stopped reacting to store
+            // notification (because it's now MASTER). We need to remove
+            // these switches.
+            Iterator<Long> it = this.syncedSwitches.keySet().iterator();
+            while (it.hasNext()) {
+                counters.switchesNotReconnectingToNewMaster.updateCounterWithFlush();
+                counters.consolidateStoreInconsistencies.updateCounterWithFlush();
+                Long dpid = it.next();
+                shouldNotifyReadyForReconcile = true;
+                addUpdateToQueue(new SwitchUpdate(dpid,
+                                                  SwitchUpdateType.REMOVED));
+                it.remove();
+            }
+            if (shouldNotifyReadyForReconcile) {
+                // at least one previously known switch has been removed.
+                addUpdateToQueue(new ReadyForReconcileUpdate());
+            }
+
+            // FIXME: do we need this final check here.
+            // Now iterate through all active switches and determine if
+            // any of them are missing from the sync store. This can only
+            // happen if another controller has removed them (because we know
+            // that we have written them to the store).
+            for (IOFSwitch sw: this.activeSwitches.values()) {
+                if (addSwitchToStoreIfAbsent(sw))
+                    counters.consolidateStoreInconsistencies.updateCounterWithFlush();
+            }
+        }
+
+        // FIXME: remove this method
+        public Map<Long,IOFSwitch> getAllSwitchMap() {
+            // this.syncedSwitches will be empty after the master transition
+            Map<Long,IOFSwitch> switches =
+                    new HashMap<Long, IOFSwitch>(this.syncedSwitches);
+            if (this.role != Role.SLAVE)
+                switches.putAll(this.activeSwitches);
+            return switches;
+        }
+
+        public Set<Long> getAllSwitchDpids() {
+            // this.syncedSwitches will be empty after the master transition
+            Set<Long> dpids = new HashSet<Long>(this.syncedSwitches.keySet());
+            if (this.role != Role.SLAVE)
+                dpids.addAll(this.activeSwitches.keySet());
+            return dpids;
+        }
+
+        public IOFSwitch getSwitch(long dpid) {
+            if (this.role == Role.SLAVE)
+                return this.syncedSwitches.get(dpid);
+            // MASTER: if the switch is found in the active map return
+            // otherwise look up the switch in the bigSync map. The bigSync map
+            // wil be cleared after the transition is complete.
+            IOFSwitch sw = this.activeSwitches.get(dpid);
+            if (sw != null)
+                return sw;
+            return this.syncedSwitches.get(dpid);
+        }
+
+        public void addSwitchEvent(long dpid, String reason, boolean flushNow) {
+            if (flushNow)
+                evSwitch.updateEventWithFlush(new SwitchEvent(dpid, reason));
+            else
+                evSwitch.updateEventNoFlush(new SwitchEvent(dpid, reason));
+        }
+
+    }
+
+
+    /**
+     *  Updates handled by the main loop
+     */
+    interface IUpdate {
+        /**
+         * Calls the appropriate listeners
+         */
+        public void dispatch();
+    }
+
+    /**
+     * Update message that indicates that the controller can now start
+     * flow reconciliation after a SLAVE->MASTER transition
+     */
+    private class ReadyForReconcileUpdate implements IUpdate {
+        @Override
+        public void dispatch() {
+            counters.readyForReconcile.updateCounterWithFlush();
+            if (readyForReconcileListeners != null) {
+                for (IReadyForReconcileListener listener:
+                        readyForReconcileListeners) {
+                    listener.readyForReconcile();
+                }
+            }
+        }
+    }
+
+    enum SwitchUpdateType {
+        ADDED,
+        REMOVED,
+        ACTIVATED,
+        DEACTIVATED,
+        PORTCHANGED,
+        OTHERCHANGE
+    }
+    /**
+     * Update message indicating a switch was added or removed
+     */
+    private class SwitchUpdate implements IUpdate {
+        private final long swId;
+        private final SwitchUpdateType switchUpdateType;
+        private final ImmutablePort port;
+        private final PortChangeType changeType;
+
+
+        public SwitchUpdate(long swId, SwitchUpdateType switchUpdateType) {
+            this(swId, switchUpdateType, null, null);
+        }
+        public SwitchUpdate(long swId,
+                            SwitchUpdateType switchUpdateType,
+                            ImmutablePort port,
+                            PortChangeType changeType) {
+            if (switchUpdateType == SwitchUpdateType.PORTCHANGED) {
+                if (port == null) {
+                    throw new NullPointerException("Port must not be null " +
+                            "for PORTCHANGED updates");
+                }
+                if (changeType == null) {
+                    throw new NullPointerException("ChangeType must not be " +
+                            "null for PORTCHANGED updates");
+                }
+            } else {
+                if (port != null || changeType != null) {
+                    throw new IllegalArgumentException("port and changeType " +
+                            "must be null for " + switchUpdateType +
+                            " updates");
+                }
+            }
+            this.swId = swId;
+            this.switchUpdateType = switchUpdateType;
+            this.port = port;
+            this.changeType = changeType;
+        }
+        @Override
+        public void dispatch() {
+            if (log.isTraceEnabled()) {
+                log.trace("Dispatching switch update {} {}",
+                        HexString.toHexString(swId), switchUpdateType);
+            }
+            if (switchListeners != null) {
+                for (IOFSwitchListener listener : switchListeners) {
+                    switch(switchUpdateType) {
+                        case ADDED:
+                            // don't count here. We have more specific
+                            // counters before the update is created
+                            listener.switchAdded(swId);
+                            break;
+                        case REMOVED:
+                            // don't count here. We have more specific
+                            // counters before the update is created
+                            listener.switchRemoved(swId);
+                            break;
+                        case PORTCHANGED:
+                            counters.switchPortChanged.updateCounterWithFlush();
+                            listener.switchPortChanged(swId, port, changeType);
+                            break;
+                        case ACTIVATED:
+                            // don't count here. We have more specific
+                            // counters before the update is created
+                            listener.switchActivated(swId);
+                            break;
+                        case DEACTIVATED:
+                            // ignore
+                            break;
+                        case OTHERCHANGE:
+                            counters.switchOtherChange.updateCounterWithFlush();
+                            listener.switchChanged(swId);
+                            break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Update message indicating controller's role has changed.
+     * RoleManager, which enqueues these updates gurantees that we will
+     * only have a single transition from SLAVE to MASTER.
+     */
+    private class HARoleUpdate implements IUpdate {
+        private final Role newRole;
+        public HARoleUpdate(Role newRole) {
+            if (newRole != Role.MASTER)
+                throw new IllegalArgumentException("Only legal role change is"
+                                                   + "to MASTER. Got to "
+                                                   + newRole);
+            this.newRole = newRole;
+        }
+        @Override
+        public void dispatch() {
+            if (log.isDebugEnabled()) {
+                log.debug("Dispatching HA Role update newRole = {}",
+                          newRole);
+            }
+            for (IHAListener listener : haListeners.getOrderedListeners()) {
+                if (log.isTraceEnabled()) {
+                    log.trace("Calling HAListener {} with transitionToMaster",
+                              listener.getName());
+                }
+                listener.transitionToMaster();
+            }
+            if (newRole != Role.SLAVE) {
+                Controller.this.notifiedRole = newRole;
+            }
+        }
+    }
+
+    /**
+     * Update message indicating
+     * IPs of controllers in controller cluster have changed.
+     */
+    private class HAControllerNodeIPUpdate implements IUpdate {
+        public final Map<String,String> curControllerNodeIPs;
+        public final Map<String,String> addedControllerNodeIPs;
+        public final Map<String,String> removedControllerNodeIPs;
+        public HAControllerNodeIPUpdate(
+                HashMap<String,String> curControllerNodeIPs,
+                HashMap<String,String> addedControllerNodeIPs,
+                HashMap<String,String> removedControllerNodeIPs) {
+            this.curControllerNodeIPs = curControllerNodeIPs;
+            this.addedControllerNodeIPs = addedControllerNodeIPs;
+            this.removedControllerNodeIPs = removedControllerNodeIPs;
+        }
+        @Override
+        public void dispatch() {
+            if (log.isTraceEnabled()) {
+                log.trace("Dispatching HA Controller Node IP update "
+                        + "curIPs = {}, addedIPs = {}, removedIPs = {}",
+                        new Object[] { curControllerNodeIPs, addedControllerNodeIPs,
+                            removedControllerNodeIPs }
+                        );
+            }
+            if (haListeners != null) {
+                for (IHAListener listener: haListeners.getOrderedListeners()) {
+                    listener.controllerNodeIPsChanged(curControllerNodeIPs,
+                            addedControllerNodeIPs, removedControllerNodeIPs);
+                }
+            }
+        }
+    }
+
+    // ***************
+    // Getters/Setters
+    // ***************
+
+    void setStorageSourceService(IStorageSourceService storageSource) {
+        this.storageSource = storageSource;
+    }
+
+    IStorageSourceService getStorageSourceService() {
+        return this.storageSource;
+    }
+
+    void setCounterStore(ICounterStoreService counterStore) {
+        this.counterStore = counterStore;
+    }
+
+    void setDebugCounter(IDebugCounterService debugCounters) {
+        this.debugCounters = debugCounters;
+    }
+
+    public void setDebugEvent(IDebugEventService debugEvent) {
+        this.debugEvents = debugEvent;
+    }
+
+    IDebugCounterService getDebugCounter() {
+        return this.debugCounters;
+    }
+
+    void setSyncService(ISyncService syncService) {
+        this.syncService = syncService;
+    }
+    void setPktInProcessingService(IPktInProcessingTimeService pits) {
+        this.pktinProcTime = pits;
+    }
+
+    void setRestApiService(IRestApiService restApi) {
+        this.restApi = restApi;
+    }
+
+    void setThreadPoolService(IThreadPoolService tp) {
+        this.threadPool = tp;
+    }
+
+    IThreadPoolService getThreadPoolService() {
+        return this.threadPool;
+    }
+
+    @Override
+    public Role getRole() {
+        // FIXME:
+        return notifiedRole;
+    }
+
+    @Override
+    public RoleInfo getRoleInfo() {
+        return roleManager.getRoleInfo();
+    }
+
+    @Override
+    public void setRole(Role role, String roleChangeDescription) {
+        roleManager.setRole(role, roleChangeDescription);
+    }
+
+    // ****************
+    // Message handlers
+    // ****************
+
+    /**
+     * Indicates that ports on the given switch have changed. Enqueue a
+     * switch update.
+     * @param sw
+     */
+     void notifyPortChanged(IOFSwitch sw,
+                            ImmutablePort port,
+                            PortChangeType changeType) {
+         if (sw == null) {
+             String msg = String.format("Switch must not be null. " +
+                     "port=%s, changeType=%s", port, changeType);
+             throw new NullPointerException(msg);
+         }
+         if (port == null) {
+             String msg = String.format("Port must not be null. " +
+                     "switch=%s, changeType=%s", sw, changeType);
+             throw new NullPointerException(msg);
+         }
+         if (changeType == null) {
+             String msg = String.format("ChangeType must not be null. " +
+                     "switch=%s, port=%s", sw, port);
+             throw new NullPointerException(msg);
+         }
+         this.switchManager.switchPortsChanged(sw, port, changeType);
+     }
+
+    /**
+     * flcontext_cache - Keep a thread local stack of contexts
+     */
+    protected static final ThreadLocal<Stack<FloodlightContext>> flcontext_cache =
+        new ThreadLocal <Stack<FloodlightContext>> () {
+            @Override
+            protected Stack<FloodlightContext> initialValue() {
+                return new Stack<FloodlightContext>();
+            }
+        };
+
+    /**
+     * flcontext_alloc - pop a context off the stack, if required create a new one
+     * @return FloodlightContext
+     */
+    protected static FloodlightContext flcontext_alloc() {
+        FloodlightContext flcontext = null;
+
+        if (flcontext_cache.get().empty()) {
+            flcontext = new FloodlightContext();
+        }
+        else {
+            flcontext = flcontext_cache.get().pop();
+        }
+
+        return flcontext;
+    }
+
+    /**
+     * flcontext_free - Free the context to the current thread
+     * @param flcontext
+     */
+    protected void flcontext_free(FloodlightContext flcontext) {
+        flcontext.getStorage().clear();
+        flcontext_cache.get().push(flcontext);
+    }
+
+
+    /**
+     *
+     * Handle and dispatch a message to IOFMessageListeners.
+     *
+     * We only dispatch messages to listeners if the controller's role is MASTER.
+     *
+     * @param sw The switch sending the message
+     * @param m The message the switch sent
+     * @param flContext The floodlight context to use for this message. If
+     * null, a new context will be allocated.
+     * @throws IOException
+     *
+     * FIXME: this method and the ChannelHandler disagree on which messages
+     * should be dispatched and which shouldn't
+     */
+    @LogMessageDocs({
+        @LogMessageDoc(level="ERROR",
+                message="Ignoring PacketIn (Xid = {xid}) because the data" +
+                        " field is empty.",
+                explanation="The switch sent an improperly-formatted PacketIn" +
+                        " message",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="WARN",
+                message="Unhandled OF Message: {} from {}",
+                explanation="The switch sent a message not handled by " +
+                        "the controller")
+    })
+    protected void handleMessage(IOFSwitch sw, OFMessage m,
+                                 FloodlightContext bContext)
+            throws IOException {
+        Ethernet eth = null;
+
+        if (this.notifiedRole == Role.SLAVE) {
+            counters.dispatchMessageWhileSlave.updateCounterNoFlush();
+            // We are SLAVE. Do not dispatch messages to listeners.
+            return;
+        }
+        counters.dispatchMessage.updateCounterNoFlush();
+
+        switch (m.getType()) {
+            case PACKET_IN:
+                OFPacketIn pi = (OFPacketIn)m;
+
+                if (pi.getPacketData().length <= 0) {
+                    log.error("Ignoring PacketIn (Xid = " + pi.getXid() +
+                              ") because the data field is empty.");
+                    return;
+                }
+
+                if (Controller.ALWAYS_DECODE_ETH) {
+                    eth = new Ethernet();
+                    eth.deserialize(pi.getPacketData(), 0,
+                            pi.getPacketData().length);
+                    counterStore.updatePacketInCountersLocal(sw, m, eth);
+                }
+                // fall through to default case...
+
+            default:
+
+                List<IOFMessageListener> listeners = null;
+                if (messageListeners.containsKey(m.getType())) {
+                    listeners = messageListeners.get(m.getType()).
+                            getOrderedListeners();
+                }
+
+                FloodlightContext bc = null;
+                if (listeners != null) {
+                    // Check if floodlight context is passed from the calling
+                    // function, if so use that floodlight context, otherwise
+                    // allocate one
+                    if (bContext == null) {
+                        bc = flcontext_alloc();
+                    } else {
+                        bc = bContext;
+                    }
+                    if (eth != null) {
+                        IFloodlightProviderService.bcStore.put(bc,
+                                IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
+                                eth);
+                    }
+
+                    // Get the starting time (overall and per-component) of
+                    // the processing chain for this packet if performance
+                    // monitoring is turned on
+                    pktinProcTime.recordStartTimePktIn();
+                    Command cmd;
+                    for (IOFMessageListener listener : listeners) {
+                        pktinProcTime.recordStartTimeComp(listener);
+                        cmd = listener.receive(sw, m, bc);
+                        pktinProcTime.recordEndTimeComp(listener);
+
+                        if (Command.STOP.equals(cmd)) {
+                            break;
+                        }
+                    }
+                    pktinProcTime.recordEndTimePktIn(sw, m, bc);
+                } else {
+                    if (m.getType() != OFType.BARRIER_REPLY)
+                        log.warn("Unhandled OF Message: {} from {}", m, sw);
+                    else
+                        log.debug("Received a Barrier Reply, no listeners for it");
+                }
+
+                if ((bContext == null) && (bc != null)) flcontext_free(bc);
+        }
+    }
+
+    void switchActivated(IOFSwitch sw) {
+        this.switchManager.switchActivated(sw);
+    }
+
+    void switchDeactivated(IOFSwitch sw) {
+        this.switchManager.switchDeactivated(sw);
+    }
+
+    void switchDisconnected(IOFSwitch sw) {
+        this.switchManager.switchDisconnected(sw);
+    }
+
+    // ***************
+    // IFloodlightProvider
+    // ***************
+
+    /**
+     * Forward to RoleManager
+     * @param h
+     */
+    void addSwitchChannelAndSendInitialRole(OFChannelHandler h) {
+        roleManager.addOFChannelHandlerAndSendRole(h);
+    }
+
+    /**
+     * Forwards to RoleManager
+     * @param h
+     */
+    void removeSwitchChannel(OFChannelHandler h) {
+        roleManager.removeOFChannelHandler(h);
+    }
+
+    /**
+     * Forwards to RoleManager
+     * @param h
+     * @param role
+     */
+    void reassertRole(OFChannelHandler h, Role role) {
+        roleManager.reassertRole(h, role);
+    }
+
+    // FIXME: remove this method
+    @Override
+    public Map<Long,IOFSwitch> getAllSwitchMap() {
+        return this.switchManager.getAllSwitchMap();
+    }
+
+    @Override
+    public Set<Long> getAllSwitchDpids() {
+        return this.switchManager.getAllSwitchDpids();
+    }
+
+    @Override
+    public IOFSwitch getSwitch(long dpid) {
+        return this.switchManager.getSwitch(dpid);
+    }
+
+    @Override
+    public void addOFSwitchListener(IOFSwitchListener listener) {
+        this.switchListeners.add(listener);
+    }
+
+    @Override
+    public void removeOFSwitchListener(IOFSwitchListener listener) {
+        this.switchListeners.remove(listener);
+    }
+
+    @Override
+    public synchronized void addOFMessageListener(OFType type,
+                                                  IOFMessageListener listener) {
+        ListenerDispatcher<OFType, IOFMessageListener> ldd =
+            messageListeners.get(type);
+        if (ldd == null) {
+            ldd = new ListenerDispatcher<OFType, IOFMessageListener>();
+            messageListeners.put(type, ldd);
+        }
+        ldd.addListener(type, listener);
+    }
+
+    @Override
+    public synchronized void removeOFMessageListener(OFType type,
+                                                     IOFMessageListener listener) {
+        ListenerDispatcher<OFType, IOFMessageListener> ldd =
+            messageListeners.get(type);
+        if (ldd != null) {
+            ldd.removeListener(listener);
+        }
+    }
+
+    private void logListeners() {
+        for (Map.Entry<OFType,
+                       ListenerDispatcher<OFType,
+                                          IOFMessageListener>> entry
+             : messageListeners.entrySet()) {
+
+            OFType type = entry.getKey();
+            ListenerDispatcher<OFType, IOFMessageListener> ldd =
+                    entry.getValue();
+
+            StringBuilder sb = new StringBuilder();
+            sb.append("OFListeners for ");
+            sb.append(type);
+            sb.append(": ");
+            for (IOFMessageListener l : ldd.getOrderedListeners()) {
+                sb.append(l.getName());
+                sb.append(",");
+            }
+            log.debug(sb.toString());
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("HAListeners: ");
+        for (IHAListener l: haListeners.getOrderedListeners()) {
+            sb.append(l.getName());
+            sb.append(", ");
+        }
+        log.debug(sb.toString());
+    }
+
+    public void removeOFMessageListeners(OFType type) {
+        messageListeners.remove(type);
+    }
+
+    @Override
+    public Map<OFType, List<IOFMessageListener>> getListeners() {
+        Map<OFType, List<IOFMessageListener>> lers =
+            new HashMap<OFType, List<IOFMessageListener>>();
+        for(Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e :
+            messageListeners.entrySet()) {
+            lers.put(e.getKey(), e.getValue().getOrderedListeners());
+        }
+        return Collections.unmodifiableMap(lers);
+    }
+
+    @Override
+    @LogMessageDocs({
+        @LogMessageDoc(level="ERROR",
+                message="Error reinjecting OFMessage on switch {switch}",
+                explanation="An I/O error occured while attempting to " +
+                        "process an OpenFlow message",
+                recommendation=LogMessageDoc.CHECK_SWITCH)
+    })
+    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
+                                   FloodlightContext bc) {
+        if (sw == null)
+            throw new NullPointerException("Switch must not be null");
+        if (msg == null)
+            throw new NullPointerException("OFMessage must not be null");
+
+        // FIXME: Do we need to be able to inject messages from switches
+        // where we're the slave controller (i.e. they're connected but
+        // not active)?
+        if (!sw.isActive()) return false;
+
+        try {
+            // Pass Floodlight context to the handleMessages()
+            handleMessage(sw, msg, bc);
+        } catch (IOException e) {
+            log.error("Error reinjecting OFMessage on switch {}",
+                      sw.getStringId());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    @LogMessageDoc(message="Calling System.exit",
+                   explanation="The controller is terminating")
+    public synchronized void terminate() {
+        log.info("Calling System.exit");
+        System.exit(1);
+    }
+
+    @Override
+    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) {
+        // call the overloaded version with floodlight context set to null
+        return injectOfMessage(sw, msg, null);
+    }
+
+    @Override
+    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
+                                      FloodlightContext bc) {
+        if (sw == null)
+            throw new NullPointerException("Switch must not be null");
+        if (m == null)
+            throw new NullPointerException("OFMessage must not be null");
+        if (bc == null)
+            bc = new FloodlightContext();
+        if (log.isTraceEnabled()) {
+            String str = OFMessage.getDataAsString(sw, m, bc);
+            log.trace("{}", str);
+        }
+
+        List<IOFMessageListener> listeners = null;
+        if (messageListeners.containsKey(m.getType())) {
+            listeners =
+                    messageListeners.get(m.getType()).getOrderedListeners();
+        }
+
+        if (listeners != null) {
+            for (IOFMessageListener listener : listeners) {
+                if (Command.STOP.equals(listener.receive(sw, m, bc))) {
+                    break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public BasicFactory getOFMessageFactory() {
+        return factory;
+    }
+
+    // **************
+    // Initialization
+    // **************
+
+
+    /**
+     * Sets the initial role based on properties in the config params.
+     * It looks for two different properties.
+     * If the "role" property is specified then the value should be
+     * either "EQUAL", "MASTER", or "SLAVE" and the role of the
+     * controller is set to the specified value. If the "role" property
+     * is not specified then it looks next for the "role.path" property.
+     * In this case the value should be the path to a property file in
+     * the file system that contains a property called "floodlight.role"
+     * which can be one of the values listed above for the "role" property.
+     * The idea behind the "role.path" mechanism is that you have some
+     * separate heartbeat and master controller election algorithm that
+     * determines the role of the controller. When a role transition happens,
+     * it updates the current role in the file specified by the "role.path"
+     * file. Then if floodlight restarts for some reason it can get the
+     * correct current role of the controller from the file.
+     * @param configParams The config params for the FloodlightProvider service
+     * @return A valid role if role information is specified in the
+     *         config params, otherwise null
+     */
+    @LogMessageDocs({
+        @LogMessageDoc(message="Controller role set to {role}",
+                explanation="Setting the initial HA role to "),
+        @LogMessageDoc(level="ERROR",
+                message="Invalid current role value: {role}",
+                explanation="An invalid HA role value was read from the " +
+                            "properties file",
+                recommendation=LogMessageDoc.CHECK_CONTROLLER)
+    })
+    protected Role getInitialRole(Map<String, String> configParams) {
+        Role role = Role.MASTER;
+        String roleString = configParams.get("role");
+        if (roleString == null) {
+            String rolePath = configParams.get("rolepath");
+            if (rolePath != null) {
+                Properties properties = new Properties();
+                try {
+                    properties.load(new FileInputStream(rolePath));
+                    roleString = properties.getProperty("floodlight.role");
+                }
+                catch (IOException exc) {
+                    // Don't treat it as an error if the file specified by the
+                    // rolepath property doesn't exist. This lets us enable the
+                    // HA mechanism by just creating/setting the floodlight.role
+                    // property in that file without having to modify the
+                    // floodlight properties.
+                }
+            }
+        }
+
+        if (roleString != null) {
+            // Canonicalize the string to the form used for the enum constants
+            roleString = roleString.trim().toUpperCase();
+            try {
+                role = Role.valueOf(roleString);
+            }
+            catch (IllegalArgumentException exc) {
+                log.error("Invalid current role value: {}", roleString);
+            }
+        }
+        if (role == Role.EQUAL)
+            role = Role.MASTER;
+
+        log.info("Controller role set to {}", role);
+
+        return role;
+    }
+
+    /**
+     * Tell controller that we're ready to accept switches loop
+     * @throws IOException
+     */
+    @Override
+    @LogMessageDocs({
+        @LogMessageDoc(message="Listening for switch connections on {address}",
+                explanation="The controller is ready and listening for new" +
+                        " switch connections"),
+        @LogMessageDoc(message="Storage exception in controller " +
+                        "updates loop; terminating process",
+                explanation=ERROR_DATABASE,
+                recommendation=LogMessageDoc.CHECK_CONTROLLER),
+        @LogMessageDoc(level="ERROR",
+                message="Exception in controller updates loop",
+                explanation="Failed to dispatch controller event",
+                recommendation=LogMessageDoc.GENERIC_ACTION)
+    })
+    public void run() {
+        if (log.isDebugEnabled()) {
+            logListeners();
+        }
+
+        try {
+           final ServerBootstrap bootstrap = createServerBootStrap();
+
+            bootstrap.setOption("reuseAddr", true);
+            bootstrap.setOption("child.keepAlive", true);
+            bootstrap.setOption("child.tcpNoDelay", true);
+            bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
+
+            ChannelPipelineFactory pfact =
+                    new OpenflowPipelineFactory(this, null);
+            bootstrap.setPipelineFactory(pfact);
+            InetSocketAddress sa =
+            		(openFlowHost == null)
+            		? new InetSocketAddress(openFlowPort)
+            		: new InetSocketAddress(openFlowHost, openFlowPort);
+            final ChannelGroup cg = new DefaultChannelGroup();
+            cg.add(bootstrap.bind(sa));
+
+            log.info("Listening for switch connections on {}", sa);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        // main loop
+        while (true) {
+            try {
+                IUpdate update = updates.take();
+                update.dispatch();
+            } catch (InterruptedException e) {
+                log.error("Received interrupted exception in updates loop;" +
+                          "terminating process");
+                terminate();
+            } catch (StorageException e) {
+                log.error("Storage exception in controller " +
+                          "updates loop; terminating process", e);
+                terminate();
+            } catch (Exception e) {
+                log.error("Exception in controller updates loop", e);
+            }
+        }
+    }
+
+    private ServerBootstrap createServerBootStrap() {
+        if (workerThreads == 0) {
+            return new ServerBootstrap(
+                    new NioServerSocketChannelFactory(
+                            Executors.newCachedThreadPool(),
+                            Executors.newCachedThreadPool()));
+        } else {
+            return new ServerBootstrap(
+                    new NioServerSocketChannelFactory(
+                            Executors.newCachedThreadPool(),
+                            Executors.newCachedThreadPool(), workerThreads));
+        }
+    }
+
+    private void setConfigParams(Map<String, String> configParams) {
+        String ofPort = configParams.get("openflowport");
+        if (ofPort != null) {
+            this.openFlowPort = Integer.parseInt(ofPort);
+        }
+        log.debug("OpenFlow port set to {}", this.openFlowPort);
+        String threads = configParams.get("workerthreads");
+        if (threads != null) {
+            this.workerThreads = Integer.parseInt(threads);
+        }
+        log.debug("Number of worker threads set to {}", this.workerThreads);
+
+    }
+
+    private void initVendorMessages() {
+        // Configure openflowj to be able to parse the role request/reply
+        // vendor messages.
+        OFNiciraVendorExtensions.initialize();
+
+        // Register the standard Vendor actions that we support
+        OFVendorActions.registerStandardVendorActions();
+    }
+
+    /**
+     * Initialize internal data structures
+     */
+    public void init(Map<String, String> configParams) {
+        // These data structures are initialized here because other
+        // module's startUp() might be called before ours
+        this.messageListeners =
+                new ConcurrentHashMap<OFType,
+                                      ListenerDispatcher<OFType,
+                                                         IOFMessageListener>>();
+        this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
+        // add switch notification listener
+        this.addOFSwitchListener(new NotificationSwitchListener());
+        this.readyForReconcileListeners =
+                new CopyOnWriteArraySet<IReadyForReconcileListener>();
+        this.haListeners =
+                new ListenerDispatcher<HAListenerTypeMarker, IHAListener>();
+        this.driverRegistry = new NaiiveSwitchDriverRegistry();
+        this.controllerNodeIPsCache = new HashMap<String, String>();
+        this.updates = new LinkedBlockingQueue<IUpdate>();
+        this.factory = BasicFactory.getInstance();
+        this.providerMap = new HashMap<String, List<IInfoProvider>>();
+        setConfigParams(configParams);
+        Role initialRole = getInitialRole(configParams);
+        this.notifiedRole = initialRole;
+        initVendorMessages();
+
+        String option = configParams.get("flushSwitchesOnReconnect");
+
+        if (option != null && option.equalsIgnoreCase("true")) {
+            this.setAlwaysClearFlowsOnSwActivate(true);
+            log.info("Flush switches on reconnect -- Enabled.");
+        } else {
+            this.setAlwaysClearFlowsOnSwActivate(false);
+            log.info("Flush switches on reconnect -- Disabled");
+        }
+
+        uplinkPortPrefixSet = new HashSet<String>();
+        uplinkPortPrefixSet.add("eth");
+        uplinkPortPrefixSet.add("bond");
+        String str = configParams.get("uplinkPortPrefix");
+        if (str != null) {
+            List<String> items = Arrays.asList(str.split("\\s*,\\s*"));
+            if (items != null) {
+                for (String s: items) {
+                    if (s.length() > 0) {
+                        uplinkPortPrefixSet.add(s);
+                    }
+                }
+            }
+        }
+
+        this.roleManager = new RoleManager(this.notifiedRole,
+                                           INITIAL_ROLE_CHANGE_DESCRIPTION);
+        this.switchManager = new SwitchManager(this.notifiedRole);
+        this.counters = new Counters();
+        this.swConnectCache =
+                new TimedCache<Long>(100, 5*1000 );  // 5 seconds interval
+     }
+
+    /**
+     * Startup all of the controller's components
+     */
+    @LogMessageDoc(message="Waiting for storage source",
+                explanation="The system database is not yet ready",
+                recommendation="If this message persists, this indicates " +
+                        "that the system database has failed to start. " +
+                        LogMessageDoc.CHECK_CONTROLLER)
+    public void startupComponents() throws FloodlightModuleException {
+        // Create the table names we use
+        storageSource.createTable(CONTROLLER_TABLE_NAME, null);
+        storageSource.createTable(CONTROLLER_INTERFACE_TABLE_NAME, null);
+        storageSource.createTable(SWITCH_CONFIG_TABLE_NAME, null);
+        storageSource.setTablePrimaryKeyName(CONTROLLER_TABLE_NAME,
+                                             CONTROLLER_ID);
+        storageSource.addListener(CONTROLLER_INTERFACE_TABLE_NAME, this);
+
+        storageSource.createTable(FLOW_PRIORITY_TABLE_NAME, null);
+        storageSource.setTablePrimaryKeyName(FLOW_PRIORITY_TABLE_NAME,
+                                             FLOW_COLUMN_PRIMARY_KEY);
+        storageSource.addListener(FLOW_PRIORITY_TABLE_NAME, this);
+        readFlowPriorityConfigurationFromStorage();
+
+        // Startup load monitoring
+        if (overload_drop) {
+            this.loadmonitor.startMonitoring(
+                this.threadPool.getScheduledExecutor());
+        }
+
+        // Add our REST API
+        restApi.addRestletRoutable(new CoreWebRoutable());
+
+        this.ses = threadPool.getScheduledExecutor();
+
+        try {
+            this.syncService.registerStore(SWITCH_SYNC_STORE_NAME, Scope.LOCAL);
+            this.storeClient = this.syncService
+                    .getStoreClient(SWITCH_SYNC_STORE_NAME,
+                                    Long.class,
+                                    SwitchSyncRepresentation.class);
+            this.storeClient.addStoreListener(this.switchManager);
+        } catch (SyncException e) {
+            throw new FloodlightModuleException("Error while setting up sync service", e);
+        }
+
+        try {
+            this.counters.createCounters(debugCounters);
+        } catch (CounterException e) {
+            throw new FloodlightModuleException(e.getMessage());
+        }
+
+        addInfoProvider("summary", this);
+
+        registerControllerDebugEvents();
+    }
+
+    @LogMessageDoc(level="ERROR",
+            message="failed to access storage: {reason}",
+            explanation="Could not retrieve forwarding configuration",
+            recommendation=LogMessageDoc.CHECK_CONTROLLER)
+    private void readFlowPriorityConfigurationFromStorage() {
+        try {
+            Map<String, Object> row;
+            IResultSet resultSet = storageSource.executeQuery(
+                FLOW_PRIORITY_TABLE_NAME, FLOW_COLUMN_NAMES, null, null);
+            if (resultSet == null)
+                return;
+
+            for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
+                row = it.next().getRow();
+                if (row.containsKey(FLOW_COLUMN_PRIMARY_KEY)) {
+                    String primary_key = (String) row.get(FLOW_COLUMN_PRIMARY_KEY);
+                    if (primary_key.equals(FLOW_VALUE_PRIMARY_KEY)) {
+                        if (row.containsKey(FLOW_COLUMN_ACCESS_PRIORITY)) {
+                            accessPriority =
+                                Short.valueOf((String) row.get(FLOW_COLUMN_ACCESS_PRIORITY));
+                        }
+                        if (row.containsKey(FLOW_COLUMN_CORE_PRIORITY)) {
+                            corePriority =
+                                    Short.valueOf((String) row.get(FLOW_COLUMN_CORE_PRIORITY));
+                        }
+                    }
+                }
+            }
+        }
+        catch (StorageException e) {
+            log.error("Failed to access storage for forwarding configuration: {}",
+                      e.getMessage());
+        }
+        catch (NumberFormatException e) {
+            // log error, no stack-trace
+            log.error("Failed to read core or access flow priority from " +
+                      "storage. Illegal number: {}", e.getMessage());
+        }
+    }
+
+
+    private void registerControllerDebugEvents() throws FloodlightModuleException {
+        if (debugEvents == null) {
+            debugEvents = new NullDebugEvent();
+        }
+        try {
+            evSwitch = debugEvents.registerEvent(
+                               Counters.prefix, "switchevent",
+                               "Switch connected, disconnected or port changed",
+                               EventType.ALWAYS_LOG, SwitchEvent.class, 100);
+        } catch (MaxEventsRegistered e) {
+            throw new FloodlightModuleException("Max events registered", e);
+        }
+    }
+
+    public class SwitchEvent {
+        @EventColumn(name = "dpid", description = EventFieldType.DPID)
+        long dpid;
+
+        @EventColumn(name = "reason", description = EventFieldType.STRING)
+        String reason;
+
+        public SwitchEvent(long dpid, String reason) {
+            this.dpid = dpid;
+            this.reason = reason;
+        }
+    }
+
+    @Override
+    public void addInfoProvider(String type, IInfoProvider provider) {
+        if (!providerMap.containsKey(type)) {
+            providerMap.put(type, new ArrayList<IInfoProvider>());
+        }
+        providerMap.get(type).add(provider);
+    }
+
+    @Override
+    public void removeInfoProvider(String type, IInfoProvider provider) {
+        if (!providerMap.containsKey(type)) {
+            log.debug("Provider type {} doesn't exist.", type);
+            return;
+        }
+
+        providerMap.get(type).remove(provider);
+    }
+
+    @Override
+    public Map<String, Object> getControllerInfo(String type) {
+        if (!providerMap.containsKey(type)) return null;
+
+        Map<String, Object> result = new LinkedHashMap<String, Object>();
+        for (IInfoProvider provider : providerMap.get(type)) {
+            result.putAll(provider.getInfo(type));
+        }
+
+        return result;
+    }
+
+    @Override
+    public void addHAListener(IHAListener listener) {
+        this.haListeners.addListener(null,listener);
+    }
+
+    @Override
+    public void removeHAListener(IHAListener listener) {
+        this.haListeners.removeListener(listener);
+    }
+
+    @Override
+    public void addReadyForReconcileListener(IReadyForReconcileListener l) {
+        this.readyForReconcileListeners.add(l);
+    }
+
+
+    /**
+     * Handle changes to the controller nodes IPs and dispatch update.
+     */
+    protected void handleControllerNodeIPChanges() {
+        HashMap<String,String> curControllerNodeIPs = new HashMap<String,String>();
+        HashMap<String,String> addedControllerNodeIPs = new HashMap<String,String>();
+        HashMap<String,String> removedControllerNodeIPs =new HashMap<String,String>();
+        String[] colNames = { CONTROLLER_INTERFACE_CONTROLLER_ID,
+                           CONTROLLER_INTERFACE_TYPE,
+                           CONTROLLER_INTERFACE_NUMBER,
+                           CONTROLLER_INTERFACE_DISCOVERED_IP };
+        synchronized(controllerNodeIPsCache) {
+            // We currently assume that interface Ethernet0 is the relevant
+            // controller interface. Might change.
+            // We could (should?) implement this using
+            // predicates, but creating the individual and compound predicate
+            // seems more overhead then just checking every row. Particularly,
+            // since the number of rows is small and changes infrequent
+            IResultSet res = storageSource.executeQuery(CONTROLLER_INTERFACE_TABLE_NAME,
+                    colNames,null, null);
+            while (res.next()) {
+                if (res.getString(CONTROLLER_INTERFACE_TYPE).equals("Ethernet") &&
+                        res.getInt(CONTROLLER_INTERFACE_NUMBER) == 0) {
+                    String controllerID = res.getString(CONTROLLER_INTERFACE_CONTROLLER_ID);
+                    String discoveredIP = res.getString(CONTROLLER_INTERFACE_DISCOVERED_IP);
+                    String curIP = controllerNodeIPsCache.get(controllerID);
+
+                    curControllerNodeIPs.put(controllerID, discoveredIP);
+                    if (curIP == null) {
+                        // new controller node IP
+                        addedControllerNodeIPs.put(controllerID, discoveredIP);
+                    }
+                    else if (!curIP.equals(discoveredIP)) {
+                        // IP changed
+                        removedControllerNodeIPs.put(controllerID, curIP);
+                        addedControllerNodeIPs.put(controllerID, discoveredIP);
+                    }
+                }
+            }
+            // Now figure out if rows have been deleted. We can't use the
+            // rowKeys from rowsDeleted directly, since the tables primary
+            // key is a compound that we can't disassemble
+            Set<String> curEntries = curControllerNodeIPs.keySet();
+            Set<String> removedEntries = controllerNodeIPsCache.keySet();
+            removedEntries.removeAll(curEntries);
+            for (String removedControllerID : removedEntries)
+                removedControllerNodeIPs.put(removedControllerID,
+                                             controllerNodeIPsCache.get(removedControllerID));
+            controllerNodeIPsCache.clear();
+            controllerNodeIPsCache.putAll(curControllerNodeIPs);
+            counters.controllerNodeIpsChanged.updateCounterWithFlush();
+            HAControllerNodeIPUpdate update = new HAControllerNodeIPUpdate(
+                                curControllerNodeIPs, addedControllerNodeIPs,
+                                removedControllerNodeIPs);
+            if (!removedControllerNodeIPs.isEmpty() || !addedControllerNodeIPs.isEmpty()) {
+                addUpdateToQueue(update);
+            }
+        }
+    }
+
+    @Override
+    public Map<String, String> getControllerNodeIPs() {
+        // We return a copy of the mapping so we can guarantee that
+        // the mapping return is the same as one that will be (or was)
+        // dispatched to IHAListeners
+        HashMap<String,String> retval = new HashMap<String,String>();
+        synchronized(controllerNodeIPsCache) {
+            retval.putAll(controllerNodeIPsCache);
+        }
+        return retval;
+    }
+
+    private static final String FLOW_PRIORITY_CHANGED_AFTER_STARTUP =
+            "Flow priority configuration has changed after " +
+            "controller startup. Restart controller for new " +
+            "configuration to take effect.";
+    @LogMessageDoc(level="WARN",
+            message=FLOW_PRIORITY_CHANGED_AFTER_STARTUP,
+            explanation="A user has changed the priority with which access " +
+                    "and core flows are installed after controller startup. " +
+                    "Changing this setting will only take affect after a " +
+                    "controller restart",
+            recommendation="Restart controller")
+    @Override
+    public void rowsModified(String tableName, Set<Object> rowKeys) {
+        if (tableName.equals(CONTROLLER_INTERFACE_TABLE_NAME)) {
+            handleControllerNodeIPChanges();
+        } else if (tableName.equals(FLOW_PRIORITY_TABLE_NAME)) {
+            log.warn(FLOW_PRIORITY_CHANGED_AFTER_STARTUP);
+        }
+
+
+    }
+
+    @Override
+    public void rowsDeleted(String tableName, Set<Object> rowKeys) {
+        if (tableName.equals(CONTROLLER_INTERFACE_TABLE_NAME)) {
+            handleControllerNodeIPChanges();
+        } else if (tableName.equals(FLOW_PRIORITY_TABLE_NAME)) {
+            log.warn(FLOW_PRIORITY_CHANGED_AFTER_STARTUP);
+        }
+    }
+
+    @Override
+    public long getSystemStartTime() {
+        RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
+        return rb.getStartTime();
+    }
+
+    @Override
+    public void setAlwaysClearFlowsOnSwActivate(boolean value) {
+        this.alwaysClearFlowsOnSwActivate = value;
+    }
+
+
+    @Override
+    public Map<String, Long> getMemory() {
+        Map<String, Long> m = new HashMap<String, Long>();
+        Runtime runtime = Runtime.getRuntime();
+        m.put("total", runtime.totalMemory());
+        m.put("free", runtime.freeMemory());
+        return m;
+    }
+
+    @Override
+    public Long getUptime() {
+        RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
+        return rb.getUptime();
+    }
+
+
+
+    @Override
+    public void addOFSwitchDriver(String manufacturerDescriptionPrefix,
+                                  IOFSwitchDriver driver) {
+        driverRegistry.addSwitchDriver(manufacturerDescriptionPrefix, driver);
+    }
+
+    /**
+     * Forward to the registry to get an IOFSwitch instance.
+     * @param desc
+     * @return
+     */
+    IOFSwitch getOFSwitchInstance(OFDescriptionStatistics desc) {
+        return driverRegistry.getOFSwitchInstance(desc);
+    }
+
+    /**
+     *  Switch Added/Deleted Events
+     */
+    @Override
+    public void addSwitchEvent(long switchDPID, String reason, boolean flushNow) {
+        switchManager.addSwitchEvent(switchDPID, reason, flushNow);
+    }
+
+    @LogMessageDoc(level="WARN",
+            message="Failure adding update {} to queue",
+            explanation="The controller tried to add an internal notification" +
+                        " to its message queue but the add failed.",
+            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+    private void addUpdateToQueue(IUpdate update) {
+        try {
+            this.updates.put(update);
+        } catch (InterruptedException e) {
+            // This should never happen
+            log.error("Failure adding update {} to queue.", update);
+        }
+    }
+
+    void flushAll() {
+        // Flush all flow-mods/packet-out/stats generated from this "train"
+        OFSwitchBase.flush_all();
+        counterStore.updateFlush();
+        debugCounters.flushCounters();
+        debugEvents.flushEvents();
+    }
+
+    short getAccessFlowPriority() {
+        return accessPriority;
+    }
+
+    short getCoreFlowPriority() {
+        return corePriority;
+    }
+
+    /**
+     * FOR TESTING ONLY.
+     * Dispatch all updates in the update queue until queue is empty
+     */
+    void processUpdateQueueForTesting() {
+        while(!updates.isEmpty()) {
+            IUpdate update = updates.poll();
+            if (update != null)
+                update.dispatch();
+        }
+    }
+
+    /**
+     * FOR TESTING ONLY
+     * check if update queue is empty
+     */
+    boolean isUpdateQueueEmptyForTesting() {
+        return this.updates.isEmpty();
+    }
+
+    /**
+     * FOR TESTING ONLY
+     * @param update
+     */
+    void setConsolidateStoreTaskDelay(int consolidateStoreTaskDelayMs) {
+        this.consolidateStoreTimeDelayMs = consolidateStoreTaskDelayMs;
+    }
+
+    /**
+     * FOR TESTING ONLY
+     * returns the store listener so we can send events to the listener
+     */
+    IStoreListener<Long> getStoreListener() {
+        return this.switchManager;
+    }
+
+    @Override
+    public Map<String, Object> getInfo(String type) {
+        if (!"summary".equals(type)) return null;
+
+        Map<String, Object> info = new HashMap<String, Object>();
+
+        info.put("# Switches", this.getAllSwitchDpids().size());
+        return info;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java b/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java
deleted file mode 100644
index c511a09ee13d9d6604cbc3e9c095adea8d6c0b8b..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.OFConnectionCounters;
-import net.floodlightcontroller.debugcounter.IDebugCounter;
-import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import net.floodlightcontroller.debugcounter.IDebugCounterService.MetaData;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD",
-                    justification = "It is ok to predefine Debug Counters that are not yet used")
-public class ControllerCounters {
-
-    public final String prefix = ControllerCounters.class.getSimpleName();
-    public final String statsPrefix = IOFSwitchBackend.class.getPackage()
-                                                            .getName();
-
-    public final IDebugCounter packetParsingError;
-    public final IDebugCounter dispatchMessageWhileStandby;
-    public final IDebugCounter dispatchMessage;
-
-    public ControllerCounters(IDebugCounterService debugCounters) {
-        debugCounters.registerModule(prefix);
-        debugCounters.registerModule(OFConnectionCounters.COUNTER_MODULE);
-
-        dispatchMessageWhileStandby = debugCounters.registerCounter(prefix,
-                                                                    "dispatch-message-while-slave",
-                                                                    "Number of times an OF message was received "
-                                                                            + "and supposed to be dispatched but the "
-                                                                            + "controller was in SLAVE role and the message "
-                                                                            + "was not dispatched");
-        // does this cnt make sense? more specific?? per type?
-        // count stops?
-        dispatchMessage = debugCounters.registerCounter(prefix,
-                                                        "dispatch-message",
-                                                        "Number of times an OF message was dispatched "
-                                                                + "to registered modules");
-
-        // TODO: FIXME
-        // Need a better way to handle these
-        packetParsingError = debugCounters.registerCounter(prefix,
-                                                           "packet-parsing-error",
-                                                           "Number of times the packet parsing "
-                                                                   + "encountered an error",
-                                                           MetaData.ERROR);
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java b/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java
index 12716c4bab5c4b4afeb55089a5ee7264e2d46148..8299bb2c223f6c93437813db9dc8963acf386859 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java
@@ -21,11 +21,6 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
-import net.floodlightcontroller.core.internal.IOFSwitchService;
-import net.floodlightcontroller.core.internal.Controller;
-import net.floodlightcontroller.core.module.Run;
-
-import org.projectfloodlight.openflow.protocol.OFType;
 import org.sdnplatform.sync.ISyncService;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -44,10 +39,6 @@ import net.floodlightcontroller.threadpool.IThreadPoolService;
 public class FloodlightProvider implements IFloodlightModule {
     Controller controller;
 
-    public FloodlightProvider() {
-        controller = new Controller();
-    }
-    
     @Override
     public Collection<Class<? extends IFloodlightService>> getModuleServices() {
         Collection<Class<? extends IFloodlightService>> services =
@@ -79,7 +70,6 @@ public class FloodlightProvider implements IFloodlightModule {
         dependencies.add(ICounterStoreService.class);
         dependencies.add(IDebugCounterService.class);
         dependencies.add(IDebugEventService.class);
-        dependencies.add(IOFSwitchService.class);
         dependencies.add(IThreadPoolService.class);
         dependencies.add(ISyncService.class);
         return dependencies;
@@ -109,23 +99,6 @@ public class FloodlightProvider implements IFloodlightModule {
     @Override
     public void startUp(FloodlightModuleContext context)
             throws FloodlightModuleException {
-        controller.startupComponents(context.getModuleLoader());
+        controller.startupComponents();
     }
-    
-    @Run(mainLoop=true)
-    public void run() throws FloodlightModuleException {
-        controller.run();
-    }
-
-	@Override
-	public boolean isCallbackOrderingPrereq(OFType type, String name) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	@Override
-	public boolean isCallbackOrderingPostreq(OFType type, String name) {
-		// TODO Auto-generated method stub
-		return false;
-	}
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFAuxException.java b/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutException.java
similarity index 51%
rename from src/main/java/net/floodlightcontroller/core/internal/OFAuxException.java
rename to src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutException.java
index e2a6ccfdd8c0e1a6af30bfe91f4fecea3b6035d5..421ec1ac7dd3121a245b1b3b82fee0131b86f032 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFAuxException.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutException.java
@@ -1,7 +1,7 @@
 /**
-*    Copyright 2011, Big Switch Networks, Inc.
+*    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
@@ -18,25 +18,12 @@
 package net.floodlightcontroller.core.internal;
 
 /**
- * This exception indicates an error or unexpected message during
- * OF Aux handshaking. E.g., if a switch reports that it cannot supply us
- * with the number of OF Aux connections needed.
- *  @author Jason Parraga <Jason.Parraga@bigswitch.com>
+ * Exception is thrown when the handshake fails to complete 
+ * before a specified time
+ * @author readams
  */
-public class OFAuxException extends SwitchStateException{
-
-        private static final long serialVersionUID = 8452081020837079086L;
-
-        public OFAuxException() {
-            super();
-        }
+public class HandshakeTimeoutException extends Exception {
 
-        public OFAuxException(String arg0) {
-            super(arg0);
-        }
+    private static final long serialVersionUID = 6859880268940337312L;
 
-        public OFAuxException(Throwable arg0) {
-            super(arg0);
-        }
-        
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java b/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
index 89ef68109bdc715eb2c16ea3f59f6c2c7b33fc67..e89b3895c7e77ff7fde72e83e61aad25e1598fe1 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
@@ -1,7 +1,7 @@
 /**
-*    Copyright 2011, Big Switch Networks, Inc.
+*    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
@@ -30,37 +30,36 @@ import org.jboss.netty.util.TimerTask;
 /**
  * Trigger a timeout if a switch fails to complete handshake soon enough
  */
-public class HandshakeTimeoutHandler
+public class HandshakeTimeoutHandler 
     extends SimpleChannelUpstreamHandler {
-
-    static final HandshakeTimeoutException EXCEPTION =
+    static final HandshakeTimeoutException EXCEPTION = 
             new HandshakeTimeoutException();
-
-    final OFChannelHandler handshakeHandler;
+    
+    final OFChannelHandler channelHandler;
     final Timer timer;
     final long timeoutNanos;
     volatile Timeout timeout;
-
-    public HandshakeTimeoutHandler(OFChannelHandler handshakeHandler,
+    
+    public HandshakeTimeoutHandler(OFChannelHandler channelHandler,
                                    Timer timer,
                                    long timeoutSeconds) {
         super();
-        this.handshakeHandler = handshakeHandler;
+        this.channelHandler = channelHandler;
         this.timer = timer;
         this.timeoutNanos = TimeUnit.SECONDS.toNanos(timeoutSeconds);
 
     }
-
+    
     @Override
     public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
             throws Exception {
         if (timeoutNanos > 0) {
-            timeout = timer.newTimeout(new HandshakeTimeoutTask(ctx),
+            timeout = timer.newTimeout(new HandshakeTimeoutTask(ctx), 
                                        timeoutNanos, TimeUnit.NANOSECONDS);
         }
         ctx.sendUpstream(e);
     }
-
+    
     @Override
     public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
             throws Exception {
@@ -69,7 +68,7 @@ public class HandshakeTimeoutHandler
             timeout = null;
         }
     }
-
+    
     private final class HandshakeTimeoutTask implements TimerTask {
 
         private final ChannelHandlerContext ctx;
@@ -87,7 +86,7 @@ public class HandshakeTimeoutHandler
             if (!ctx.getChannel().isOpen()) {
                 return;
             }
-            if (!handshakeHandler.isSwitchHandshakeComplete())
+            if (!channelHandler.isHandshakeComplete())
                 Channels.fireExceptionCaught(ctx, EXCEPTION);
         }
     }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/IAppHandshakePluginFactory.java b/src/main/java/net/floodlightcontroller/core/internal/IAppHandshakePluginFactory.java
deleted file mode 100644
index fd45309f30208a9b965de54fa92c7b1e4f5859e2..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/IAppHandshakePluginFactory.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-/**
- * This interface creates a contract used by the switch handshake handler. Each
- * switch that is connected needs it's own running instance of the registered
- * plugins. Thus is depends on a factory to churn out these instances.
- * @author Jason Parraga <Jason.Parraga@bigswitch.com>
- *
- */
-public interface IAppHandshakePluginFactory {
-
-    /**
-     * Create an instance of OFSwitchAppHandshakePlugin
-     * @return an instance of OFSwitchAppHandshakePlugin
-     */
-    OFSwitchAppHandshakePlugin createPlugin();
-}
-
-
diff --git a/src/main/java/net/floodlightcontroller/core/internal/INewOFConnectionListener.java b/src/main/java/net/floodlightcontroller/core/internal/INewOFConnectionListener.java
deleted file mode 100644
index 9f03bc38e422bb3da8623b5e8bf2eddf245d7d90..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/INewOFConnectionListener.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import net.floodlightcontroller.core.IOFConnectionBackend;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-
-/** a listener that is notified when a new OFConnection has been opened and
- *  handshaked (i.e., the {@link OFFeaturesReply} has been received.
- *
- * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- */
-public interface INewOFConnectionListener {
-    /** notify this listener that a new connection has been opened
-     *
-     * @param connection - the new connection
-     * @param featuresReply - the {@link OFFeaturesReply} that was received.
-     */
-    void connectionOpened(IOFConnectionBackend connection,
-                          OFFeaturesReply featuresReply);
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/IOFConnectionListener.java b/src/main/java/net/floodlightcontroller/core/internal/IOFConnectionListener.java
deleted file mode 100644
index f537e2d4fff00de8405346326f91fff9a93cba42..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/IOFConnectionListener.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import net.floodlightcontroller.core.IOFConnectionBackend;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-
-public interface IOFConnectionListener {
-    void connectionClosed(IOFConnectionBackend connection);
-
-    void messageReceived(IOFConnectionBackend connection, OFMessage m);
-
-    boolean isSwitchHandshakeComplete(IOFConnectionBackend connection);
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchManager.java b/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchManager.java
deleted file mode 100644
index 81a85346ca78e944cf2cf6dd4d52d6fb7d74ee16..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchManager.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.util.List;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.IOFConnectionBackend;
-import net.floodlightcontroller.core.IOFSwitch.SwitchStatus;
-import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.IOFSwitchDriver;
-import net.floodlightcontroller.core.LogicalOFMessageCategory;
-import net.floodlightcontroller.core.PortChangeType;
-import net.floodlightcontroller.core.SwitchDescription;
-
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.types.DatapathId;
-
-import com.google.common.collect.ImmutableList;
-
-public interface IOFSwitchManager {
-
-    /**
-     * Called when a switch is added.
-     * @param sw the added switch
-     */
-    void switchAdded(IOFSwitchBackend sw);
-
-    /**
-     * Called when a switch disconnects
-     * @param sw the added switch
-     */
-    void switchDisconnected(IOFSwitchBackend sw);
-
-    /**
-     * Indicates that ports on the given switch have changed. Enqueue a
-     * switch update.
-     * @param sw the added switch
-     */
-    void notifyPortChanged(IOFSwitchBackend sw, OFPortDesc port,
-                           PortChangeType type);
-
-    /**
-     * Relays to ISwitchDriverRegistry
-     */
-    IOFSwitchBackend getOFSwitchInstance(IOFConnectionBackend connection,
-                                         SwitchDescription description,
-                                         OFFactory factory,
-                                         DatapathId datapathId);
-
-    /**
-     * Relays an upstream message to the controller to dispatch to listeners.
-     * @param sw The switch the message was received on.
-     * @param m The message received.
-     * @param bContext the Floodlight context of the message, normally null in this case.
-     */
-    void handleMessage(IOFSwitchBackend sw, OFMessage m, FloodlightContext bContext);
-
-    /**
-     * Gets an unmodifiable collection of OFSwitchHandshakeHandlers
-     * @return an unmodifiable collection of OFSwitchHandshakeHandlers
-     */
-    ImmutableList<OFSwitchHandshakeHandler> getSwitchHandshakeHandlers();
-
-    /**
-     * Adds an OFSwitch driver
-     *  @param manufacturerDescriptionPrefix Register the given prefix
-     * with the driver.
-     * @param driver A IOFSwitchDriver instance to handle IOFSwitch instantiation
-     * for the given manufacturer description prefix
-     * @throws IllegalStateException If the the manufacturer description is
-     * already registered
-     * @throws NullPointerExeption if manufacturerDescriptionPrefix is null
-     * @throws NullPointerExeption if driver is null
-     */
-    void addOFSwitchDriver(String manufacturerDescriptionPrefix,
-                           IOFSwitchDriver driver);
-
-    /**
-     * Handles all changes to the switch status. Will alert listeners and manage
-     * the internal switch map appropriately.
-     * @param sw the switch that has changed
-     * @param oldStatus the switch's old status
-     * @param newStatus the switch's new status
-     */
-    void switchStatusChanged(IOFSwitchBackend sw, SwitchStatus oldStatus,
-            SwitchStatus newStatus);
-
-    /**
-     * Gets the number of connections required by the application
-     * @return the number of connections required by the applications
-     */
-    int getNumRequiredConnections();
-
-    /**
-     * Record a switch event in in-memory debug-event
-     * @param switchDpid
-     * @param reason Reason for this event
-     * @param flushNow see debug-event flushing in IDebugEventService
-     */
-    public void addSwitchEvent(DatapathId switchDpid, String reason, boolean flushNow);
-
-    /**
-     * Get the list of handshake plugins necessary for the switch handshake.
-     * @return the list of handshake plugins registered by applications.
-     */
-    List<IAppHandshakePluginFactory> getHandshakePlugins();
-
-    /**
-     * Get the switch manager's counters
-     * @return the switch manager's counters
-     */
-    SwitchManagerCounters getCounters();
-
-    /**
-     * Checks to see if the supplied category has been registered with the controller
-     * @param category the logical OF Message category to check or
-     * @return true if registered
-     */
-    boolean isCategoryRegistered(LogicalOFMessageCategory category);
-
-    void handshakeDisconnected(DatapathId dpid);
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchService.java b/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchService.java
deleted file mode 100644
index 1896d27207e2ba176abbf063cc80aac279831e74..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchService.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitchListener;
-import net.floodlightcontroller.core.LogicalOFMessageCategory;
-import net.floodlightcontroller.core.module.IFloodlightService;
-import net.floodlightcontroller.core.rest.SwitchRepresentation;
-import org.projectfloodlight.openflow.types.DatapathId;
-
-public interface IOFSwitchService extends IFloodlightService {
-
-    /**
-     * Get's the switch map stored in the switch manager
-     * @return the map of switches known by the switch manager
-     */
-    Map<DatapathId, IOFSwitch> getAllSwitchMap();
-
-    /**
-     * If the switch with the given DPID is known to any controller in the
-     * cluster, this method returns the associated IOFSwitch instance. As such
-     * the returned switches not necessarily connected or in master role for
-     * the local controller.
-     *
-     * Multiple calls to this method with the same DPID may return different
-     * IOFSwitch references. A caller must not store or otherwise rely on
-     * IOFSwitch references to be constant over the lifecycle of a switch.
-     *
-     * @param dpid the dpid of the switch to query
-     * @return the IOFSwitch instance associated with the dpid, null if no
-     * switch with the dpid is known to the cluster
-     */
-    IOFSwitch getSwitch(DatapathId dpid);
-
-    /**
-     * If the switch with the given DPID is known to any controller in the
-     * cluster, this method returns the associated IOFSwitch instance. As such
-     * the returned switches not necessarily connected or in master role for
-     * the local controller.
-     *
-     * Multiple calls to this method with the same DPID may return different
-     * IOFSwitch references. A caller must not store or otherwise rely on
-     * IOFSwitch references to be constant over the lifecycle of a switch.
-     *
-     * @param dpid the dpid of the switch to query
-     * @return the IOFSwitch instance associated with the dpid, null if no
-     * switch with the dpid is known to the cluster OR if the switch status
-     * is not considered visible.
-     */
-    IOFSwitch getActiveSwitch(DatapathId dpid);
-
-    /**
-     * Add a switch listener
-     * @param listener The module that wants to listen for events
-     */
-    void addOFSwitchListener(IOFSwitchListener listener);
-
-    /**
-     * Remove a switch listener
-     * @param listener The The module that no longer wants to listen for events
-     */
-    void removeOFSwitchListener(IOFSwitchListener listener);
-
-    /**
-     * Registers a logical OFMessage category to be used by an application
-     * @param category the logical OFMessage category
-     */
-    void registerLogicalOFMessageCategory(LogicalOFMessageCategory category);
-
-    /**
-     * Registers an app handshake plugin to be used during switch handshaking.
-     * @param plugin the app handshake plugin to be used during switch handshaking.
-     */
-    void registerHandshakePlugin(IAppHandshakePluginFactory plugin);
-
-    /**
-     * Get the REST representations of the active switches.
-     * @return Representation wrappers of the active switches.
-     */
-    List<SwitchRepresentation> getSwitchRepresentations();
-
-    /**
-     * Get the REST representation of a switch.
-     * @param dpid the dpid of the desired switch representation.
-     * @return The switch representation.
-     */
-    SwitchRepresentation getSwitchRepresentation(DatapathId dpid);
-
-    /**
-     * Returns a snapshot of the set DPIDs for all known switches.
-     *
-     * The returned set is owned by the caller: the caller can modify it at
-     * will and changes to the known switches are not reflected in the returned
-     * set. The caller needs to call getAllSwitchDpids() if an updated
-     * version is needed.
-     *
-     * See {@link #getSwitch(long)} for what  "known" switch is.
-     * @return the set of DPIDs of all known switches
-     */
-    Set<DatapathId> getAllSwitchDpids();
-
-    /**
-     * Gets an immutable list of handshake handlers.
-     * @return an immutable list of handshake handlers.
-     */
-    List<OFSwitchHandshakeHandler> getSwitchHandshakeHandlers();
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/ISwitchDriverRegistry.java b/src/main/java/net/floodlightcontroller/core/internal/ISwitchDriverRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..6251fd26db9eab73cef4824c28ef20100d3b756f
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/ISwitchDriverRegistry.java
@@ -0,0 +1,60 @@
+package net.floodlightcontroller.core.internal;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitchDriver;
+
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+
+/**
+ * Maintain a registry for SwitchDrivers. Drivers can register with the
+ * registry and a user can get IOFSwitch instances based on the switch's
+ * OFDescriptionStatistics.
+ *
+ * A driver registers itself by specifying a <i>prefix string</i> of the
+ * switch's <i>manufacturer</i> description. When a user request an
+ * IOFSwitch instance the registry matches the manufacturer description
+ * of the switch against the prefixes in the registry.
+ *
+ * See getOFSwitchInstance() for a description of the lookup contract
+ *
+ * @author gregor
+ *
+ */
+public interface ISwitchDriverRegistry {
+
+    /**
+     * Register an IOFSwitchDriver with the registry
+     *
+     * @param manufacturerDescriptionPrefix Register the given prefix
+     * with the driver.
+     * @param driver A IOFSwitchDriver instance to handle IOFSwitch instaniation
+     * for the given manufacturer description prefix
+     * @throws IllegalStateException If the the manufacturer description is
+     * already registered
+     * @throws NullPointerExeption if manufacturerDescriptionPrefix is null
+     * @throws NullPointerExeption if driver is null
+     */
+    void addSwitchDriver(String manufacturerDescriptionPrefix,
+                         IOFSwitchDriver driver);
+    /**
+     * Return an IOFSwitch instance according to the description stats.
+     *
+     * The driver with the <i>longest matching prefix</i> will be picked first.
+     * The description is then handed over to the choosen driver to return an
+     * IOFSwitch instance. If the driver does not return an IOFSwitch
+     * (returns null) the registry will continue to the next driver with
+     * a matching manufacturer description prefix. If no driver returns an
+     * IOFSwitch instance the registry returns a default OFSwitchImpl instance.
+     *
+     * The returned switch will have its description reply and
+     * switch properties set according to the DescriptionStats passed in
+     *
+     * @param description The OFDescriptionStatistics for which to return an
+     * IOFSwitch implementation
+     * @return A IOFSwitch implementation matching the description or an
+     * OFSwitchImpl if no driver returned a more concrete instance.
+     * @throws NullPointerException If the OFDescriptionStatistics or any
+     * of its members is null.
+     */
+    IOFSwitch getOFSwitchInstance(OFDescriptionStatistics description);
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/NaiiveSwitchDriverRegistry.java b/src/main/java/net/floodlightcontroller/core/internal/NaiiveSwitchDriverRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..8109e3add7ebc6f580596eccac975e14b3bf7c6c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/NaiiveSwitchDriverRegistry.java
@@ -0,0 +1,105 @@
+package net.floodlightcontroller.core.internal;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitchDriver;
+
+/**
+ * This implementation of ISwitchDriverRegistry uses a naiive algorithm to
+ * perform longest prefix matching on the manufacturere description prefixes
+ *
+ * We maintain a map that maps prefixes to the drivers as well as a sorted
+ * set that contains the prefixes sorted by their length. We exploit the fact
+ * that lexicographical order defines that shorter strings are always less
+ * than longer strings with the same prefix). Thus we can use reverse order for
+ * our purposes.
+ * To perform a lookup we iterate through the sorted set until we find a prefix
+ * that matches the manufacturer description. Since the set is sorted this
+ * will be the longest matching prefix.
+ *
+ * @author gregor
+ */
+class NaiiveSwitchDriverRegistry implements ISwitchDriverRegistry {
+    private final SortedSet<String> switchDescSorted;
+    private final Map<String,IOFSwitchDriver> switchBindingMap;
+
+    public NaiiveSwitchDriverRegistry() {
+        switchBindingMap = new HashMap<String, IOFSwitchDriver>();
+        switchDescSorted = new TreeSet<String>(Collections.reverseOrder());
+    }
+
+    @Override
+    public synchronized void addSwitchDriver(String manufacturerDescPrefix,
+                                             IOFSwitchDriver driver) {
+        if (manufacturerDescPrefix == null) {
+            throw new NullPointerException("manufacturerDescrptionPrefix" +
+                    " must not be null");
+        }
+        if (driver == null) {
+            throw new NullPointerException("driver must not be null");
+        }
+
+        IOFSwitchDriver existingDriver = switchBindingMap.get(manufacturerDescPrefix);
+        if (existingDriver != null ) {
+            throw new IllegalStateException("Failed to add OFSwitch driver for "
+                    + manufacturerDescPrefix + "already registered");
+        }
+        switchBindingMap.put(manufacturerDescPrefix, driver);
+        switchDescSorted.add(manufacturerDescPrefix);
+    }
+
+    @Override
+    // TODO: instead of synchronized we could actually use a r/w lock
+    // but it's probably not worth it.
+    public synchronized IOFSwitch
+            getOFSwitchInstance(OFDescriptionStatistics description) {
+        if (description == null)
+            throw new NullPointerException("description must not be null");
+        if (description.getHardwareDescription() == null) {
+            throw new NullPointerException(
+                    "hardware description must not be null");
+        }
+        if (description.getManufacturerDescription() == null) {
+            throw new NullPointerException(
+                    "manufacturer description must not be null");
+        }
+        if (description.getSerialNumber() == null) {
+            throw new NullPointerException(
+                    "serial number must not be null");
+        }
+        if (description.getDatapathDescription() == null) {
+            throw new NullPointerException(
+                    "datapath description must not be null");
+        }
+        if (description.getSoftwareDescription() == null) {
+            throw new NullPointerException(
+                    "software description must not be null");
+        }
+
+
+        // Find the appropriate driver
+        for (String descPrefix: switchDescSorted) {
+            if (description.getManufacturerDescription()
+                    .startsWith(descPrefix)) {
+                IOFSwitchDriver driver = switchBindingMap.get(descPrefix);
+                IOFSwitch sw = driver.getOFSwitchImpl(description);
+                if (sw != null) {
+                    sw.setSwitchProperties(description);
+                    return sw;
+                }
+            }
+        }
+        // no switch found
+        IOFSwitch sw = new OFSwitchImpl();
+        sw.setSwitchProperties(description);
+        return sw;
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/NaiveSwitchDriverRegistry.java b/src/main/java/net/floodlightcontroller/core/internal/NaiveSwitchDriverRegistry.java
deleted file mode 100644
index 6f2fffed183dd3e58ab59729a5f8d636ad3a9009..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/NaiveSwitchDriverRegistry.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import javax.annotation.Nonnull;
-
-import net.floodlightcontroller.core.IOFConnectionBackend;
-import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.IOFSwitchDriver;
-import net.floodlightcontroller.core.OFSwitch;
-import net.floodlightcontroller.core.SwitchDescription;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-/**
- * This implementation of ISwitchDriverRegistry uses a naive algorithm to
- * perform longest prefix matching on the manufacturer description prefixes
- *
- * We maintain a map that maps prefixes to the drivers as well as a sorted
- * set that contains the prefixes sorted by their length. We exploit the fact
- * that lexicographical order defines that shorter strings are always less
- * than longer strings with the same prefix). Thus we can use reverse order for
- * our purposes.
- * To perform a lookup we iterate through the sorted set until we find a prefix
- * that matches the manufacturer description. Since the set is sorted this
- * will be the longest matching prefix.
- *
- * @author gregor
- */
-class NaiveSwitchDriverRegistry implements ISwitchDriverRegistry {
-
-    protected static final Logger log = LoggerFactory.getLogger(NaiveSwitchDriverRegistry.class);
-    private final SortedSet<String> switchDescSorted;
-    private final Map<String,IOFSwitchDriver> switchBindingMap;
-    private final IOFSwitchManager switchManager;
-
-    public NaiveSwitchDriverRegistry(@Nonnull IOFSwitchManager switchManager) {
-        Preconditions.checkNotNull(switchManager, "switchManager must not be null");
-        this.switchManager  = switchManager;
-        switchBindingMap = new HashMap<String, IOFSwitchDriver>();
-        switchDescSorted = new TreeSet<String>(Collections.reverseOrder());
-    }
-
-    @Override
-    public synchronized void addSwitchDriver(@Nonnull String manufacturerDescPrefix,
-                                             @Nonnull IOFSwitchDriver driver) {
-        Preconditions.checkNotNull(manufacturerDescPrefix, "manufactererDescProfix");
-        Preconditions.checkNotNull(driver, "driver");
-
-        IOFSwitchDriver existingDriver = switchBindingMap.get(manufacturerDescPrefix);
-        if (existingDriver != null ) {
-            throw new IllegalStateException("Failed to add OFSwitch driver for "
-                    + manufacturerDescPrefix + "already registered");
-        }
-        switchBindingMap.put(manufacturerDescPrefix, driver);
-        switchDescSorted.add(manufacturerDescPrefix);
-    }
-
-    @Override
-    // TODO: instead of synchronized we could actually use a r/w lock
-    // but it's probably not worth it.
-    public synchronized IOFSwitchBackend
-            getOFSwitchInstance(@Nonnull IOFConnectionBackend connection, @Nonnull SwitchDescription description,
-                    @Nonnull OFFactory factory, @Nonnull DatapathId id) {
-        Preconditions.checkNotNull(connection, "connection");
-        Preconditions.checkNotNull(description, "description");
-        Preconditions.checkNotNull(factory, "factory");
-        Preconditions.checkNotNull(id, "id");
-
-        Preconditions.checkNotNull(description.getHardwareDescription(), "hardware description");
-        Preconditions.checkNotNull(description.getManufacturerDescription(), "manufacturer description");
-        Preconditions.checkNotNull(description.getSerialNumber(), "serial number");
-        Preconditions.checkNotNull(description.getDatapathDescription(), "datapath description");
-        Preconditions.checkNotNull(description.getSoftwareDescription(), "software description");
-
-        // Find the appropriate driver
-        for (String descPrefix: switchDescSorted) {
-            if (description.getManufacturerDescription()
-                    .startsWith(descPrefix)) {
-                IOFSwitchDriver driver = switchBindingMap.get(descPrefix);
-                IOFSwitchBackend sw = driver.getOFSwitchImpl(description, factory);
-                if (sw != null) {
-                    sw.setSwitchProperties(description);
-                    return sw;
-                }
-            }
-        }
-        // no switch found
-        IOFSwitchBackend sw = new OFSwitch(connection, factory, switchManager, id);
-        sw.setSwitchProperties(description);
-        return sw;
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/NiciraRoleUtils.java b/src/main/java/net/floodlightcontroller/core/internal/NiciraRoleUtils.java
deleted file mode 100644
index bf84d89a9047bf4bdc91bb635e6aecd11d0cbf69..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/NiciraRoleUtils.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import org.projectfloodlight.openflow.protocol.OFControllerRole;
-import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
-import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
-
-/** static utilities to convert between Pre-OF1.2 "Nicira Style" roles and OF1.2+ OpenFlow
- *  standard roles.
- *  @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
- */
-public class NiciraRoleUtils {
-    private NiciraRoleUtils() {}
-
-    public static OFControllerRole niciraToOFRole(OFNiciraControllerRoleReply roleReply) {
-        switch(roleReply.getRole()) {
-            case ROLE_MASTER:
-                return OFControllerRole.ROLE_MASTER;
-            case ROLE_OTHER:
-                return OFControllerRole.ROLE_EQUAL;
-            case ROLE_SLAVE:
-                return OFControllerRole.ROLE_SLAVE;
-            default:
-                throw new IllegalArgumentException("unknown Nicira role value: " + roleReply.getRole());
-        }
-    }
-
-    public static OFNiciraControllerRole ofRoleToNiciraRole(OFControllerRole role) {
-        switch(role) {
-            case ROLE_EQUAL:
-                return OFNiciraControllerRole.ROLE_OTHER;
-            case ROLE_MASTER:
-                return OFNiciraControllerRole.ROLE_MASTER;
-            case ROLE_SLAVE:
-                return OFNiciraControllerRole.ROLE_SLAVE;
-            default:
-                throw new IllegalArgumentException("Unknown role: " + role);
-        }
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..76f819ac904d35ceebd619c7c24da8eeae7e0324
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
@@ -0,0 +1,1788 @@
+package net.floodlightcontroller.core.internal;
+
+import java.io.IOException;
+import java.nio.channels.ClosedChannelException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.IOFSwitch.PortChangeEvent;
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
+import net.floodlightcontroller.core.internal.Controller.Counters;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
+import net.floodlightcontroller.storage.IResultSet;
+import net.floodlightcontroller.storage.StorageException;
+import net.floodlightcontroller.util.LoadMonitor;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.Channels;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
+import org.jboss.netty.handler.timeout.IdleStateEvent;
+import org.jboss.netty.handler.timeout.ReadTimeoutException;
+import org.openflow.protocol.OFBarrierReply;
+import org.openflow.protocol.OFBarrierRequest;
+import org.openflow.protocol.OFEchoReply;
+import org.openflow.protocol.OFEchoRequest;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFFlowRemoved;
+import org.openflow.protocol.OFGetConfigReply;
+import org.openflow.protocol.OFGetConfigRequest;
+import org.openflow.protocol.OFHello;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPortStatus;
+import org.openflow.protocol.OFQueueGetConfigReply;
+import org.openflow.protocol.OFSetConfig;
+import org.openflow.protocol.OFStatisticsReply;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.OFSwitchConfig;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.OFVendor;
+import org.openflow.protocol.OFError.OFBadActionCode;
+import org.openflow.protocol.OFError.OFBadRequestCode;
+import org.openflow.protocol.OFError.OFErrorType;
+import org.openflow.protocol.OFError.OFFlowModFailedCode;
+import org.openflow.protocol.OFError.OFHelloFailedCode;
+import org.openflow.protocol.OFError.OFPortModFailedCode;
+import org.openflow.protocol.OFError.OFQueueOpFailedCode;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.MessageParseException;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.util.HexString;
+import org.openflow.vendor.nicira.OFNiciraVendorData;
+import org.openflow.vendor.nicira.OFRoleReplyVendorData;
+import org.openflow.vendor.nicira.OFRoleRequestVendorData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.bigswitch.floodlight.vendor.OFBigSwitchVendorData;
+import com.bigswitch.floodlight.vendor.OFBsnL2TableSetVendorData;
+
+
+
+/**
+ * Channel handler deals with the switch connection and dispatches
+ * switch messages to the appropriate locations.
+ * @author readams
+ */
+class OFChannelHandler
+    extends IdleStateAwareChannelHandler {
+
+    private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
+
+    private static final long DEFAULT_ROLE_TIMEOUT_MS = 10*1000; // 10 sec
+
+    private final Controller controller;
+    private final Counters counters;
+    private IOFSwitch sw;
+    private Channel channel;
+    // State needs to be volatile because the HandshakeTimeoutHandler
+    // needs to check if the handshake is complete
+    private volatile ChannelState state;
+    private RoleChanger roleChanger;
+    private OFFeaturesReply featuresReply;
+
+    private final ArrayList<OFPortStatus> pendingPortStatusMsg;
+
+    /** transaction Ids to use during handshake. Since only one thread
+     * calls into the OFChannelHandler we don't need atomic.
+     * We will count down
+     */
+    private int handshakeTransactionIds = -1;
+
+
+
+    /**
+     * When we remove a pending role request and set the role on the switch
+     * we use this enum to indicate how we arrived at the decision.
+     * @author gregor
+     */
+    private enum RoleRecvStatus {
+        /** We receveived a role reply message from the switch */
+        RECEIVED_REPLY,
+        /** The switch returned an error indicated that roles are not
+         * supported*/
+        UNSUPPORTED,
+        /** The request timed out */
+        NO_REPLY;
+    }
+    /**
+     * A utility class to handle role requests and replies for this channel.
+     * After a role request is submitted the role changer keeps track of the
+     * pending request, collects the reply (if any) and times out the request
+     * if necessary.
+     *
+     * To simplify role handling we only keep track of the /last/ pending
+     * role reply send to the switch. If multiple requests are pending and
+     * we receive replies for earlier requests we ignore them. However, this
+     * way of handling pending requests implies that we could wait forever if
+     * a new request is submitted before the timeout triggers. If necessary
+     * we could work around that though.
+     * @author gregor
+     */
+    private class RoleChanger {
+        // indicates that a request is currently pending
+        // needs to be volatile to allow correct double-check idiom
+        private volatile boolean requestPending;
+        // the transactiong Id of the pending request
+        private int pendingXid;
+        // the role that's pending
+        private Role pendingRole;
+        // system time in MS when we send the request
+        private long roleSubmitTime;
+        // the timeout to use
+        private final long roleTimeoutMs;
+
+        public RoleChanger(long roleTimeoutMs) {
+            this.requestPending = false;
+            this.roleSubmitTime = 0;
+            this.pendingXid = -1;
+            this.pendingRole = null;
+            this.roleTimeoutMs = roleTimeoutMs;
+        }
+
+        /**
+         * Send NX role request message to the switch requesting the specified
+         * role.
+         *
+         * @param sw switch to send the role request message to
+         * @param role role to request
+         */
+        private int sendNxRoleRequest(Role role)
+                throws IOException {
+
+            int xid = sw.getNextTransactionId();
+            // Convert the role enum to the appropriate integer constant used
+            // in the NX role request message
+            int nxRole = role.toNxRole();
+
+            // Construct the role request message
+            OFVendor roleRequest = (OFVendor)BasicFactory.getInstance()
+                    .getMessage(OFType.VENDOR);
+            roleRequest.setXid(xid);
+            roleRequest.setVendor(OFNiciraVendorData.NX_VENDOR_ID);
+            OFRoleRequestVendorData roleRequestData = new OFRoleRequestVendorData();
+            roleRequestData.setRole(nxRole);
+            roleRequest.setVendorData(roleRequestData);
+            roleRequest.setLengthU(OFVendor.MINIMUM_LENGTH +
+                    roleRequestData.getLength());
+
+            // Send it to the switch
+            sw.write(Collections.<OFMessage>singletonList(roleRequest),
+                     new FloodlightContext());
+
+            return xid;
+        }
+
+        /**
+         * Send a role request for the given role only if no other role
+         * request is currently pending.
+         * @param role The role to send to the switch.
+         * @throws IOException
+         */
+        synchronized void sendRoleRequestIfNotPending(Role role)
+                throws IOException {
+            if (!requestPending)
+                sendRoleRequest(role);
+            else
+                counters.roleNotResentBecauseRolePending.updateCounterWithFlush();
+        }
+
+        /**
+         * Send a role request with the given role to the switch.
+         *
+         * Send a role request with the given role to the switch and update
+         * the pending request and timestamp.
+         *
+         * @param role
+         * @throws IOException
+         */
+        synchronized void sendRoleRequest(Role role) throws IOException {
+            /*
+             * There are three cases to consider for SUPPORTS_NX_ROLE:
+             *
+             * 1) unset. We have neither received a role reply from the
+             *    switch nor has a request timed out. Send a request.
+             * 2) TRUE: We've already send a request earlier and received
+             *    a reply. The switch supports role and we should send one.
+             * 3) FALSE: We have already send a role and received an error.
+             *    The switch does not support roles. Don't send a role request,
+             *    set the switch's role directly.
+             */
+            Boolean supportsNxRole = (Boolean)
+                    sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
+            if ((supportsNxRole != null) && !supportsNxRole) {
+                setSwitchRole(role, RoleRecvStatus.UNSUPPORTED);
+            } else {
+                pendingXid = sendNxRoleRequest(role);
+                pendingRole = role;
+                roleSubmitTime = System.currentTimeMillis();
+                requestPending = true;
+            }
+        }
+
+        /**
+         * Deliver a received role reply and set SWITCH_SUPPORTS_NX_ROLE.
+         *
+         * Check if a request is pending and if the received reply matches the
+         * the expected pending reply (we check both role and xid) we set
+         * the role for the switch/channel.
+         *
+         * If a request is pending but doesn't match the reply we ignore it.
+         *
+         * If no request is pending we disconnect.
+         *
+         * @param xid
+         * @param role
+         * @throws SwitchStateException if no request is pending
+         */
+        synchronized void deliverRoleReply(int xid, Role role) {
+            if (!requestPending) {
+                // Maybe don't disconnect if the role reply we received is
+                // for the same role we are already in.
+                String msg = String.format("Switch: [%s], State: [%s], "
+                                + "received unexpected RoleReply[%s]. "
+                                + "No roles are pending",
+                                OFChannelHandler.this.getSwitchInfoString(),
+                                OFChannelHandler.this.state.toString(),
+                                role);
+                throw new SwitchStateException(msg);
+            }
+
+            if (pendingXid == xid && pendingRole == role) {
+                log.debug("Received role reply message from {}, setting role to {}",
+                          getSwitchInfoString(), role);
+                counters.roleReplyReceived.updateCounterWithFlush();
+                setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY);
+            } else {
+                log.debug("Received stale or unexpected role reply from " +
+                          "switch {} ({}, xid={}). Ignoring. " +
+                          "Waiting for {}, xid={}",
+                          new Object[] { getSwitchInfoString(), role, xid,
+                                         pendingRole, pendingXid });
+            }
+        }
+
+        /**
+         * Called if we receive an  error message. If the xid matches the
+         * pending request we handle it otherwise we ignore it. We also
+         * set SWITCH_SUPPORTS_NX_ROLE to false.
+         *
+         * Note: since we only keep the last pending request we might get
+         * error messages for earlier role requests that we won't be able
+         * to handle
+         * @param xid
+         * @return true if the error was handled by us, false otherwise
+         * @throws SwitchStateException if the error was for the pending
+         * role request but was unexpected
+         */
+        synchronized boolean deliverError(OFError error) {
+            if (!requestPending)
+                return false;
+
+            if (pendingXid == error.getXid()) {
+                boolean isBadRequestError =
+                        (error.getErrorType() == OFError.OFErrorType.
+                        OFPET_BAD_REQUEST.getValue());
+                if (isBadRequestError) {
+                    counters.roleReplyErrorUnsupported.updateCounterWithFlush();
+                    setSwitchRole(pendingRole, RoleRecvStatus.UNSUPPORTED);
+                } else {
+                    // TODO: Is this the right thing to do if we receive
+                    // some other error besides a bad request error?
+                    // Presumably that means the switch did actually
+                    // understand the role request message, but there
+                    // was some other error from processing the message.
+                    // OF 1.2 specifies a OFPET_ROLE_REQUEST_FAILED
+                    // error code, but it doesn't look like the Nicira
+                    // role request has that. Should check OVS source
+                    // code to see if it's possible for any other errors
+                    // to be returned.
+                    // If we received an error the switch is not
+                    // in the correct role, so we need to disconnect it.
+                    // We could also resend the request but then we need to
+                    // check if there are other pending request in which
+                    // case we shouldn't resend. If we do resend we need
+                    // to make sure that the switch eventually accepts one
+                    // of our requests or disconnect the switch. This feels
+                    // cumbersome.
+                    String msg = String.format("Switch: [%s], State: [%s], "
+                                    + "Unexpected error %s in respone to our "
+                                    + "role request for %s.",
+                                    OFChannelHandler.this.getSwitchInfoString(),
+                                    OFChannelHandler.this.state.toString(),
+                                    getErrorString(error),
+                                    pendingRole);
+                    throw new SwitchStateException(msg);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Check if a pending role request has timed out.
+         */
+        void checkTimeout() {
+            if (!requestPending)
+                return;
+            synchronized(this) {
+                if (!requestPending)
+                    return;
+                long now = System.currentTimeMillis();
+                if (now - roleSubmitTime > roleTimeoutMs) {
+                    // timeout triggered.
+                    counters.roleReplyTimeout.updateCounterWithFlush();
+                    setSwitchRole(pendingRole, RoleRecvStatus.NO_REPLY);
+                }
+            }
+        }
+
+        /**
+         * Set the role for this switch / channel.
+         *
+         * If the status indicates that we received a reply we set the role.
+         * If the status indicates otherwise we disconnect the switch if
+         * the role is SLAVE.
+         *
+         * "Setting a role" means setting the appropriate ChannelState,
+         * setting the flags on the switch and
+         * notifying Controller.java about new role of the switch
+         *
+         * @param role The role to set.
+         * @param status How we derived at the decision to set this status.
+         */
+        synchronized private void setSwitchRole(Role role, RoleRecvStatus status) {
+            requestPending = false;
+            if (status == RoleRecvStatus.RECEIVED_REPLY)
+                sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
+            else
+                sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
+            sw.setHARole(role);
+
+            if (role != Role.SLAVE) {
+                OFChannelHandler.this.setState(ChannelState.MASTER);
+                // TODO: should we really activate the switch again if it's
+                // already master??
+                if (log.isDebugEnabled()) {
+                    log.debug("Switch {} activated. Role is now MASTER",
+                              getSwitchInfoString());
+                }
+                controller.switchActivated(OFChannelHandler.this.sw);
+            } else {
+                OFChannelHandler.this.setState(ChannelState.SLAVE);
+                if (status != RoleRecvStatus.RECEIVED_REPLY) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Disconnecting switch {}. Doesn't support role"
+                              + "({}) request and controller is now SLAVE",
+                              getSwitchInfoString(), status);
+                    }
+                    // the disconnect will trigger a switch removed to
+                    // controller so no need to signal anything else
+                    sw.disconnectOutputStream();
+                } else {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Switch {} is now SLAVE",
+                                  getSwitchInfoString());
+                    }
+                    controller.switchDeactivated(OFChannelHandler.this.sw);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * The state machine for handling the switch/channel state.
+     * @author gregor
+     */
+    enum ChannelState {
+        /**
+         * Initial state before channel is connected.
+         */
+        INIT(false) {
+            @Override
+            void
+            processOFMessage(OFChannelHandler h, OFMessage m)
+                    throws IOException {
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFError(OFChannelHandler h, OFError m)
+                    throws IOException {
+                // need to implement since its abstract but it will never
+                // be called
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                unhandledMessageReceived(h, m);
+            }
+        },
+
+        /**
+         * We send a HELLO to the switch and wait for a reply.
+         * Once we receive the reply we send an OFFeaturesRequest and
+         * a request to clear all FlowMods.
+         * Next state is WAIT_FEATURES_REPLY
+         */
+        WAIT_HELLO(false) {
+            @Override
+            void processOFHello(OFChannelHandler h, OFHello m)
+                    throws IOException {
+                h.sendHandShakeMessage(OFType.FEATURES_REQUEST);
+                h.setState(WAIT_FEATURES_REPLY);
+            }
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException {
+                illegalMessageReceived(h, m);
+            }
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatisticsReply  m)
+                    throws IOException {
+                illegalMessageReceived(h, m);
+            }
+            @Override
+            void processOFError(OFChannelHandler h, OFError m) {
+                logErrorDisconnect(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                unhandledMessageReceived(h, m);
+            }
+        },
+
+        /**
+         * We are waiting for a features reply message. Once we receive it
+         * we send a SetConfig request, barrier, and GetConfig request.
+         * Next stats is WAIT_CONFIG_REPLY or WAIT_SET_L2_TABLE_REPLY
+         */
+        WAIT_FEATURES_REPLY(false) {
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException {
+                h.featuresReply = m;
+                if (m.getTables() > 1) {
+                    log.debug("Have {} table for switch {}", m.getTables(),
+                              h.getSwitchInfoString());
+                    // likely supports L2 table extensions. Send set
+                    h.sendHandshakeL2TableSet();
+                    // TODO: no L2 SET reply yet, so fire and forget the set
+                    // table message and move directly to sendHandshakeConfig
+                    h.sendHandshakeSetConfig();
+                    h.setState(WAIT_CONFIG_REPLY);
+                    //h.setState(WAIT_SET_L2_TABLE_REPLY);
+                } else {
+                    h.sendHandshakeSetConfig();
+                    h.setState(WAIT_CONFIG_REPLY);
+                }
+            }
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatisticsReply  m)
+                    throws IOException {
+                illegalMessageReceived(h, m);
+            }
+            @Override
+            void processOFError(OFChannelHandler h, OFError m) {
+                logErrorDisconnect(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                unhandledMessageReceived(h, m);
+            }
+        },
+
+        WAIT_SET_L2_TABLE_REPLY(false) {
+            @Override void processOFVendor(OFChannelHandler h, OFVendor m)
+                    throws IOException {
+                // TODO: actually parse the response
+                h.sendHandshakeSetConfig();
+                h.setState(WAIT_CONFIG_REPLY);
+            };
+
+            @Override
+            void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
+                // do nothing;
+            }
+
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException {
+                // TODO: we could re-set the features reply
+                illegalMessageReceived(h, m);
+            }
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatisticsReply  m)
+                    throws IOException {
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFError(OFChannelHandler h, OFError m) {
+                logErrorDisconnect(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                h.pendingPortStatusMsg.add(m);
+            }
+        },
+
+        /**
+         * We are waiting for a config reply message. Once we receive it
+         * we send a DescriptionStatsRequest to the switch.
+         * Next state: WAIT_DESCRIPTION_STAT_REPLY
+         */
+        WAIT_CONFIG_REPLY(false) {
+            @Override
+            @LogMessageDocs({
+                @LogMessageDoc(level="WARN",
+                        message="Config Reply from {switch} has " +
+                                "miss length set to {length}",
+                        explanation="The controller requires that the switch " +
+                                "use a miss length of 0xffff for correct " +
+                                "function",
+                        recommendation="Use a different switch to ensure " +
+                                "correct function")
+            })
+            void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
+                    throws IOException {
+                if (m.getMissSendLength() == (short)0xffff) {
+                    log.trace("Config Reply from switch {} confirms "
+                            + "miss length set to 0xffff",
+                            h.getSwitchInfoString());
+                } else {
+                    // FIXME: we can't really deal with switches that don't send
+                    // full packets. Shouldn't we drop the connection here?
+                    // FIXME: count??
+                    log.warn("Config Reply from switch {} has"
+                            + "miss length set to {}",
+                            h.getSwitchInfoString(),
+                            m.getMissSendLength());
+                }
+                h.sendHandshakeDescriptionStatsRequest();
+                h.setState(WAIT_DESCRIPTION_STAT_REPLY);
+            }
+
+            @Override
+            void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
+                // do nothing;
+            }
+
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException {
+                // TODO: we could re-set the features reply
+                illegalMessageReceived(h, m);
+            }
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatisticsReply  m)
+                    throws IOException {
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFError(OFChannelHandler h, OFError m) {
+                if (m.getErrorType() == OFErrorType.OFPET_BAD_REQUEST.getValue()
+                        && m.getErrorCode() ==
+                            OFBadRequestCode.OFPBRC_BAD_VENDOR.ordinal()) {
+                    log.debug("Switch {} has multiple tables but does not " +
+                            "support L2 table extension",
+                            h.getSwitchInfoString());
+                    return;
+                }
+                logErrorDisconnect(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                h.pendingPortStatusMsg.add(m);
+            }
+        },
+
+        /**
+         * We are waiting for a OFDescriptionStat message from teh switch.
+         * Once we receive any stat message we try to parse it. If it's not
+         * a description stats message we disconnect. If its the expected
+         * description stats message, we:
+         *    - use the switch driver to bind the switch and get an IOFSwitch
+         *      instance, setup the switch instance
+         *    - setup the IOFSwitch instance
+         *    - add switch to FloodlightProvider and send the intial role
+         *      request to the switch.
+         * Next state: WAIT_INITIAL_ROLE
+         * All following states will have a h.sw instance!
+         */
+        WAIT_DESCRIPTION_STAT_REPLY(false) {
+            @LogMessageDoc(message="Switch {switch info} bound to class " +
+                "{switch driver}, description {switch description}",
+                    explanation="The specified switch has been bound to " +
+                            "a switch driver based on the switch description" +
+                            "received from the switch")
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatisticsReply m) {
+                // Read description, if it has been updated
+                OFDescriptionStatistics description =
+                        new OFDescriptionStatistics();
+                ChannelBuffer data =
+                        ChannelBuffers.buffer(description.getLength());
+                OFStatistics f = m.getFirstStatistics();
+                f.writeTo(data);
+                description.readFrom(data);
+                h.sw = h.controller.getOFSwitchInstance(description);
+                // set switch information
+                // set features reply and channel first so we a DPID and
+                // channel info.
+                h.sw.setFeaturesReply(h.featuresReply);
+                h.sw.setConnected(true);
+                h.sw.setChannel(h.channel);
+                h.sw.setFloodlightProvider(h.controller);
+                h.sw.setThreadPoolService(h.controller.getThreadPoolService());
+                try {
+                    h.sw.setDebugCounterService(h.controller.getDebugCounter());
+                } catch (CounterException e) {
+                    h.counters.switchCounterRegistrationFailed
+                            .updateCounterNoFlush();
+                    log.warn("Could not register counters for switch {} ",
+                              h.getSwitchInfoString(), e);
+                }
+                h.sw.setAccessFlowPriority(h.controller.getAccessFlowPriority());
+                h.sw.setCoreFlowPriority(h.controller.getCoreFlowPriority());
+                for (OFPortStatus ps: h.pendingPortStatusMsg)
+                    handlePortStatusMessage(h, ps, false);
+                h.pendingPortStatusMsg.clear();
+                h.readPropertyFromStorage();
+                log.info("Switch {} bound to class {}, writeThrottle={}," +
+                        " description {}",
+                         new Object[] { h.sw, h.sw.getClass(),
+                                        h.sw.isWriteThrottleEnabled(),
+                                    description });
+                h.sw.startDriverHandshake();
+                if (h.sw.isDriverHandshakeComplete())
+                    h.gotoWaitInitialRoleState();
+                else
+                    h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
+            }
+
+            @Override
+            void processOFError(OFChannelHandler h, OFError m) {
+                logErrorDisconnect(h, m);
+            }
+
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException {
+                // TODO: we could re-set the features reply
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                h.pendingPortStatusMsg.add(m);
+            }
+        },
+
+        WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(false) {
+            @Override
+            void processOFError(OFChannelHandler h, OFError m)
+                    throws IOException {
+                // will never be called. We override processOFMessage
+            }
+
+            @Override
+            void processOFMessage(OFChannelHandler h, OFMessage m)
+                    throws IOException {
+                if (m.getType() == OFType.ECHO_REQUEST)
+                    processOFEchoRequest(h, (OFEchoRequest)m);
+                else {
+                    // FIXME: other message to handle here?
+                    h.sw.processDriverHandshakeMessage(m);
+                    if (h.sw.isDriverHandshakeComplete()) {
+                        h.gotoWaitInitialRoleState();
+                    }
+                }
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                handlePortStatusMessage(h, m, false);
+            }
+        },
+
+        /**
+         * We are waiting for the intial role reply message (or error
+         * indication) from the switch.
+         * Next State: MASTER or SLAVE
+         */
+        WAIT_INITIAL_ROLE(false) {
+            @Override
+            void processOFError(OFChannelHandler h, OFError m) {
+                // role changer will ignore the error if it isn't for it
+                boolean didHandle = h.roleChanger.deliverError(m);
+                if (!didHandle) {
+                    logError(h, m);
+                }
+            }
+
+            @Override
+            void processOFVendor(OFChannelHandler h, OFVendor m)
+                    throws IOException {
+                Role role = extractNiciraRoleReply(h, m);
+                // If role == null it measn the message wasn't really a
+                // Nicira role reply. We ignore this case.
+                if (role != null)
+                    h.roleChanger.deliverRoleReply(m.getXid(), role);
+                else
+                    unhandledMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException {
+                // TODO: we could re-set the features reply
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatisticsReply m) {
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                handlePortStatusMessage(h, m, false);
+
+            }
+        },
+
+        /**
+         * The switch is in MASTER role. We enter this state after a role
+         * reply from the switch is received (or the controller is MASTER
+         * and the switch doesn't support roles). The handshake is complete at
+         * this point. We only leave this state if the switch disconnects or
+         * if we send a role request for SLAVE /and/ receive the role reply for
+         * SLAVE.
+         */
+        MASTER(true) {
+            @LogMessageDoc(level="WARN",
+                message="Received permission error from switch {} while" +
+                         "being master. Reasserting master role.",
+                explanation="The switch has denied an operation likely " +
+                         "indicating inconsistent controller roles",
+                recommendation="This situation can occurs transiently during role" +
+                 " changes. If, however, the condition persists or happens" +
+                 " frequently this indicates a role inconsistency. " +
+                 LogMessageDoc.CHECK_CONTROLLER )
+            @Override
+            void processOFError(OFChannelHandler h, OFError m)
+                    throws IOException {
+                // role changer will ignore the error if it isn't for it
+                boolean didHandle = h.roleChanger.deliverError(m);
+                if (didHandle)
+                    return;
+                if (m.getErrorType() ==
+                        OFErrorType.OFPET_BAD_REQUEST.getValue() &&
+                   m.getErrorCode() ==
+                        OFBadRequestCode.OFPBRC_EPERM.ordinal()) {
+                    // We are the master controller and the switch returned
+                    // a permission error. This is a likely indicator that
+                    // the switch thinks we are slave. Reassert our
+                    // role
+                    // FIXME: this could be really bad during role transitions
+                    // if two controllers are master (even if its only for
+                    // a brief period). We might need to see if these errors
+                    // persist before we reassert
+                    h.counters.epermErrorWhileSwitchIsMaster.updateCounterWithFlush();
+                    log.warn("Received permission error from switch {} while" +
+                             "being master. Reasserting master role.",
+                             h.getSwitchInfoString());
+                    h.controller.reassertRole(h, Role.MASTER);
+                }
+                else if (m.getErrorType() ==
+                        OFErrorType.OFPET_PORT_MOD_FAILED.getValue() &&
+                    m.getErrorCode() ==
+                        OFFlowModFailedCode.OFPFMFC_ALL_TABLES_FULL.ordinal()) {
+                    h.sw.setTableFull(true);
+                }
+                else {
+                    logError(h, m);
+                }
+                h.dispatchMessage(m);
+            }
+
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatisticsReply m) {
+                h.sw.deliverStatisticsReply(m);
+            }
+
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException {
+                h.sw.setFeaturesReply(m);
+                h.sw.deliverOFFeaturesReply(m);
+            }
+
+            @Override
+            void processOFVendor(OFChannelHandler h, OFVendor m)
+                    throws IOException {
+                Role role = extractNiciraRoleReply(h, m);
+                // If role == null it means the message wasn't really a
+                // Nicira role reply. We ignore just dispatch it to the
+                // OFMessage listenersa in this case.
+                if (role != null)
+                    h.roleChanger.deliverRoleReply(m.getXid(), role);
+                else
+                    h.dispatchMessage(m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                handlePortStatusMessage(h, m, true);
+            }
+
+            @Override
+            void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
+                h.dispatchMessage(m);
+            }
+
+            @Override
+            void processOFFlowRemoved(OFChannelHandler h,
+                                      OFFlowRemoved m) throws IOException {
+                h.dispatchMessage(m);
+            }
+            @Override
+            void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) throws IOException{
+                h.dispatchMessage(m);
+            }
+        },
+
+        /**
+         * The switch is in SLAVE role. We enter this state after a role
+         * reply from the switch is received. The handshake is complete at
+         * this point. We only leave this state if the switch disconnects or
+         * if we send a role request for MASTER /and/ receive the role reply for
+         * MASTER.
+         * TODO: CURRENTLY, WE DO NOT DISPATCH ANY MESSAGE IN SLAVE.
+         */
+        SLAVE(true) {
+            @Override
+            void processOFError(OFChannelHandler h, OFError m)
+                    throws IOException {
+                // role changer will ignore the error if it isn't for it
+                boolean didHandle = h.roleChanger.deliverError(m);
+                if (!didHandle) {
+                    logError(h, m);
+                }
+            }
+
+
+
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatisticsReply m) {
+                // FIXME.
+                h.sw.deliverStatisticsReply(m);
+            }
+
+            @Override
+            void processOFVendor(OFChannelHandler h, OFVendor m)
+                    throws IOException {
+                Role role = extractNiciraRoleReply(h, m);
+                // If role == null it means the message wasn't really a
+                // Nicira role reply. We ignore it.
+                if (role != null)
+                    h.roleChanger.deliverRoleReply(m.getXid(), role);
+                else
+                    unhandledMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException {
+                // do nothing
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                // do nothing
+            }
+
+            @Override
+            @LogMessageDoc(level="WARN",
+                message="Received PacketIn from switch {} while" +
+                         "being slave. Reasserting slave role.",
+                explanation="The switch has receive a PacketIn despite being " +
+                         "in slave role indicating inconsistent controller roles",
+                recommendation="This situation can occurs transiently during role" +
+                         " changes. If, however, the condition persists or happens" +
+                         " frequently this indicates a role inconsistency. " +
+                         LogMessageDoc.CHECK_CONTROLLER )
+            void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
+                // we don't expect packetIn while slave, reassert we are slave
+                h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush();
+                log.warn("Received PacketIn from switch {} while" +
+                         "being slave. Reasserting slave role.", h.sw);
+                h.controller.reassertRole(h, Role.SLAVE);
+            }
+        };
+
+        private final boolean handshakeComplete;
+        ChannelState(boolean handshakeComplete) {
+            this.handshakeComplete = handshakeComplete;
+        }
+
+        /**
+         * Is this a state in which the handshake has completed?
+         * @return true if the handshake is complete
+         */
+        public boolean isHandshakeComplete() {
+            return handshakeComplete;
+        }
+
+        /**
+         * Get a string specifying the switch connection, state, and
+         * message received. To be used as message for SwitchStateException
+         * or log messages
+         * @param h The channel handler (to get switch information_
+         * @param m The OFMessage that has just been received
+         * @param details A string giving more details about the exact nature
+         * of the problem.
+         * @return
+         */
+        // needs to be protected because enum members are acutally subclasses
+        protected String getSwitchStateMessage(OFChannelHandler h,
+                                                      OFMessage m,
+                                                      String details) {
+            return String.format("Switch: [%s], State: [%s], received: [%s]"
+                                 + ", details: %s",
+                                 h.getSwitchInfoString(),
+                                 this.toString(),
+                                 m.getType().toString(),
+                                 details);
+        }
+
+        /**
+         * We have an OFMessage we didn't expect given the current state and
+         * we want to treat this as an error.
+         * We currently throw an exception that will terminate the connection
+         * However, we could be more forgiving
+         * @param h the channel handler that received the message
+         * @param m the message
+         * @throws SwitchStateExeption we always through the execption
+         */
+        // needs to be protected because enum members are acutally subclasses
+        protected void illegalMessageReceived(OFChannelHandler h, OFMessage m) {
+            String msg = getSwitchStateMessage(h, m,
+                    "Switch should never send this message in the current state");
+            throw new SwitchStateException(msg);
+
+        }
+
+        /**
+         * We have an OFMessage we didn't expect given the current state and
+         * we want to ignore the message
+         * @param h the channel handler the received the message
+         * @param m the message
+         */
+        protected void unhandledMessageReceived(OFChannelHandler h,
+                                                OFMessage m) {
+            h.counters.unhandledMessage.updateCounterNoFlush();
+            if (log.isDebugEnabled()) {
+                String msg = getSwitchStateMessage(h, m,
+                        "Ignoring unexpected message");
+                log.debug(msg);
+            }
+        }
+
+        /**
+         * Log an OpenFlow error message from a switch
+         * @param sw The switch that sent the error
+         * @param error The error message
+         */
+        @LogMessageDoc(level="ERROR",
+                message="Error {error type} {error code} from {switch} " +
+                        "in state {state}",
+                explanation="The switch responded with an unexpected error" +
+                        "to an OpenFlow message from the controller",
+                recommendation="This could indicate improper network operation. " +
+                        "If the problem persists restarting the switch and " +
+                        "controller may help."
+                )
+        protected void logError(OFChannelHandler h, OFError error) {
+            log.error("{} from switch {} in state {}",
+                      new Object[] {
+                          getErrorString(error),
+                          h.getSwitchInfoString(),
+                          this.toString()});
+        }
+
+        /**
+         * Log an OpenFlow error message from a switch and disconnect the
+         * channel
+         * @param sw The switch that sent the error
+         * @param error The error message
+         */
+        protected void logErrorDisconnect(OFChannelHandler h, OFError error) {
+            logError(h, error);
+            h.channel.disconnect();
+        }
+
+
+        /**
+         * Extract the role from an OFVendor message.
+         *
+         * Extract the role from an OFVendor message if the message is a
+         * Nicira role reply. Otherwise return null.
+         *
+         * @param h The channel handler receiving the message
+         * @param vendorMessage The vendor message to parse.
+         * @return The role in the message if the message is a Nicira role
+         * reply, null otherwise.
+         * @throws SwitchStateException If the message is a Nicira role reply
+         * but the numeric role value is unknown.
+         * FIXME: The message parser should make sure that the Nicira role is
+         * actually valid. Why do we need to take care of it ?!?
+         */
+        protected Role extractNiciraRoleReply(OFChannelHandler h,
+                                              OFVendor vendorMessage) {
+            int vendor = vendorMessage.getVendor();
+            if (vendor != OFNiciraVendorData.NX_VENDOR_ID)
+                return null;
+            if (! (vendorMessage.getVendorData() instanceof OFRoleReplyVendorData))
+                return null;
+            OFRoleReplyVendorData roleReplyVendorData =
+                    (OFRoleReplyVendorData) vendorMessage.getVendorData();
+            Role role = Role.fromNxRole(roleReplyVendorData.getRole());
+            if (role == null) {
+                String msg = String.format("Switch: [%s], State: [%s], "
+                        + "received NX_ROLE_REPLY with invalid role "
+                        + "value %d",
+                        h.getSwitchInfoString(),
+                        this.toString(),
+                        roleReplyVendorData.getRole());
+                throw new SwitchStateException(msg);
+            }
+            return role;
+        }
+
+        /**
+         * Handle a port status message.
+         *
+         * Handle a port status message by updating the port maps in the
+         * IOFSwitch instance and notifying Controller about the change so
+         * it can dispatch a switch update.
+         *
+         * @param h The OFChannelHhandler that received the message
+         * @param m The PortStatus message we received
+         * @param doNotify if true switch port changed events will be
+         * dispatched
+         */
+        protected void handlePortStatusMessage(OFChannelHandler h,
+                                               OFPortStatus m,
+                                               boolean doNotify) {
+            if (h.sw == null) {
+                String msg = getSwitchStateMessage(h, m,
+                        "State machine error: switch is null. Should never " +
+                        "happen");
+                throw new SwitchStateException(msg);
+            }
+            Collection<PortChangeEvent> changes = h.sw.processOFPortStatus(m);
+            if (doNotify) {
+                for (PortChangeEvent ev: changes)
+                    h.controller.notifyPortChanged(h.sw, ev.port, ev.type);
+            }
+        }
+
+        /**
+         * Process an OF message received on the channel and
+         * update state accordingly.
+         *
+         * The main "event" of the state machine. Process the received message,
+         * send follow up message if required and update state if required.
+         *
+         * Switches on the message type and calls more specific event handlers
+         * for each individual OF message type. If we receive a message that
+         * is supposed to be sent from a controller to a switch we throw
+         * a SwitchStateExeption.
+         *
+         * The more specific handlers can also throw SwitchStateExceptions
+         *
+         * @param h The OFChannelHandler that received the message
+         * @param m The message we received.
+         * @throws SwitchStateException
+         * @throws IOException
+         */
+        void processOFMessage(OFChannelHandler h, OFMessage m) throws IOException {
+            h.roleChanger.checkTimeout();
+            switch(m.getType()) {
+                case HELLO:
+                    processOFHello(h, (OFHello)m);
+                    break;
+                case BARRIER_REPLY:
+                    processOFBarrierReply(h, (OFBarrierReply)m);
+                    break;
+                case ECHO_REPLY:
+                    processOFEchoReply(h, (OFEchoReply)m);
+                    break;
+                case ECHO_REQUEST:
+                    processOFEchoRequest(h, (OFEchoRequest)m);
+                    break;
+                case ERROR:
+                    processOFError(h, (OFError)m);
+                    break;
+                case FEATURES_REPLY:
+                    processOFFeaturesReply(h, (OFFeaturesReply)m);
+                    break;
+                case FLOW_REMOVED:
+                    processOFFlowRemoved(h, (OFFlowRemoved)m);
+                    break;
+                case GET_CONFIG_REPLY:
+                    processOFGetConfigReply(h, (OFGetConfigReply)m);
+                    break;
+                case PACKET_IN:
+                    processOFPacketIn(h, (OFPacketIn)m);
+                    break;
+                case PORT_STATUS:
+                    processOFPortStatus(h, (OFPortStatus)m);
+                    break;
+                case QUEUE_GET_CONFIG_REPLY:
+                    processOFQueueGetConfigReply(h, (OFQueueGetConfigReply)m);
+                    break;
+                case STATS_REPLY:
+                    processOFStatisticsReply(h, (OFStatisticsReply)m);
+                    break;
+                case VENDOR:
+                    processOFVendor(h, (OFVendor)m);
+                    break;
+                // The following messages are sent to switches. The controller
+                // should never receive them
+                case SET_CONFIG:
+                case GET_CONFIG_REQUEST:
+                case PACKET_OUT:
+                case PORT_MOD:
+                case QUEUE_GET_CONFIG_REQUEST:
+                case BARRIER_REQUEST:
+                case STATS_REQUEST:
+                case FEATURES_REQUEST:
+                case FLOW_MOD:
+                    illegalMessageReceived(h, m);
+                    break;
+            }
+        }
+
+        /*-----------------------------------------------------------------
+         * Default implementation for message handlers in any state.
+         *
+         * Individual states must override these if they want a behavior
+         * that differs from the default.
+         *
+         * In general, these handlers simply ignore the message and do
+         * nothing.
+         *
+         * There are some exceptions though, since some messages really
+         * are handled the same way in every state (e.g., ECHO_REQUST) or
+         * that are only valid in a single state (e.g., HELLO, GET_CONFIG_REPLY
+         -----------------------------------------------------------------*/
+
+        void processOFHello(OFChannelHandler h, OFHello m) throws IOException {
+            // we only expect hello in the WAIT_HELLO state
+            illegalMessageReceived(h, m);
+        }
+
+        void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
+                throws IOException {
+            // Silently ignore.
+        }
+
+        void processOFEchoRequest(OFChannelHandler h, OFEchoRequest m)
+            throws IOException {
+            OFEchoReply reply = (OFEchoReply)
+                    BasicFactory.getInstance().getMessage(OFType.ECHO_REPLY);
+            reply.setXid(m.getXid());
+            reply.setPayload(m.getPayload());
+            reply.setLengthU(m.getLengthU());
+            h.channel.write(Collections.singletonList(reply));
+        }
+
+        void processOFEchoReply(OFChannelHandler h, OFEchoReply m)
+            throws IOException {
+            // Do nothing with EchoReplies !!
+        }
+
+        // no default implementation for OFError
+        // every state must override it
+        abstract void processOFError(OFChannelHandler h, OFError m)
+                throws IOException;
+
+
+        void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                throws IOException {
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFFlowRemoved(OFChannelHandler h, OFFlowRemoved m)
+            throws IOException {
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
+                throws IOException {
+            // we only expect config replies in the WAIT_CONFIG_REPLY state
+            // TODO: might use two different strategies depending on whether
+            // we got a miss length of 64k or not.
+            illegalMessageReceived(h, m);
+        }
+
+        void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
+                throws IOException {
+            unhandledMessageReceived(h, m);
+        }
+
+        // bi default implementation. Every state needs to handle it.
+        abstract void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                throws IOException;
+
+        void processOFQueueGetConfigReply(OFChannelHandler h,
+                                          OFQueueGetConfigReply m)
+                throws IOException {
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFStatisticsReply(OFChannelHandler h, OFStatisticsReply m)
+                throws IOException {
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFVendor(OFChannelHandler h, OFVendor m)
+                throws IOException {
+            // TODO: it might make sense to parse the vendor message here
+            // into the known vendor messages we support and then call more
+            // spefic event handlers
+            unhandledMessageReceived(h, m);
+        }
+    }
+
+
+    /**
+     * Create a new unconnecte OFChannelHandler.
+     * @param controller
+     */
+    OFChannelHandler(Controller controller) {
+        this.controller = controller;
+        this.counters = controller.getCounters();
+        this.roleChanger = new RoleChanger(DEFAULT_ROLE_TIMEOUT_MS);
+        this.state = ChannelState.INIT;
+        this.pendingPortStatusMsg = new ArrayList<OFPortStatus>();
+    }
+
+    /**
+     * Is this a state in which the handshake has completed?
+     * @return true if the handshake is complete
+     */
+    boolean isHandshakeComplete() {
+        return this.state.isHandshakeComplete();
+    }
+
+    /**
+     * Forwards to RoleChanger. See there.
+     * @param role
+     */
+    void sendRoleRequestIfNotPending(Role role) {
+        try {
+            roleChanger.sendRoleRequestIfNotPending(role);
+        } catch (IOException e) {
+             log.error("Disconnecting switch {} due to IO Error: {}",
+                              getSwitchInfoString(), e.getMessage());
+             channel.close();
+        }
+    }
+
+    /**
+     * Forwards to RoleChanger. See there.
+     * @param role
+     */
+    void sendRoleRequest(Role role) {
+        try {
+            roleChanger.sendRoleRequest(role);
+        } catch (IOException e) {
+             log.error("Disconnecting switch {} due to IO Error: {}",
+                              getSwitchInfoString(), e.getMessage());
+             channel.close();
+        }
+    }
+
+
+    @Override
+    @LogMessageDoc(message="New switch connection from {ip address}",
+                   explanation="A new switch has connected from the " +
+                            "specified IP address")
+    public void channelConnected(ChannelHandlerContext ctx,
+                                 ChannelStateEvent e) throws Exception {
+        counters.switchConnected.updateCounterWithFlush();
+        channel = e.getChannel();
+        log.info("New switch connection from {}",
+                 channel.getRemoteAddress());
+        sendHandShakeMessage(OFType.HELLO);
+        setState(ChannelState.WAIT_HELLO);
+    }
+
+    @Override
+    @LogMessageDoc(message="Disconnected switch {switch information}",
+                   explanation="The specified switch has disconnected.")
+    public void channelDisconnected(ChannelHandlerContext ctx,
+                                    ChannelStateEvent e) throws Exception {
+        controller.removeSwitchChannel(this);
+        if (this.sw != null) {
+            // TODO: switchDisconnected() will check if we've previously
+            // activated the switch. Nevertheless, we might want to check
+            // here as well.
+            controller.switchDisconnected(this.sw);
+            this.sw.setConnected(false);
+        }
+
+        log.info("Disconnected switch {}", getSwitchInfoString());
+    }
+
+    @Override
+    @LogMessageDocs({
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch} due to read timeout",
+                explanation="The connected switch has failed to send any " +
+                            "messages or respond to echo requests",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch}: failed to " +
+                        "complete handshake",
+                explanation="The switch did not respond correctly " +
+                            "to handshake messages",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch} due to IO Error: {}",
+                explanation="There was an error communicating with the switch",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch} due to switch " +
+                        "state error: {error}",
+                explanation="The switch sent an unexpected message",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch} due to " +
+                        "message parse failure",
+                explanation="Could not parse a message from the switch",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Terminating controller due to storage exception",
+                explanation=Controller.ERROR_DATABASE,
+                recommendation=LogMessageDoc.CHECK_CONTROLLER),
+        @LogMessageDoc(level="ERROR",
+                message="Could not process message: queue full",
+                explanation="OpenFlow messages are arriving faster than " +
+                            " the controller can process them.",
+                recommendation=LogMessageDoc.CHECK_CONTROLLER),
+        @LogMessageDoc(level="ERROR",
+                message="Error while processing message " +
+                        "from switch {switch} {cause}",
+                explanation="An error occurred processing the switch message",
+                recommendation=LogMessageDoc.GENERIC_ACTION)
+    })
+    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
+            throws Exception {
+        if (e.getCause() instanceof ReadTimeoutException) {
+            // switch timeout
+            log.error("Disconnecting switch {} due to read timeout",
+                                 getSwitchInfoString());
+            counters.switchDisconnectReadTimeout.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof HandshakeTimeoutException) {
+            log.error("Disconnecting switch {}: failed to complete handshake",
+                      getSwitchInfoString());
+            counters.switchDisconnectHandshakeTimeout.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof ClosedChannelException) {
+            log.debug("Channel for sw {} already closed", getSwitchInfoString());
+        } else if (e.getCause() instanceof IOException) {
+            log.error("Disconnecting switch {} due to IO Error: {}",
+                      getSwitchInfoString(), e.getCause().getMessage());
+            if (log.isDebugEnabled()) {
+                // still print stack trace if debug is enabled
+                log.debug("StackTrace for previous Exception: ", e.getCause());
+            }
+            counters.switchDisconnectIOError.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof SwitchStateException) {
+            log.error("Disconnecting switch {} due to switch state error: {}",
+                      getSwitchInfoString(), e.getCause().getMessage());
+            if (log.isDebugEnabled()) {
+                // still print stack trace if debug is enabled
+                log.debug("StackTrace for previous Exception: ", e.getCause());
+            }
+            counters.switchDisconnectSwitchStateException.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof MessageParseException) {
+            log.error("Disconnecting switch "
+                                 + getSwitchInfoString() +
+                                 " due to message parse failure",
+                                 e.getCause());
+            counters.switchDisconnectParseError.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof StorageException) {
+            log.error("Terminating controller due to storage exception",
+                      e.getCause());
+            this.controller.terminate();
+        } else if (e.getCause() instanceof RejectedExecutionException) {
+            log.warn("Could not process message: queue full");
+            counters.rejectedExecutionException.updateCounterWithFlush();
+        } else {
+            log.error("Error while processing message from switch "
+                                 + getSwitchInfoString()
+                                 + "state " + this.state, e.getCause());
+            counters.switchDisconnectOtherException.updateCounterWithFlush();
+            ctx.getChannel().close();
+        }
+    }
+
+    @Override
+    public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
+            throws Exception {
+        OFMessage m = BasicFactory.getInstance().getMessage(OFType.ECHO_REQUEST);
+        e.getChannel().write(Collections.singletonList(m));
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
+            throws Exception {
+        if (e.getMessage() instanceof List) {
+            @SuppressWarnings("unchecked")
+            List<OFMessage> msglist = (List<OFMessage>)e.getMessage();
+
+            LoadMonitor.LoadLevel loadlevel;
+            int packets_dropped = 0;
+            int packets_allowed = 0;
+            int lldps_allowed = 0;
+
+            if (this.controller.overload_drop) {
+                loadlevel = this.controller.loadmonitor.getLoadLevel();
+            }
+            else {
+                loadlevel = LoadMonitor.LoadLevel.OK;
+            }
+
+            for (OFMessage ofm : msglist) {
+                counters.messageReceived.updateCounterNoFlush();
+                // Per-switch input throttling
+                if (sw != null && sw.inputThrottled(ofm)) {
+                    counters.messageInputThrottled.updateCounterNoFlush();
+                    continue;
+                }
+                try {
+                    if (this.controller.overload_drop &&
+                        !loadlevel.equals(LoadMonitor.LoadLevel.OK)) {
+                        switch (ofm.getType()) {
+                        case PACKET_IN:
+                            switch (loadlevel) {
+                            case VERYHIGH:
+                                // Drop all packet-ins, including LLDP/BDDPs
+                                packets_dropped++;
+                                continue;
+                            case HIGH:
+                                // Drop all packet-ins, except LLDP/BDDPs
+                                byte[] data = ((OFPacketIn)ofm).getPacketData();
+                                if (data.length > 14) {
+                                    if (((data[12] == (byte)0x88) &&
+                                         (data[13] == (byte)0xcc)) ||
+                                        ((data[12] == (byte)0x89) &&
+                                         (data[13] == (byte)0x42))) {
+                                        lldps_allowed++;
+                                        packets_allowed++;
+                                        break;
+                                    }
+                                }
+                                packets_dropped++;
+                                continue;
+                            default:
+                                // Load not high, go ahead and process msg
+                                packets_allowed++;
+                                break;
+                            }
+                            break;
+                        default:
+                            // Process all non-packet-ins
+                            packets_allowed++;
+                            break;
+                        }
+                    }
+
+                    // Do the actual packet processing
+                    state.processOFMessage(this, ofm);
+
+                }
+                catch (Exception ex) {
+                    // We are the last handler in the stream, so run the
+                    // exception through the channel again by passing in
+                    // ctx.getChannel().
+                    Channels.fireExceptionCaught(ctx.getChannel(), ex);
+                }
+            }
+
+            if (loadlevel != LoadMonitor.LoadLevel.OK) {
+                if (log.isDebugEnabled()) {
+                    log.debug(
+                        "Overload: Detected {}, packets dropped={}",
+                        loadlevel.toString(), packets_dropped);
+                    log.debug(
+                        "Overload: Packets allowed={} (LLDP/BDDPs allowed={})",
+                        packets_allowed, lldps_allowed);
+                }
+            }
+            // Flush all thread local queues etc. generated by this train
+            // of messages.
+            this.controller.flushAll();
+        }
+        else {
+            Channels.fireExceptionCaught(ctx.getChannel(),
+                                         new AssertionError("Message received from Channel is not a list"));
+        }
+    }
+
+
+    /**
+     * Get a useable error string from the OFError.
+     * @param error
+     * @return
+     */
+    public static String getErrorString(OFError error) {
+        // TODO: this really should be OFError.toString. Sigh.
+        int etint = 0xffff & error.getErrorType();
+        if (etint < 0 || etint >= OFErrorType.values().length) {
+            return String.format("Unknown error type %d", etint);
+        }
+        OFErrorType et = OFErrorType.values()[etint];
+        switch (et) {
+            case OFPET_HELLO_FAILED:
+                OFHelloFailedCode hfc =
+                    OFHelloFailedCode.values()[0xffff & error.getErrorCode()];
+                return String.format("Error %s %s", et, hfc);
+            case OFPET_BAD_REQUEST:
+                OFBadRequestCode brc =
+                    OFBadRequestCode.values()[0xffff & error.getErrorCode()];
+                return String.format("Error %s %s", et, brc);
+            case OFPET_BAD_ACTION:
+                OFBadActionCode bac =
+                    OFBadActionCode.values()[0xffff & error.getErrorCode()];
+                return String.format("Error %s %s", et, bac);
+            case OFPET_FLOW_MOD_FAILED:
+                OFFlowModFailedCode fmfc =
+                    OFFlowModFailedCode.values()[0xffff & error.getErrorCode()];
+                return String.format("Error %s %s", et, fmfc);
+            case OFPET_PORT_MOD_FAILED:
+                OFPortModFailedCode pmfc =
+                    OFPortModFailedCode.values()[0xffff & error.getErrorCode()];
+                return String.format("Error %s %s", et, pmfc);
+            case OFPET_QUEUE_OP_FAILED:
+                OFQueueOpFailedCode qofc =
+                    OFQueueOpFailedCode.values()[0xffff & error.getErrorCode()];
+                return String.format("Error %s %s", et, qofc);
+            case OFPET_VENDOR_ERROR:
+                // no codes known for vendor error
+                return String.format("Error %s", et);
+        }
+        return null;
+    }
+
+    private void dispatchMessage(OFMessage m) throws IOException {
+        // handleMessage will count
+        this.controller.handleMessage(this.sw, m, null);
+    }
+
+    /**
+     * Return a string describing this switch based on the already available
+     * information (DPID and/or remote socket)
+     * @return
+     */
+    private String getSwitchInfoString() {
+        if (sw != null)
+            return sw.toString();
+        String channelString;
+        if (channel == null || channel.getRemoteAddress() == null) {
+            channelString = "?";
+        } else {
+            channelString = channel.getRemoteAddress().toString();
+        }
+        String dpidString;
+        if (featuresReply == null) {
+            dpidString = "?";
+        } else {
+            dpidString = HexString.toHexString(featuresReply.getDatapathId());
+        }
+        return String.format("[%s DPID[%s]]", channelString, dpidString);
+    }
+
+    /**
+     * Update the channels state. Only called from the state machine.
+     * TODO: enforce restricted state transitions
+     * @param state
+     */
+    private void setState(ChannelState state) {
+        this.state = state;
+    }
+
+    /**
+     * Send a message to the switch using the handshake transactions ids.
+     * @throws IOException
+     */
+    private void sendHandShakeMessage(OFType type) throws IOException {
+        // Send initial Features Request
+        OFMessage m = BasicFactory.getInstance().getMessage(type);
+        m.setXid(handshakeTransactionIds--);
+        channel.write(Collections.singletonList(m));
+    }
+
+    /**
+     * Send an setL2TableSet message to the switch.
+     */
+    private void sendHandshakeL2TableSet() {
+        OFVendor l2TableSet = (OFVendor)
+                BasicFactory.getInstance().getMessage(OFType.VENDOR);
+        l2TableSet.setXid(handshakeTransactionIds--);
+        OFBsnL2TableSetVendorData l2TableSetData =
+                new OFBsnL2TableSetVendorData(true,
+                                              controller.getCoreFlowPriority());
+        l2TableSet.setVendor(OFBigSwitchVendorData.BSN_VENDOR_ID);
+        l2TableSet.setVendorData(l2TableSetData);
+        l2TableSet.setLengthU(OFVendor.MINIMUM_LENGTH +
+                              l2TableSetData.getLength());
+        channel.write(Collections.singletonList(l2TableSet));
+    }
+
+
+    private void gotoWaitInitialRoleState() {
+        // We need to set the new state /before/ we call addSwitchChannel
+        // because addSwitchChannel will eventually call setRole
+        // which can in turn decide that the switch doesn't support
+        // roles and transition the state straight to MASTER.
+        setState(ChannelState.WAIT_INITIAL_ROLE);
+        controller.addSwitchChannelAndSendInitialRole(this);
+    }
+
+    /**
+     * Send the configuration requests to tell the switch we want full
+     * packets
+     * @throws IOException
+     */
+    private void sendHandshakeSetConfig() throws IOException {
+        List<OFMessage> msglist = new ArrayList<OFMessage>(3);
+
+        // Ensure we receive the full packet via PacketIn
+        // FIXME: We don't set the reassembly flags.
+        OFSetConfig configSet = (OFSetConfig) BasicFactory.getInstance()
+                .getMessage(OFType.SET_CONFIG);
+        configSet.setMissSendLength((short) 0xffff)
+            .setLengthU(OFSwitchConfig.MINIMUM_LENGTH);
+        configSet.setXid(handshakeTransactionIds--);
+        msglist.add(configSet);
+
+        // Barrier
+        OFBarrierRequest barrier = (OFBarrierRequest) BasicFactory.getInstance()
+                .getMessage(OFType.BARRIER_REQUEST);
+        barrier.setXid(handshakeTransactionIds--);
+        msglist.add(barrier);
+
+        // Verify (need barrier?)
+        OFGetConfigRequest configReq = (OFGetConfigRequest)
+                BasicFactory.getInstance().getMessage(OFType.GET_CONFIG_REQUEST);
+        configReq.setXid(handshakeTransactionIds--);
+        msglist.add(configReq);
+        channel.write(msglist);
+    }
+
+    /**
+     * send a description state request
+     * @throws IOException
+     */
+    private void sendHandshakeDescriptionStatsRequest() throws IOException {
+        // Get Description to set switch-specific flags
+        OFStatisticsRequest req = new OFStatisticsRequest();
+        req.setStatisticType(OFStatisticsType.DESC);
+        req.setXid(handshakeTransactionIds--);
+
+        channel.write(Collections.singletonList(req));
+    }
+
+
+    /**
+     * Read switch properties from storage and set switch attributes accordingly
+     */
+    private void readPropertyFromStorage() {
+        // At this time, also set other switch properties from storage
+        boolean is_core_switch = false;
+        IResultSet resultSet = null;
+        try {
+            String swid = sw.getStringId();
+            resultSet = this.controller.getStorageSourceService()
+                    .getRow(Controller.SWITCH_CONFIG_TABLE_NAME, swid);
+            for (Iterator<IResultSet> it =
+                    resultSet.iterator(); it.hasNext();) {
+                is_core_switch = it.next()
+                        .getBoolean(Controller.SWITCH_CONFIG_CORE_SWITCH);
+                if (log.isDebugEnabled()) {
+                    log.debug("Reading SWITCH_IS_CORE_SWITCH " +
+                            "config for switch={}, is-core={}",
+                            sw, is_core_switch);
+                }
+            }
+        }
+        finally {
+            if (resultSet != null)
+                resultSet.close();
+        }
+        if (is_core_switch) {
+            sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH,
+                            Boolean.valueOf(true));
+        }
+    }
+
+    ChannelState getStateForTesting() {
+        return state;
+    }
+
+    void useRoleChangerWithOtherTimeoutForTesting(long roleTimeoutMs) {
+        roleChanger = new RoleChanger(roleTimeoutMs);
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java b/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java
new file mode 100644
index 0000000000000000000000000000000000000000..eca67bd97ca289fa5246edbb4196d9f0216e98c5
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java
@@ -0,0 +1,72 @@
+/**
+ *    Copyright 2012, Big Switch Networks, Inc. 
+ * 
+ *    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.core.internal;
+
+import java.util.concurrent.TimeUnit;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+
+/**
+ * A concrete implementation that handles asynchronously receiving
+ * OFFeaturesReply
+ * 
+ * @author Shudong Zhou
+ */
+public class OFFeaturesReplyFuture extends
+        OFMessageFuture<OFFeaturesReply> {
+
+    protected volatile boolean finished;
+
+    public OFFeaturesReplyFuture(IThreadPoolService tp,
+            IOFSwitch sw, int transactionId) {
+        super(tp, sw, OFType.FEATURES_REPLY, transactionId);
+        init();
+    }
+
+    public OFFeaturesReplyFuture(IThreadPoolService tp,
+            IOFSwitch sw, int transactionId, long timeout, TimeUnit unit) {
+        super(tp, sw, OFType.FEATURES_REPLY, transactionId, timeout, unit);
+        init();
+    }
+
+    private void init() {
+        this.finished = false;
+        this.result = null;
+    }
+
+    @Override
+    protected void handleReply(IOFSwitch sw, OFMessage msg) {
+        this.result = (OFFeaturesReply) msg;
+        this.finished = true;
+    }
+
+    @Override
+    protected boolean isFinished() {
+        return finished;
+    }
+
+    @Override
+    protected void unRegister() {
+        super.unRegister();
+        sw.cancelFeaturesReply(transactionId);
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java b/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..25edf396c943dfce728f79610910162ebd608a12
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java
@@ -0,0 +1,60 @@
+/**
+*    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.core.internal;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.frame.FrameDecoder;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.OFMessageFactory;
+
+/**
+ * Decode an openflow message from a Channel, for use in a netty
+ * pipeline
+ * @author readams
+ */
+public class OFMessageDecoder extends FrameDecoder {
+
+    OFMessageFactory factory = BasicFactory.getInstance();
+    
+    @Override
+    protected Object decode(ChannelHandlerContext ctx, Channel channel,
+                            ChannelBuffer buffer) throws Exception {
+        if (!channel.isConnected()) {
+            // In testing, I see decode being called AFTER decode last.
+            // This check avoids that from reading curroupted frames
+            return null;
+        }
+
+        List<OFMessage> message = factory.parseMessage(buffer);
+        return message;
+    }
+
+    @Override
+    protected Object decodeLast(ChannelHandlerContext ctx, Channel channel,
+                            ChannelBuffer buffer) throws Exception {
+        // This is not strictly needed atthis time. It is used to detect
+        // connection reset detection from netty (for debug)
+        return null;
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java b/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..6be5f9a1d524b51e85af216f70d9a4800aed0ad6
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java
@@ -0,0 +1,56 @@
+/**
+*    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.core.internal;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
+import org.openflow.protocol.OFMessage;
+
+/**
+ * Encode an openflow message for output into a ChannelBuffer, for use in a
+ * netty pipeline
+ * @author readams
+ */
+public class OFMessageEncoder extends OneToOneEncoder {
+
+    @Override
+    protected Object encode(ChannelHandlerContext ctx, Channel channel,
+                            Object msg) throws Exception {
+        if (!(  msg instanceof List))
+            return msg;
+
+        @SuppressWarnings("unchecked")
+        List<OFMessage> msglist = (List<OFMessage>)msg;
+        int size = 0;
+        for (OFMessage ofm :  msglist) {
+                size += ofm.getLengthU();
+        }
+
+        ChannelBuffer buf = ChannelBuffers.buffer(size);;
+        for (OFMessage ofm :  msglist) {
+            ofm.writeTo(buf);
+        }
+        return buf;
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFMessageFuture.java b/src/main/java/net/floodlightcontroller/core/internal/OFMessageFuture.java
new file mode 100644
index 0000000000000000000000000000000000000000..1fc9c135330d6189652fca4b37aac903bce5bf0d
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageFuture.java
@@ -0,0 +1,171 @@
+/**
+*    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.core.internal;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+
+/**
+ * A Future object used to retrieve asynchronous OFMessage replies. Unregisters
+ * and cancels itself by default after 60 seconds. This class is meant to be
+ * sub-classed and proper behavior added to the handleReply method, and
+ * termination of the Future to be handled in the isFinished method.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public abstract class OFMessageFuture<V> implements Future<V> {
+
+    protected IThreadPoolService threadPool;
+    protected volatile boolean canceled;
+    protected CountDownLatch latch;
+    protected OFType responseType;
+    protected volatile V result;
+    protected IOFSwitch sw;
+    protected Runnable timeoutTimer;
+    protected int transactionId;
+    protected static final long DEFAULT_TIMEOUT = 60;
+    protected static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS;
+
+    public OFMessageFuture(IThreadPoolService tp,
+            IOFSwitch sw, OFType responseType, int transactionId) {
+        this(tp, sw, responseType, transactionId,
+                 DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT);
+    }
+
+    public OFMessageFuture(IThreadPoolService tp,
+            IOFSwitch sw, OFType responseType, int transactionId, long timeout, TimeUnit unit) {
+        this.threadPool = tp;
+        this.canceled = false;
+        this.latch = new CountDownLatch(1);
+        this.responseType = responseType;
+        this.sw = sw;
+        this.transactionId = transactionId;
+
+        final OFMessageFuture<V> future = this;
+        timeoutTimer = new Runnable() {
+            @Override
+            public void run() {
+                if (timeoutTimer == this)
+                    future.cancel(true);
+            }
+        };
+        threadPool.getScheduledExecutor().schedule(timeoutTimer, timeout, unit);
+    }
+
+    protected void unRegister() {
+        this.timeoutTimer = null;
+    }
+
+
+    // TODO: msg should be generic!
+    public void deliverFuture(IOFSwitch sw, OFMessage msg) {
+        if (transactionId == msg.getXid()) {
+            handleReply(sw, msg);
+            if (isFinished()) {
+                unRegister();
+                this.latch.countDown();
+            }
+        }
+    }
+
+    /**
+     * Used to handle the specific expected message this Future was reigstered
+     * for, the specified msg parameter is guaranteed to match the type and
+     * transaction id specified.
+     * @param sw
+     * @param msg
+     * @return
+     */
+    protected abstract void handleReply(IOFSwitch sw, OFMessage msg);
+
+    /**
+     * Called directly after handleReply, subclasses implement this method to
+     * indicate when the future can deregister itself from receiving future
+     * messages, and when it is safe to return the results to any waiting
+     * threads.
+     * @return when this Future has completed its work
+     */
+    protected abstract boolean isFinished();
+
+    /* (non-Javadoc)
+     * @see java.util.concurrent.Future#cancel(boolean)
+     */
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        if (isDone()) {
+            return false;
+        } else {
+            unRegister();
+            canceled = true;
+            this.latch.countDown();
+            return !isDone();
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.concurrent.Future#isCancelled()
+     */
+    @Override
+    public boolean isCancelled() {
+        return canceled;
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.concurrent.Future#isDone()
+     */
+    @Override
+    public boolean isDone() {
+        return this.latch.getCount() == 0;
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.concurrent.Future#get()
+     */
+    @Override
+    public V get() throws InterruptedException, ExecutionException {
+        this.latch.await();
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit)
+     */
+    @Override
+    public V get(long timeout, TimeUnit unit) throws InterruptedException,
+            ExecutionException, TimeoutException {
+        this.latch.await(timeout, unit);
+        return result;
+    }
+
+    public int getTransactionId() {
+        return transactionId;
+    }
+
+    public void setTransactionId(int transactionId) {
+        this.transactionId = transactionId;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFStatisticsFuture.java b/src/main/java/net/floodlightcontroller/core/internal/OFStatisticsFuture.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d3f733a6ed1d3e6b7dbba272643680877f9e982
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFStatisticsFuture.java
@@ -0,0 +1,80 @@
+/**
+*    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.core.internal;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFStatisticsReply;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.statistics.OFStatistics;
+
+/**
+ * A concrete implementation that handles asynchronously receiving OFStatistics
+ * 
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFStatisticsFuture extends
+        OFMessageFuture<List<OFStatistics>> {
+
+    protected volatile boolean finished;
+
+    public OFStatisticsFuture(IThreadPoolService tp,
+            IOFSwitch sw, int transactionId) {
+        super(tp, sw, OFType.STATS_REPLY, transactionId);
+        init();
+    }
+
+    public OFStatisticsFuture(IThreadPoolService tp,
+            IOFSwitch sw, int transactionId, long timeout, TimeUnit unit) {
+        super(tp, sw, OFType.STATS_REPLY, transactionId, timeout, unit);
+        init();
+    }
+
+    private void init() {
+        this.finished = false;
+        this.result = new CopyOnWriteArrayList<OFStatistics>();
+    }
+
+    @Override
+    protected void handleReply(IOFSwitch sw, OFMessage msg) {
+        OFStatisticsReply sr = (OFStatisticsReply) msg;
+        synchronized (this.result) {
+            this.result.addAll(sr.getStatistics());
+            if ((sr.getFlags() & 0x1) == 0) {
+                this.finished = true;
+            }
+        }
+    }
+
+    @Override
+    protected boolean isFinished() {
+        return finished;
+    }
+    
+    @Override
+    protected void unRegister() {
+        super.unRegister();
+        sw.cancelStatisticsReply(transactionId);
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchAppHandshakePlugin.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchAppHandshakePlugin.java
deleted file mode 100644
index ddfd008720a6853262905afeb7072cf91c99c3f5..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchAppHandshakePlugin.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.util.concurrent.TimeUnit;
-
-import org.jboss.netty.util.Timeout;
-import org.jboss.netty.util.Timer;
-import org.jboss.netty.util.TimerTask;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.WaitAppHandshakeState;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-/**
- * This class is a plugin that can be used by applications to tap into the
- * switch handshake. It operates much like the switch handshake. Messages should
- * be sent upon entering the plugin and OF response messages should be handled
- * just like any part of the switch handshake.
- *
- * @author Jason Parraga <jason.parraga@bigswitch.com>
- */
-public abstract class OFSwitchAppHandshakePlugin {
-
-    private static final Logger log = LoggerFactory.getLogger(OFSwitchAppHandshakePlugin.class);
-
-    private WaitAppHandshakeState state;
-    @edu.umd.cs.findbugs.annotations.SuppressWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    private IOFSwitch sw;
-    private volatile Timeout timeout;
-
-    private final PluginResult defaultResult;
-    private final int timeoutS;
-
-    /**
-     * Constructor for OFSwitchAppHandshakePlugin
-     * @param defaultResult the default result in the event of a timeout
-     * @param defaultTimeoutS the timeout length in seconds
-     */
-    protected OFSwitchAppHandshakePlugin(PluginResult defaultResult, int timeoutS){
-        Preconditions.checkNotNull(defaultResult, "defaultResult");
-        Preconditions.checkNotNull(timeoutS, "timeoutS");
-
-        this.defaultResult = defaultResult;
-        this.timeoutS = timeoutS;
-    }
-
-    /**
-     * Process incoming OF Messages
-     *
-     * @param m The OF Message received
-     */
-    protected abstract void processOFMessage(OFMessage m);
-
-    /**
-     * Enter this plugin. Should be used to send messages.
-     */
-    protected abstract void enterPlugin();
-
-    /**
-     * Gets the switch associated with the handshake for use by the plugin
-     * writer.
-     *
-     * @return the switch associated with the handshake.
-     */
-    protected IOFSwitch getSwitch() {
-        return this.sw;
-    }
-
-    /**
-     * Initialization for plugin called by the OFSwitchHandshakeHandler
-     *
-     * @param state the current state of the OFSwitchHandshakeHandler
-     * @param sw the current switch of the OFSwitchHandshakeHandler
-     */
-    final void init(WaitAppHandshakeState state, IOFSwitch sw, Timer timer) {
-        this.state = state;
-        this.sw = sw;
-        this.timeout = timer.newTimeout(new PluginTimeoutTask(), timeoutS, TimeUnit.SECONDS);
-    }
-
-    /**
-     * Called to denote that the plugin has finished
-     *
-     * @param result
-     *            the result of the plugin in regards to handshaking
-     */
-    protected final void exitPlugin(PluginResult result) {
-        timeout.cancel();
-        state.exitPlugin(result);
-    }
-
-    /**
-     * Plugin timeout task that will exit the plugin
-     * with the default result value when timed out.
-     *
-     */
-    private final class PluginTimeoutTask implements TimerTask {
-
-        @Override
-        public void run(Timeout timeout) throws Exception {
-            if (!timeout.isCancelled()) {
-                log.warn("App handshake plugin for {} timed out. Returning result {}.",
-                         sw, defaultResult);
-                exitPlugin(defaultResult);
-            }
-        }
-    }
-
-    public enum PluginResultType {
-        CONTINUE(),
-        DISCONNECT(),
-        QUARANTINE();
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java
deleted file mode 100644
index 90c7d4654a6d6d8b1fd670d65d456b68053fde3d..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java
+++ /dev/null
@@ -1,1886 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.TimeUnit;
-
-import javax.annotation.Nonnull;
-
-import org.jboss.netty.util.Timer;
-import net.floodlightcontroller.core.GenTableMap;
-import net.floodlightcontroller.core.HARole;
-import net.floodlightcontroller.core.IOFConnection;
-import net.floodlightcontroller.core.IOFConnectionBackend;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitch.SwitchStatus;
-import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.PortChangeEvent;
-import net.floodlightcontroller.core.SwitchDescription;
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
-import net.floodlightcontroller.core.annotations.LogMessageDocs;
-import net.floodlightcontroller.core.internal.OFSwitchAppHandshakePlugin.PluginResultType;
-import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
-import org.projectfloodlight.openflow.protocol.OFBarrierReply;
-import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
-import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionsReply;
-import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionsRequest;
-import org.projectfloodlight.openflow.protocol.OFBsnGentableDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFBsnGentableDescStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFBsnSetAuxCxnsReply;
-import org.projectfloodlight.openflow.protocol.OFBsnSetAuxCxnsRequest;
-import org.projectfloodlight.openflow.protocol.OFBsnSetL2TableRequest;
-import org.projectfloodlight.openflow.protocol.OFControllerRole;
-import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFErrorMsg;
-import org.projectfloodlight.openflow.protocol.OFErrorType;
-import org.projectfloodlight.openflow.protocol.OFExperimenter;
-import org.projectfloodlight.openflow.protocol.OFFactories;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFFlowModFailedCode;
-import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
-import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
-import org.projectfloodlight.openflow.protocol.OFGetConfigRequest;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
-import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
-import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFPortStatus;
-import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
-import org.projectfloodlight.openflow.protocol.OFRoleReply;
-import org.projectfloodlight.openflow.protocol.OFRoleRequest;
-import org.projectfloodlight.openflow.protocol.OFSetConfig;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
-import org.projectfloodlight.openflow.protocol.OFStatsRequestFlags;
-import org.projectfloodlight.openflow.protocol.OFStatsType;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
-import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFAuxId;
-import org.projectfloodlight.openflow.types.U64;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-/**
- * Switch handler deals with the switch connection and dispatches
- * switch messages to the appropriate locations. These messages
- * are typically received by the channel handler first and piped here.
- *
- * @author Jason Parraga <jason.parraga@bigswitch.com>
- */
-public class OFSwitchHandshakeHandler implements IOFConnectionListener {
-    private static final Logger log = LoggerFactory.getLogger(OFSwitchHandshakeHandler.class);
-
-    private final IOFSwitchManager switchManager;
-    private final RoleManager roleManager;
-    private final IOFConnectionBackend mainConnection;
-    private final SwitchManagerCounters switchManagerCounters;
-    private IOFSwitchBackend sw;
-    private final Map<OFAuxId, IOFConnectionBackend> auxConnections;
-    private volatile OFSwitchHandshakeState state;
-    private RoleChanger roleChanger;
-    // Default to 1.3 - This is overwritten by the features reply
-    private OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
-    private final OFFeaturesReply featuresReply;
-    private final Timer timer;
-
-    private final ArrayList<OFPortStatus> pendingPortStatusMsg;
-
-    /** transaction Ids to use during handshake. Since only one thread
-     * calls into the OFChannelHandler we don't need atomic.
-     * We will count down
-     */
-    private long handshakeTransactionIds = 0x00FFFFFFFFL;
-
-    /* Exponential backoff of master role assertion */
-    private final long MAX_ASSERT_TIME_INTERVAL_NS = TimeUnit.SECONDS.toNanos(120);
-    private final long DEFAULT_ROLE_TIMEOUT_NS = TimeUnit.SECONDS.toNanos(10);
-
-    protected OFPortDescStatsReply portDescStats;
-
-    /**
-     * When we remove a pending role request and set the role on the switch
-     * we use this enum to indicate how we arrived at the decision.
-     * @author gregor
-     */
-    private enum RoleRecvStatus {
-        /** We received a role reply message from the switch */
-        RECEIVED_REPLY,
-        /** The switch returned an error indicated that roles are not
-         * supported*/
-        UNSUPPORTED,
-        /** The request timed out */
-        NO_REPLY;
-    }
-    /**
-     * A utility class to handle role requests and replies for this channel.
-     * After a role request is submitted the role changer keeps track of the
-     * pending request, collects the reply (if any) and times out the request
-     * if necessary.
-     *
-     * To simplify role handling we only keep track of the /last/ pending
-     * role reply send to the switch. If multiple requests are pending and
-     * we receive replies for earlier requests we ignore them. However, this
-     * way of handling pending requests implies that we could wait forever if
-     * a new request is submitted before the timeout triggers. If necessary
-     * we could work around that though.
-     * @author gregor
-     */
-    private class RoleChanger {
-        // indicates that a request is currently pending
-        // needs to be volatile to allow correct double-check idiom
-        private volatile boolean requestPending;
-        // the transaction Id of the pending request
-        private long pendingXid;
-        // the role that's pending
-        private OFControllerRole pendingRole;
-        // system time in NS when we send the request
-        private long roleSubmitTimeNs;
-        // the timeout to use
-        private final long roleTimeoutNs;
-        private long lastAssertTimeNs;
-        private long assertTimeIntervalNs = TimeUnit.SECONDS.toNanos(1);
-
-        public RoleChanger(long roleTimeoutNs) {
-            this.roleTimeoutNs = roleTimeoutNs;
-            // System.nanoTime() may be negative -- prime the roleSubmitTime as
-            // "long ago in the past" to be robust against it.
-            this.roleSubmitTimeNs = System.nanoTime() - (2 * roleTimeoutNs);
-            this.lastAssertTimeNs = System.nanoTime() - (2 * assertTimeIntervalNs);
-            this.requestPending = false;
-            this.pendingXid = -1;
-            this.pendingRole = null;
-        }
-
-        /**
-         * Send Nicira role request message to the switch requesting the
-         * specified role.
-         *
-         * @param role role to request
-         */
-        private long sendNiciraRoleRequest(OFControllerRole role){
-
-            long xid;
-            // Construct the role request message
-            if(factory.getVersion().compareTo(OFVersion.OF_12) < 0) {
-                OFNiciraControllerRoleRequest.Builder builder =
-                        factory.buildNiciraControllerRoleRequest();
-                xid = factory.nextXid();
-                builder.setXid(xid);
-
-                OFNiciraControllerRole niciraRole = NiciraRoleUtils.ofRoleToNiciraRole(role);
-                builder.setRole(niciraRole);
-                OFNiciraControllerRoleRequest roleRequest = builder.build();
-                // Send it to the switch
-                mainConnection.write(roleRequest);
-            } else {
-                // send an OF 1.2+ role request
-                OFRoleRequest roleRequest = factory.buildRoleRequest()
-                        // we don't use the generation id scheme for now,
-                        // switch initializes to 0, we keep it at 0
-                        .setGenerationId(U64.of(0))
-                        .setRole(role)
-                        .build();
-                xid = roleRequest.getXid();
-                mainConnection.write(roleRequest);
-            }
-            return xid;
-        }
-
-        /**
-         * Send a role request for the given role only if no other role
-         * request is currently pending.
-         * @param role The role to send to the switch.
-         * @throws IOException
-         */
-        @LogMessageDoc(level="WARN",
-                message="Reasserting master role on switch {SWITCH}, " +
-                        "likely a configruation error with multiple masters",
-                explanation="The controller keeps getting permission error " +
-                        "from switch, likely due to switch connected to another " +
-                        "controller also in master mode",
-                        recommendation=LogMessageDoc.CHECK_SWITCH)
-        synchronized void sendRoleRequestIfNotPending(OFControllerRole role)
-                throws IOException {
-            long now = System.nanoTime();
-            if (now - lastAssertTimeNs < assertTimeIntervalNs) {
-                return;
-            }
-
-            lastAssertTimeNs = now;
-            if (assertTimeIntervalNs < MAX_ASSERT_TIME_INTERVAL_NS) { // 2 minutes max
-                assertTimeIntervalNs <<= 1;
-            } else if (role == OFControllerRole.ROLE_MASTER){
-                log.warn("Reasserting master role on switch {}, " +
-                        "likely a switch config error with multiple masters",
-                        role, sw);
-            }
-            if (!requestPending)
-                sendRoleRequest(role);
-            else
-                switchManagerCounters.roleNotResentBecauseRolePending.increment();
-        }
-
-        /**
-         * Send a role request with the given role to the switch.
-         *
-         * Send a role request with the given role to the switch and update
-         * the pending request and timestamp.
-         *
-         * @param role
-         * @throws IOException
-         */
-        synchronized void sendRoleRequest(OFControllerRole role) throws IOException {
-            /*
-             * There are three cases to consider for SUPPORTS_NX_ROLE:
-             *
-             * 1) unset. We have neither received a role reply from the
-             *    switch nor has a request timed out. Send a request.
-             * 2) TRUE: We've already send a request earlier and received
-             *    a reply. The switch supports role and we should send one.
-             * 3) FALSE: We have already send a role and received an error.
-             *    The switch does not support roles. Don't send a role request,
-             *    set the switch's role directly.
-             */
-            Boolean supportsNxRole = (Boolean)
-                    sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
-            if ((supportsNxRole != null) && !supportsNxRole) {
-                setSwitchRole(role, RoleRecvStatus.UNSUPPORTED);
-            } else {
-                pendingXid = sendNiciraRoleRequest(role);
-                pendingRole = role;
-                this.roleSubmitTimeNs = System.nanoTime();
-                requestPending = true;
-            }
-        }
-
-        /**
-         * Deliver a received role reply and set SWITCH_SUPPORTS_NX_ROLE.
-         *
-         * Check if a request is pending and if the received reply matches the
-         * the expected pending reply (we check both role and xid) we set
-         * the role for the switch/channel.
-         *
-         * If a request is pending but doesn't match the reply we ignore it.
-         *
-         * If no request is pending we disconnect.
-         *
-         * @param xid
-         * @param role
-         * @throws SwitchStateException if no request is pending
-         */
-        synchronized void deliverRoleReply(long xid, OFControllerRole role) {
-            if (!requestPending) {
-                // Maybe don't disconnect if the role reply we received is
-                // for the same role we are already in.
-                String msg = String.format("Switch: [%s], State: [%s], "
-                                + "received unexpected RoleReply[%s]. "
-                                + "No roles are pending",
-                                OFSwitchHandshakeHandler.this.getSwitchInfoString(),
-                                OFSwitchHandshakeHandler.this.state.toString(),
-                                role);
-                throw new SwitchStateException(msg);
-            }
-
-            if (pendingXid == xid && pendingRole == role) {
-                log.debug("[{}] Received role reply message setting role to {}",
-                          getDpid(), role);
-                switchManagerCounters.roleReplyReceived.increment();
-                setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY);
-            } else {
-                log.debug("[{}] Received stale or unexpected role reply " +
-                          "{}, xid={}. Ignoring. " +
-                          "Waiting for {}, xid={}",
-                          new Object[] { getDpid(), role, xid,
-                                         pendingRole, pendingXid });
-            }
-        }
-
-        /**
-         * Called if we receive an  error message. If the xid matches the
-         * pending request we handle it otherwise we ignore it. We also
-         * set SWITCH_SUPPORTS_NX_ROLE to false.
-         *
-         * Note: since we only keep the last pending request we might get
-         * error messages for earlier role requests that we won't be able
-         * to handle
-         * @param xid
-         * @return true if the error was handled by us, false otherwise
-         * @throws SwitchStateException if the error was for the pending
-         * role request but was unexpected
-         */
-        synchronized boolean deliverError(OFErrorMsg error) {
-            if (!requestPending)
-                return false;
-
-            if (pendingXid == error.getXid()) {
-                if (error.getErrType() == OFErrorType.BAD_REQUEST) {
-                    switchManagerCounters.roleReplyErrorUnsupported.increment();
-                    setSwitchRole(pendingRole, RoleRecvStatus.UNSUPPORTED);
-                } else {
-                    // TODO: Is this the right thing to do if we receive
-                    // some other error besides a bad request error?
-                    // Presumably that means the switch did actually
-                    // understand the role request message, but there
-                    // was some other error from processing the message.
-                    // OF 1.2 specifies a ROLE_REQUEST_FAILED
-                    // error code, but it doesn't look like the Nicira
-                    // role request has that. Should check OVS source
-                    // code to see if it's possible for any other errors
-                    // to be returned.
-                    // If we received an error the switch is not
-                    // in the correct role, so we need to disconnect it.
-                    // We could also resend the request but then we need to
-                    // check if there are other pending request in which
-                    // case we shouldn't resend. If we do resend we need
-                    // to make sure that the switch eventually accepts one
-                    // of our requests or disconnect the switch. This feels
-                    // cumbersome.
-                    String msg = String.format("Switch: [%s], State: [%s], "
-                                    + "Unexpected error %s in respone to our "
-                                    + "role request for %s.",
-                                    OFSwitchHandshakeHandler.this.getSwitchInfoString(),
-                                    OFSwitchHandshakeHandler.this.state.toString(),
-                                    error.toString(),
-                                    pendingRole);
-                    throw new SwitchStateException(msg);
-                }
-                return true;
-            }
-            return false;
-        }
-
-        /**
-         * Check if a pending role request has timed out.
-         */
-        void checkTimeout() {
-            if (!requestPending)
-                return;
-            synchronized(this) {
-                if (!requestPending)
-                    return;
-                long now = System.nanoTime();
-                if (now - this.roleSubmitTimeNs > roleTimeoutNs) {
-                    // timeout triggered.
-                    switchManagerCounters.roleReplyTimeout.increment();
-                    setSwitchRole(pendingRole, RoleRecvStatus.NO_REPLY);
-                }
-            }
-        }
-
-        /**
-         * Set the role for this switch / channel.
-         *
-         * If the status indicates that we received a reply we set the role.
-         * If the status indicates otherwise we disconnect the switch if
-         * the role is SLAVE.
-         *
-         * "Setting a role" means setting the appropriate ChannelState,
-         * setting the flags on the switch and
-         * notifying Controller.java about new role of the switch
-         *
-         * @param role The role to set.
-         * @param status How we derived at the decision to set this status.
-         */
-        synchronized private void setSwitchRole(OFControllerRole role, RoleRecvStatus status) {
-            requestPending = false;
-            if (status == RoleRecvStatus.RECEIVED_REPLY)
-                sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
-            else
-                sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
-            sw.setControllerRole(role);
-
-            if (role != OFControllerRole.ROLE_SLAVE) {
-                OFSwitchHandshakeHandler.this.setState(new MasterState());
-            } else {
-                if (status != RoleRecvStatus.RECEIVED_REPLY) {
-                    if (log.isDebugEnabled()) {
-                        log.debug("Disconnecting switch {}. Doesn't support role"
-                              + "({}) request and controller is now SLAVE",
-                              getSwitchInfoString(), status);
-                    }
-                    // the disconnect will trigger a switch removed to
-                    // controller so no need to signal anything else
-                    sw.disconnect();
-                } else {
-                    OFSwitchHandshakeHandler.this.setState(new SlaveState());
-                }
-            }
-        }
-    }
-
-    /**
-     * Default implementation for message handlers in any state.
-     *
-     * Individual states must override these if they want a behavior
-     * that differs from the default.
-     *
-     * In general, these handlers simply ignore the message and do
-     * nothing.
-     *
-     * There are some exceptions though, since some messages really
-     * are handled the same way in every state (e.g., ECHO_REQUST) or
-     * that are only valid in a single state (e.g., HELLO, GET_CONFIG_REPLY
-     */
-    public abstract class OFSwitchHandshakeState {
-
-        void processOFBarrierReply(OFBarrierReply m) {
-            // do nothing
-        }
-
-        void processOFError(OFErrorMsg m) {
-            logErrorDisconnect(m);
-        }
-
-        void processOFFlowRemoved(OFFlowRemoved m) {
-            unhandledMessageReceived(m);
-        }
-
-        void processOFGetConfigReply(OFGetConfigReply m) {
-            // we only expect config replies in the WAIT_CONFIG_REPLY state
-            // TODO: might use two different strategies depending on whether
-            // we got a miss length of 64k or not.
-            illegalMessageReceived(m);
-        }
-
-        void processOFPacketIn(OFPacketIn m) {
-            unhandledMessageReceived(m);
-        }
-
-        // By default add port status messages to a pending list
-        void processOFPortStatus(OFPortStatus m) {
-            pendingPortStatusMsg.add(m);
-        }
-
-        void processOFQueueGetConfigReply(OFQueueGetConfigReply m) {
-            unhandledMessageReceived(m);
-        }
-
-        void processOFStatsReply(OFStatsReply m) {
-            switch(m.getStatsType()) {
-                case PORT_DESC:
-                    processPortDescStatsReply((OFPortDescStatsReply) m);
-                    break;
-                default:
-                    unhandledMessageReceived(m);
-            }
-        }
-
-        void processOFExperimenter(OFExperimenter m) {
-            if (m instanceof OFBsnControllerConnectionsReply) {
-                OFBsnControllerConnectionsReply reply = (OFBsnControllerConnectionsReply) m;
-                handleControllerConnectionMessage(reply);
-            } else {
-                unhandledMessageReceived(m);
-            }
-        }
-
-        void processPortDescStatsReply(OFPortDescStatsReply m) {
-            unhandledMessageReceived(m);
-        }
-
-        void processOFRoleReply(OFRoleReply m) {
-            unhandledMessageReceived(m);
-        }
-
-        private final boolean handshakeComplete;
-        OFSwitchHandshakeState(boolean handshakeComplete) {
-            this.handshakeComplete = handshakeComplete;
-        }
-
-        void logState() {
-            if(log.isDebugEnabled())
-                log.debug("[{}] - Switch Handshake - enter state {}", mainConnection.getDatapathId(), this.getClass().getSimpleName());
-        }
-
-        /** enter this state. Can initialize the handler, send
-         *  the necessary messages, etc.
-         */
-         void enterState(){
-         }
-
-        /**
-         * Is this a state in which the handshake has completed?
-         * @return true if the handshake is complete
-         */
-        public boolean isHandshakeComplete() {
-            return handshakeComplete;
-        }
-
-        /**
-         * Used to notify the WAIT OF AUX state that
-         * a new connection has been added
-         * @param connection
-         */
-        public void auxConnectionOpened(IOFConnectionBackend connection) {
-            // Should only be handled in wait of aux
-            log.debug("[{}] - Switch Handshake - unhandled aux connection event",
-                    getDpid());
-        }
-        /**
-         * Get a string specifying the switch connection, state, and
-         * message received. To be used as message for SwitchStateException
-         * or log messages
-         * @param h The channel handler (to get switch information_
-         * @param m The OFMessage that has just been received
-         * @param details A string giving more details about the exact nature
-         * of the problem.
-         * @return
-         */
-        // needs to be protected because enum members are acutally subclasses
-        protected String getSwitchStateMessage(OFMessage m,
-                                                      String details) {
-            return String.format("Switch: [%s], State: [%s], received: [%s]"
-                                 + ", details: %s",
-                                 getSwitchInfoString(),
-                                 this.toString(),
-                                 m.getType().toString(),
-                                 details);
-        }
-
-        /**
-         * We have an OFMessage we didn't expect given the current state and
-         * we want to treat this as an error.
-         * We currently throw an exception that will terminate the connection
-         * However, we could be more forgiving
-         * @param h the channel handler that received the message
-         * @param m the message
-         * @throws SwitchStateExeption we always through the execption
-         */
-        // needs to be protected because enum members are acutally subclasses
-        protected void illegalMessageReceived(OFMessage m) {
-            String msg = getSwitchStateMessage(m,
-                    "Switch should never send this message in the current state");
-            throw new SwitchStateException(msg);
-
-        }
-
-        /**
-         * We have an OFMessage we didn't expect given the current state and
-         * we want to ignore the message
-         * @param h the channel handler the received the message
-         * @param m the message
-         */
-        protected void unhandledMessageReceived(OFMessage m) {
-            switchManagerCounters.unhandledMessage.increment();
-            if (log.isDebugEnabled()) {
-                String msg = getSwitchStateMessage(m,
-                        "Ignoring unexpected message");
-                log.debug(msg);
-            }
-        }
-
-        /**
-         * Log an OpenFlow error message from a switch
-         * @param error The error message
-         */
-        @LogMessageDoc(level="ERROR",
-                message="Error {error type} {error code} from {switch} " +
-                        "in state {state}",
-                explanation="The switch responded with an unexpected error" +
-                        "to an OpenFlow message from the controller",
-                recommendation="This could indicate improper network operation. " +
-                        "If the problem persists restarting the switch and " +
-                        "controller may help."
-                )
-        protected void logError(OFErrorMsg error) {
-            log.error("{} from switch {} in state {}",
-                      new Object[] {
-                          error.toString(),
-                          getSwitchInfoString(),
-                          this.toString()});
-        }
-
-        /**
-         * Log an OpenFlow error message from a switch and disconnect the
-         * channel
-         * @param error The error message
-         */
-        protected void logErrorDisconnect(OFErrorMsg error) {
-            logError(error);
-            mainConnection.disconnect();
-        }
-
-        /**
-         * Extract the role from an OFVendor message.
-         *
-         * Extract the role from an OFVendor message if the message is a
-         * Nicira role reply. Otherwise return null.
-         *
-         * @param h The channel handler receiving the message
-         * @param vendorMessage The vendor message to parse.
-         * @return The role in the message if the message is a Nicira role
-         * reply, null otherwise.
-         */
-        protected OFControllerRole extractNiciraRoleReply(OFMessage vendorMessage) {
-            if (!(vendorMessage instanceof OFNiciraControllerRoleReply))
-                return null;
-            OFNiciraControllerRoleReply roleReply =
-                    (OFNiciraControllerRoleReply) vendorMessage;
-            return NiciraRoleUtils.niciraToOFRole(roleReply);
-        }
-
-        /**
-         * Handle a port status message.
-         *
-         * Handle a port status message by updating the port maps in the
-         * IOFSwitch instance and notifying Controller about the change so
-         * it can dispatch a switch update.
-         *
-         * @param h The OFChannelHhandler that received the message
-         * @param m The PortStatus message we received
-         * @param doNotify if true switch port changed events will be
-         * dispatched
-         */
-        protected void handlePortStatusMessage(OFPortStatus m,
-                                               boolean doNotify) {
-            if (sw == null) {
-                String msg = getSwitchStateMessage(m,
-                        "State machine error: switch is null. Should never " +
-                        "happen");
-                throw new SwitchStateException(msg);
-            }
-            Collection<PortChangeEvent> changes = sw.processOFPortStatus(m);
-            if (doNotify) {
-                for (PortChangeEvent ev: changes)
-                    switchManager.notifyPortChanged(sw, ev.port, ev.type);
-            }
-        }
-
-        protected void handleControllerConnectionMessage(OFBsnControllerConnectionsReply m) {
-            if (sw == null) {
-                String msg = getSwitchStateMessage(m,
-                        "State machine error: switch is null. Should never " +
-                        "happen");
-                throw new SwitchStateException(msg);
-            }
-            // Update switches
-            sw.updateControllerConnections(m);
-            // Notify role manager
-            roleManager.notifyControllerConnectionUpdate();
-        }
-
-
-        /**
-         * Process an OF message received on the channel and
-         * update state accordingly.
-         *
-         * The main "event" of the state machine. Process the received message,
-         * send follow up message if required and update state if required.
-         *
-         * Switches on the message type and calls more specific event handlers
-         * for each individual OF message type. If we receive a message that
-         * is supposed to be sent from a controller to a switch we throw
-         * a SwitchStateExeption.
-         *
-         * The more specific handlers can also throw SwitchStateExceptions
-         *
-         * @param h The OFChannelHandler that received the message
-         * @param m The message we received.
-         * @throws SwitchStateException
-         * @throws IOException
-         */
-        void processOFMessage(OFMessage m) {
-            roleChanger.checkTimeout();
-            switch(m.getType()) {
-                case BARRIER_REPLY:
-                    processOFBarrierReply((OFBarrierReply)m);
-                    break;
-                case ERROR:
-                    processOFError((OFErrorMsg)m);
-                    break;
-                case FLOW_REMOVED:
-                    processOFFlowRemoved((OFFlowRemoved)m);
-                    break;
-                case GET_CONFIG_REPLY:
-                    processOFGetConfigReply((OFGetConfigReply)m);
-                    break;
-                case PACKET_IN:
-                    processOFPacketIn((OFPacketIn)m);
-                    break;
-                case PORT_STATUS:
-                    processOFPortStatus((OFPortStatus)m);
-                    break;
-                case QUEUE_GET_CONFIG_REPLY:
-                    processOFQueueGetConfigReply((OFQueueGetConfigReply)m);
-                    break;
-                case STATS_REPLY:
-                    processOFStatsReply((OFStatsReply)m);
-                    break;
-                case ROLE_REPLY:
-                    processOFRoleReply((OFRoleReply)m);
-                    break;
-                case EXPERIMENTER:
-                    processOFExperimenter((OFExperimenter)m);
-                    break;
-                default:
-                    illegalMessageReceived(m);
-                    break;
-            }
-        }
-    }
-
-        /**
-         * Initial state before channel is connected. Should not handle any messages.
-         */
-          public class InitState extends OFSwitchHandshakeState {
-
-            InitState() {
-                super(false);
-            }
-
-            @Override
-            public void logState() {
-                log.debug("[{}] - Switch Handshake - Initiating from {}",
-                        getDpid(), mainConnection.getRemoteInetAddress());
-            }
-        }
-
-        /**
-         * We are waiting for a features reply message. Once we receive it
-         * we send a SetConfig request, barrier, and GetConfig request.
-         * Next stats is WAIT_CONFIG_REPLY or WAIT_SET_L2_TABLE_REPLY
-         */
-        public class WaitPortDescStatsReplyState extends OFSwitchHandshakeState {
-            WaitPortDescStatsReplyState() {
-                super(false);
-            }
-
-            @Override
-            void enterState(){
-                sendPortDescRequest();
-            }
-
-            @Override
-            void processPortDescStatsReply(OFPortDescStatsReply  m) {
-                portDescStats = m;
-
-                setState(new WaitConfigReplyState());
-            }
-
-            @Override
-            void processOFExperimenter(OFExperimenter m) {
-                unhandledMessageReceived(m);
-            }
-        }
-
-        public class WaitSetL2TableReplyState extends OFSwitchHandshakeState {
-
-            WaitSetL2TableReplyState() {
-                super(false);
-            }
-
-            @Override
-            void processOFExperimenter(OFExperimenter m) {
-                // TODO: actually parse the response
-                setState(new WaitConfigReplyState());
-            };
-
-            @Override
-            void processOFStatsReply(OFStatsReply  m) {
-                illegalMessageReceived(m);
-            }
-        }
-
-        /**
-         * We are waiting for a config reply message. Once we receive it
-         * we send a DescriptionStatsRequest to the switch.
-         * Next state: WAIT_DESCRIPTION_STAT_REPLY
-         */
-        public class WaitConfigReplyState extends OFSwitchHandshakeState {
-
-            WaitConfigReplyState() {
-                super(false);
-            }
-
-            @Override
-            @LogMessageDocs({
-                @LogMessageDoc(level="WARN",
-                        message="Config Reply from {switch} has " +
-                                "miss length set to {length}",
-                        explanation="The controller requires that the switch " +
-                                "use a miss length of 0xffff for correct " +
-                                "function",
-                        recommendation="Use a different switch to ensure " +
-                                "correct function")
-            })
-            void processOFGetConfigReply(OFGetConfigReply m) {
-                if (m.getMissSendLen() == 0xffff) {
-                    log.trace("Config Reply from switch {} confirms "
-                            + "miss length set to 0xffff",
-                            getSwitchInfoString());
-                } else {
-                    // FIXME: we can't really deal with switches that don't send
-                    // full packets. Shouldn't we drop the connection here?
-                    // FIXME: count??
-                    log.warn("Config Reply from switch {} has"
-                            + "miss length set to {}",
-                            getSwitchInfoString(),
-                            m.getMissSendLen());
-                }
-                setState(new WaitDescriptionStatReplyState());
-            }
-
-            @Override
-            void processOFStatsReply(OFStatsReply  m) {
-                illegalMessageReceived(m);
-            }
-
-            @Override
-            void processOFError(OFErrorMsg m) {
-                if ((m.getErrType() == OFErrorType.BAD_REQUEST) &&
-                        (((OFBadRequestErrorMsg)m).getCode() == OFBadRequestCode.BAD_EXPERIMENTER)) {
-                    log.debug("Switch {} has multiple tables but does not " +
-                            "support L2 table extension",
-                            getSwitchInfoString());
-                    return;
-                }
-                logErrorDisconnect(m);
-            }
-
-            @Override
-            void enterState() {
-                sendHandshakeSetConfig();
-            }
-        }
-
-        /**
-         * We are waiting for a OFDescriptionStat message from the switch.
-         * Once we receive any stat message we try to parse it. If it's not
-         * a description stats message we disconnect. If its the expected
-         * description stats message, we:
-         *    - use the switch driver to bind the switch and get an IOFSwitch
-         *      instance, setup the switch instance
-         *    - setup the IOFSwitch instance
-         *    - add switch to FloodlightProvider and send the intial role
-         *      request to the switch.
-         *
-         * Next state: WaitOFAuxCxnsReplyState (if OF1.3), else
-         *     WaitInitialRoleState or WaitSwitchDriverSubHandshake
-         *
-         * All following states will have a h.sw instance!
-         */
-        public class WaitDescriptionStatReplyState extends OFSwitchHandshakeState{
-
-            WaitDescriptionStatReplyState() {
-                super(false);
-            }
-
-            @LogMessageDoc(message="Switch {switch info} bound to class " +
-                "{switch driver}, description {switch description}",
-                    explanation="The specified switch has been bound to " +
-                            "a switch driver based on the switch description" +
-                            "received from the switch")
-            @Override
-            void processOFStatsReply(OFStatsReply m) {
-                // Read description, if it has been updated
-                if (m.getStatsType() != OFStatsType.DESC) {
-                    illegalMessageReceived(m);
-                    return;
-                }
-
-                OFDescStatsReply descStatsReply = (OFDescStatsReply) m;
-                SwitchDescription description = new SwitchDescription(descStatsReply);
-                sw = switchManager.getOFSwitchInstance(mainConnection, description, factory, featuresReply.getDatapathId());
-                switchManager.switchAdded(sw);
-                // set switch information
-                // set features reply and channel first so we a DPID and
-                // channel info.
-                sw.setFeaturesReply(featuresReply);
-                if(portDescStats != null) {
-                    sw.setPortDescStats(portDescStats);
-                }
-
-                // Handle pending messages now that we have a sw object
-                handlePendingPortStatusMessages(description);
-
-                // Handle non OF 13 connections
-                if(featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0){
-                    sw.startDriverHandshake();
-                    if (sw.isDriverHandshakeComplete()) {
-                        setState(new WaitAppHandshakeState());
-                    } else {
-                        setState(new WaitSwitchDriverSubHandshakeState());
-                    }
-                }
-                // Handle OF 1.3 MAIN Connection
-                else{
-                    setState(new WaitOFAuxCxnsReplyState());
-                }
-            }
-
-            void handlePendingPortStatusMessages(SwitchDescription description){
-                for (OFPortStatus ps: pendingPortStatusMsg)
-                    handlePortStatusMessage(ps, false);
-                pendingPortStatusMsg.clear();
-                log.info("Switch {} bound to class {}," +
-                        " description {}",
-                         new Object[] { sw, sw.getClass(),
-                                    description });
-            }
-
-            @Override
-            void enterState() {
-                sendHandshakeDescriptionStatsRequest();
-            }
-        }
-
-        /**
-         * We are waiting for an OFAuxCxnsReply message from the switch.
-         *  If the switch replies with a status of 0 it has approved of our request.
-         *  If the auxiliary connections haven't already connected we will
-         *  wait for them.
-         *
-         * Next state: WAIT_GENTABLE_DESC_STATS_REPLY (if OF1.3), else
-         *     WAIT_INITIAL_ROLE or WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
-         *
-         * All following states will have a h.sw instance!
-         */
-        public class WaitOFAuxCxnsReplyState extends OFSwitchHandshakeState {
-
-            // Default number of aux connections
-            int numAux = 0;
-
-            WaitOFAuxCxnsReplyState() {
-                super(false);
-            }
-
-            @Override
-            void processOFExperimenter(OFExperimenter m) {
-               if(m instanceof OFBsnSetAuxCxnsReply){
-                   OFBsnSetAuxCxnsReply auxReply = (OFBsnSetAuxCxnsReply) m;
-
-                   if(auxReply.getStatus() == 0){
-                       if(this.numAux != 0){
-                           // All aux connections havent arrived yet
-                           if(auxConnections.size() != this.numAux){
-                               // We do nothing and wait for connections...
-                           } else {
-                               // Looks like all the aux connections have already arrived
-                               gotoNextState();
-                           }
-                       }
-                       else {
-                           // We don't need any OF Aux Connections
-                           gotoNextState();
-                       }
-                   } else {
-                       String msg = String.format("Switch: [%s], HandshakeState: [%s], "
-                               + "received unexpected OF Aux Status [%s]. ",
-                               OFSwitchHandshakeHandler.this.getSwitchInfoString(),
-                               OFSwitchHandshakeHandler.this.state.toString(),
-                               String.valueOf(auxReply.getStatus()));
-                       throw new OFAuxException(msg);
-                   }
-               } else if(m instanceof OFBsnControllerConnectionsReply) {
-                   OFBsnControllerConnectionsReply reply = (OFBsnControllerConnectionsReply) m;
-                   handleControllerConnectionMessage(reply);
-               }
-            }
-
-            @Override
-            public void auxConnectionOpened(IOFConnectionBackend auxConnection){
-                auxConnections.put(auxConnection.getAuxId(), auxConnection);
-                auxConnection.setListener(OFSwitchHandshakeHandler.this);
-
-                // Only handle success case
-                if(auxConnections.size() == this.numAux){
-                    if(log.isDebugEnabled()) {
-                        log.debug("[{}] - all {} required aux connections open. Proceeding",
-                                getDpid(), numAux);
-                    }
-                    gotoNextState();
-                } else {
-                    log.debug("[" + getDpid() + "] - {} / {} required aux connections open. Waiting for more connections. ",
-                            auxConnections.size(), numAux);
-                }
-            }
-
-            @Override
-            void processOFError(OFErrorMsg m) {
-                log.info("Received error on OF Aux handshake - switch does not support OF Aux: {}", m);
-                gotoNextState();
-            }
-
-            void gotoNextState(){
-                // Register any aux connections that have been receieved.
-                for (IOFConnectionBackend conn : auxConnections.values()) {
-                    sw.registerConnection(conn);
-                }
-                setState(new WaitGentableDescStatsReplyState());
-            }
-
-            @Override
-            public void enterState() {
-                this.numAux = switchManager.getNumRequiredConnections();
-                sendOFAuxSetCxnsRequest(this.numAux);
-            }
-
-            @Override
-            void processOFPortStatus(OFPortStatus m) {
-                handlePortStatusMessage(m, false);
-            }
-        }
-
-        /**
-         * We have requested the GenTable mapping (OFBsnGenTableDescStatsRequest)
-         * and are waiting on the reply / replies (note: it is a multipart message).
-         * Once we're received all parts, we create a GenTableMapping object and
-         * set it in the switch.
-         *
-         * If we receive an error messsage corresponding to our request, we conclude
-         * that the switch doesn't support GenTables and leave the empty default
-         * mapping in the switch.
-         *
-         * Next state: WaitSwitchDriverSubHandshakeState() if a driver handshake is required
-         *     WaitAppHandshake else
-         */
-        public class WaitGentableDescStatsReplyState extends OFSwitchHandshakeState {
-
-            private final List<OFBsnGentableDescStatsReply> pendingGenTableDescStatsReplies;
-            private final long pendingRequestXid;
-
-            WaitGentableDescStatsReplyState() {
-                super(false);
-                pendingGenTableDescStatsReplies = new CopyOnWriteArrayList<>();
-                pendingRequestXid = sendHandshakeGenTableDescStatsRequest();
-            }
-
-            @Override
-            void processOFStatsReply(OFStatsReply m) {
-                // Read description, if it has been updated
-                if (!(m instanceof OFBsnGentableDescStatsReply)) {
-                    illegalMessageReceived(m);
-                    return;
-                }
-
-                OFBsnGentableDescStatsReply reply = (OFBsnGentableDescStatsReply) m;
-
-                pendingGenTableDescStatsReplies.add(reply);
-                if(reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
-                    // more replies to follow, stay in state
-                    return;
-                }
-
-                if(sw == null) {
-                    throw new IllegalArgumentException("Switch instance unknown at time of GenTableDescStatsReply");
-                }
-
-                GenTableMap genTableMap = GenTableMap.of(pendingGenTableDescStatsReplies);
-                if(log.isDebugEnabled())
-                    log.debug("[{}] Gen Tables: {}", sw.getId(), genTableMap);
-                sw.setGenTableMap(genTableMap);
-
-                gotoNextState();
-            }
-
-            public void gotoNextState() {
-                sw.startDriverHandshake();
-                if (sw.isDriverHandshakeComplete())
-                    setState(new WaitAppHandshakeState());
-                else
-                    setState(new WaitSwitchDriverSubHandshakeState());
-            }
-
-            @Override
-            void processOFError(OFErrorMsg m) {
-                if(m.getXid() == pendingRequestXid) {
-                    // let switch continue with an empty set of gentables
-                    log.info("Received error on GenTable handshake - switch does not support gentables: {}", m);
-                    gotoNextState();
-                } else {
-                    illegalMessageReceived(m);
-                }
-            }
-
-            @Override
-            void processOFPortStatus(OFPortStatus m) {
-                handlePortStatusMessage(m, false);
-            }
-        }
-
-        public class WaitSwitchDriverSubHandshakeState extends OFSwitchHandshakeState {
-
-            WaitSwitchDriverSubHandshakeState() {
-                super(false);
-            }
-
-            @Override
-            void processOFMessage(OFMessage m) {
-                // FIXME: other message to handle here?
-                sw.processDriverHandshakeMessage(m);
-                if (sw.isDriverHandshakeComplete()) {
-                    setState(new WaitAppHandshakeState());
-                }
-            }
-
-            @Override
-            void processOFPortStatus(OFPortStatus m) {
-                handlePortStatusMessage(m, false);
-            }
-        }
-
-    public class WaitAppHandshakeState extends OFSwitchHandshakeState {
-
-        private final Iterator<IAppHandshakePluginFactory> pluginIterator;
-        private OFSwitchAppHandshakePlugin plugin;
-
-        WaitAppHandshakeState() {
-            super(false);
-            this.pluginIterator = switchManager.getHandshakePlugins().iterator();
-        }
-
-        @Override
-        void processOFMessage(OFMessage m) {
-            if(m.getType() == OFType.PORT_STATUS){
-                OFPortStatus status = (OFPortStatus) m;
-                handlePortStatusMessage(status, false);
-            }
-            else if(plugin != null){
-                this.plugin.processOFMessage(m);
-            }
-            else{
-                super.processOFMessage(m);
-            }
-        }
-
-        /**
-         * Called by handshake plugins to signify that they have finished their
-         * sub handshake.
-         *
-         * @param result
-         *            the result of the sub handshake
-         */
-        void exitPlugin(PluginResult result) {
-
-            // Proceed
-            if (result.getResultType() == PluginResultType.CONTINUE) {
-                if (log.isDebugEnabled()) {
-                    log.debug("Switch " + getSwitchInfoString() + " app handshake plugin {} returned {}."
-                            + " Proceeding normally..",
-                            this.plugin.getClass().getSimpleName(), result);
-                }
-
-                enterNextPlugin();
-
-            // Stop
-            } else if (result.getResultType() == PluginResultType.DISCONNECT) {
-                log.error("Switch " + getSwitchInfoString() + " app handshake plugin {} returned {}. "
-                        + "Disconnecting switch.",
-                        this.plugin.getClass().getSimpleName(), result);
-                mainConnection.disconnect();
-            } else if (result.getResultType() == PluginResultType.QUARANTINE) {
-                log.warn("Switch " + getSwitchInfoString() + " app handshake plugin {} returned {}. "
-                        + "Putting switch into quarantine state.",
-                        this.plugin.getClass().getSimpleName(),
-                         result);
-                setState(new QuarantineState(result.getReason()));
-            }
-        }
-
-        @Override
-        public void enterState() {
-            enterNextPlugin();
-        }
-
-        /**
-         * Initialize the plugin and begin.
-         *
-         * @param plugin the of switch app handshake plugin
-         */
-        public void enterNextPlugin() {
-            if(this.pluginIterator.hasNext()){
-                this.plugin = pluginIterator.next().createPlugin();
-                this.plugin.init(this, sw, timer);
-                this.plugin.enterPlugin();
-            }
-            // No more plugins left...
-            else{
-                // Non OF 1.3
-                if(featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0){
-                    setState(new WaitInitialRoleState());
-                } else {
-                    setState(new WaitControllerCxnsReplyState());
-                }
-            }
-        }
-
-        @Override
-        void processOFPortStatus(OFPortStatus m) {
-            handlePortStatusMessage(m, false);
-        }
-
-        OFSwitchAppHandshakePlugin getCurrentPlugin() {
-            return plugin;
-        }
-
-    }
-
-    /**
-     * Switch is in a quarantine state. Essentially the handshake is complete.
-     */
-    public class QuarantineState extends OFSwitchHandshakeState {
-
-        private final String quarantineReason;
-
-        QuarantineState(String reason) {
-            super(true);
-            this.quarantineReason = reason;
-        }
-
-        @Override
-        public void enterState() {
-            setSwitchStatus(SwitchStatus.QUARANTINED);
-        }
-
-        @Override
-        void processOFPortStatus(OFPortStatus m) {
-            handlePortStatusMessage(m, false);
-        }
-
-        public String getQuarantineReason() {
-            return this.quarantineReason;
-        }
-    }
-
-    public class WaitControllerCxnsReplyState extends OFSwitchHandshakeState {
-
-        WaitControllerCxnsReplyState() {
-            super(false);
-        }
-
-        @Override
-        void processOFExperimenter(OFExperimenter m) {
-            if(m instanceof OFBsnControllerConnectionsReply) {
-                OFBsnControllerConnectionsReply reply = (OFBsnControllerConnectionsReply) m;
-                handleControllerConnectionMessage(reply);
-
-                setState(new WaitInitialRoleState());
-            } else {
-                unhandledMessageReceived(m);
-            }
-        }
-
-        @Override
-        void processOFPortStatus(OFPortStatus m) {
-            handlePortStatusMessage(m, false);
-        }
-
-        @Override
-        public void enterState() {
-            // Write out request down
-            OFBsnControllerConnectionsRequest request = factory.buildBsnControllerConnectionsRequest()
-                    .build();
-            mainConnection.write(request);
-
-        }
-
-    }
-
-    /**
-     * We are waiting for the initial role reply message (or error indication)
-     * from the switch. Next State: MASTER or SLAVE
-     */
-        public class WaitInitialRoleState extends OFSwitchHandshakeState {
-
-            WaitInitialRoleState() {
-                super(false);
-            }
-
-            @Override
-            void processOFError(OFErrorMsg m) {
-                // role changer will ignore the error if it isn't for it
-                boolean didHandle = roleChanger.deliverError(m);
-                if (!didHandle) {
-                    logError(m);
-                }
-            }
-
-            @Override
-            void processOFExperimenter(OFExperimenter m) {
-                OFControllerRole role = extractNiciraRoleReply(m);
-                // If role == null it measn the message wasn't really a
-                // Nicira role reply. We ignore this case.
-                if (role != null) {
-                    roleChanger.deliverRoleReply(m.getXid(), role);
-                } else if(m instanceof OFBsnControllerConnectionsReply) {
-                    OFBsnControllerConnectionsReply reply = (OFBsnControllerConnectionsReply) m;
-                    handleControllerConnectionMessage(reply);
-                } else {
-                    unhandledMessageReceived(m);
-                }
-            }
-
-            @Override
-            void processOFRoleReply(OFRoleReply m) {
-                roleChanger.deliverRoleReply(m.getXid(), m.getRole());
-            }
-
-            @Override
-            void processOFStatsReply(OFStatsReply m) {
-                illegalMessageReceived(m);
-            }
-
-            @Override
-            void processOFPortStatus(OFPortStatus m) {
-                handlePortStatusMessage(m, false);
-            }
-
-            @Override
-            void enterState(){
-                sendRoleRequest(roleManager.getOFControllerRole());
-            }
-        }
-
-        /**
-         * The switch is in MASTER role. We enter this state after a role
-         * reply from the switch is received (or the controller is MASTER
-         * and the switch doesn't support roles). The handshake is complete at
-         * this point. We only leave this state if the switch disconnects or
-         * if we send a role request for SLAVE /and/ receive the role reply for
-         * SLAVE.
-         */
-        public class MasterState extends OFSwitchHandshakeState {
-
-            MasterState() {
-                super(true);
-            }
-
-            @Override
-            void enterState() {
-                setSwitchStatus(SwitchStatus.MASTER);
-            }
-
-            @LogMessageDoc(level="WARN",
-                message="Received permission error from switch {} while" +
-                         "being master. Reasserting master role.",
-                explanation="The switch has denied an operation likely " +
-                         "indicating inconsistent controller roles",
-                recommendation="This situation can occurs transiently during role" +
-                 " changes. If, however, the condition persists or happens" +
-                 " frequently this indicates a role inconsistency. " +
-                 LogMessageDoc.CHECK_CONTROLLER )
-            @Override
-            void processOFError(OFErrorMsg m) {
-                // role changer will ignore the error if it isn't for it
-                boolean didHandle = roleChanger.deliverError(m);
-                if (didHandle)
-                    return;
-                if ((m.getErrType() == OFErrorType.BAD_REQUEST) &&
-                        (((OFBadRequestErrorMsg)m).getCode() == OFBadRequestCode.EPERM)) {
-                    // We are the master controller and the switch returned
-                    // a permission error. This is a likely indicator that
-                    // the switch thinks we are slave. Reassert our
-                    // role
-                    // FIXME: this could be really bad during role transitions
-                    // if two controllers are master (even if its only for
-                    // a brief period). We might need to see if these errors
-                    // persist before we reassert
-                    switchManagerCounters.epermErrorWhileSwitchIsMaster.increment();
-                    log.warn("Received permission error from switch {} while" +
-                             "being master. Reasserting master role.",
-                             getSwitchInfoString());
-                    reassertRole(OFControllerRole.ROLE_MASTER);
-                }
-                else if ((m.getErrType() == OFErrorType.FLOW_MOD_FAILED) &&
-                        (((OFFlowModFailedErrorMsg)m).getCode() == OFFlowModFailedCode.ALL_TABLES_FULL)) {
-                    sw.setTableFull(true);
-                }
-                else {
-                    logError(m);
-                }
-                dispatchMessage(m);
-            }
-
-            @Override
-            void processOFExperimenter(OFExperimenter m) {
-                OFControllerRole role = extractNiciraRoleReply(m);
-                // If role == null it means the message wasn't really a
-                // Nicira role reply. We ignore just dispatch it to the
-                // OFMessage listenersa in this case.
-                if (role != null) {
-                    roleChanger.deliverRoleReply(m.getXid(), role);
-                } else if (m instanceof OFBsnControllerConnectionsReply){
-                    OFBsnControllerConnectionsReply reply = (OFBsnControllerConnectionsReply) m;
-                    handleControllerConnectionMessage(reply);
-                } else {
-                    dispatchMessage(m);
-                }
-            }
-
-
-            @Override
-            void processOFRoleReply(OFRoleReply m) {
-                roleChanger.deliverRoleReply(m.getXid(), m.getRole());
-            }
-
-            @Override
-            void processOFPortStatus(OFPortStatus m) {
-                handlePortStatusMessage(m, true);
-            }
-
-            @Override
-            void processOFPacketIn(OFPacketIn m) {
-                dispatchMessage(m);
-            }
-
-            @Override
-            void processOFFlowRemoved(OFFlowRemoved m) {
-                dispatchMessage(m);
-            }
-        }
-
-        /**
-         * The switch is in SLAVE role. We enter this state after a role
-         * reply from the switch is received. The handshake is complete at
-         * this point. We only leave this state if the switch disconnects or
-         * if we send a role request for MASTER /and/ receive the role reply for
-         * MASTER.
-         * TODO: CURRENTLY, WE DO NOT DISPATCH ANY MESSAGE IN SLAVE.
-         */
-        public class SlaveState extends OFSwitchHandshakeState {
-
-            SlaveState() {
-                super(true);
-            }
-
-            @Override
-            void enterState() {
-                setSwitchStatus(SwitchStatus.SLAVE);
-            }
-
-            @Override
-            void processOFError(OFErrorMsg m) {
-                // role changer will ignore the error if it isn't for it
-                boolean didHandle = roleChanger.deliverError(m);
-                if (!didHandle) {
-                    logError(m);
-                }
-            }
-
-            @Override
-            void processOFStatsReply(OFStatsReply m) {
-            }
-
-            @Override
-            void processOFPortStatus(OFPortStatus m) {
-                handlePortStatusMessage(m, true);
-            }
-
-            @Override
-            void processOFExperimenter(OFExperimenter m) {
-                OFControllerRole role = extractNiciraRoleReply(m);
-                // If role == null it means the message wasn't really a
-                // Nicira role reply. We ignore it.
-                if (role != null) {
-                    roleChanger.deliverRoleReply(m.getXid(), role);
-                } else if (m instanceof OFBsnControllerConnectionsReply){
-                    OFBsnControllerConnectionsReply reply = (OFBsnControllerConnectionsReply) m;
-                    handleControllerConnectionMessage(reply);
-                } else {
-                    unhandledMessageReceived(m);
-                }
-            }
-
-            @Override
-            void processOFRoleReply(OFRoleReply m) {
-                roleChanger.deliverRoleReply(m.getXid(), m.getRole());
-            }
-
-            @Override
-            @LogMessageDoc(level="WARN",
-                message="Received PacketIn from switch {} while" +
-                         "being slave. Reasserting slave role.",
-                explanation="The switch has receive a PacketIn despite being " +
-                         "in slave role indicating inconsistent controller roles",
-                recommendation="This situation can occurs transiently during role" +
-                         " changes. If, however, the condition persists or happens" +
-                         " frequently this indicates a role inconsistency. " +
-                         LogMessageDoc.CHECK_CONTROLLER )
-            void processOFPacketIn(OFPacketIn m) {
-                // we don't expect packetIn while slave, reassert we are slave
-                switchManagerCounters.packetInWhileSwitchIsSlave.increment();
-                log.warn("Received PacketIn from switch {} while" +
-                         "being slave. Reasserting slave role.", sw);
-                reassertRole(OFControllerRole.ROLE_SLAVE);
-            }
-        };
-
-
-    /**
-     * Create a new unconnected OFChannelHandler.
-     * @param controller
-     * @param broker
-     * @throws SwitchHandshakeHandlerException
-     */
-    OFSwitchHandshakeHandler(@Nonnull IOFConnectionBackend connection,
-                             @Nonnull OFFeaturesReply featuresReply,
-                             @Nonnull IOFSwitchManager switchManager,
-                             @Nonnull RoleManager roleManager,
-                             @Nonnull Timer timer) {
-        Preconditions.checkNotNull(connection, "connection");
-        Preconditions.checkNotNull(featuresReply, "featuresReply");
-        Preconditions.checkNotNull(switchManager, "switchManager");
-        Preconditions.checkNotNull(roleManager, "roleManager");
-        Preconditions.checkNotNull(timer, "timer");
-        Preconditions.checkArgument(connection.getAuxId().equals(OFAuxId.MAIN),
-                "connection must be MAIN connection but is %s", connection);
-
-        this.switchManager = switchManager;
-        this.roleManager = roleManager;
-        this.mainConnection = connection;
-        this.auxConnections = new ConcurrentHashMap<OFAuxId, IOFConnectionBackend>();
-        this.featuresReply = featuresReply;
-        this.timer = timer;
-        this.switchManagerCounters = switchManager.getCounters();
-        this.factory = OFFactories.getFactory(featuresReply.getVersion());
-        this.roleChanger = new RoleChanger(DEFAULT_ROLE_TIMEOUT_NS);
-        setState(new InitState());
-        this.pendingPortStatusMsg = new ArrayList<OFPortStatus>();
-
-        connection.setListener(this);
-    }
-
-    /**
-     * This begins the switch handshake. We start where the OFChannelHandler
-     * left off, right after receiving the OFFeaturesReply.
-     */
-    public void beginHandshake() {
-        Preconditions.checkState(state instanceof InitState, "must be in InitState");
-
-        if (this.featuresReply.getNTables() > 1) {
-            log.debug("Have {} table for switch {}", this.featuresReply.getNTables(),
-                      getSwitchInfoString());
-            // likely supports L2 table extensions. Send set
-            sendHandshakeL2TableSet();
-            // TODO: no L2 SET reply yet, so fire and forget the set
-        }
-
-        if(this.featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0) {
-            setState(new WaitConfigReplyState());
-        } else {
-            // OF 1.3. Ask for Port Descriptions
-            setState(new WaitPortDescStatsReplyState());
-        }
-    }
-
-    public DatapathId getDpid(){
-        return this.featuresReply.getDatapathId();
-    }
-
-    public OFAuxId getOFAuxId(){
-        return this.featuresReply.getAuxiliaryId();
-    }
-
-    /**
-     * Is this a state in which the handshake has completed?
-     * @return true if the handshake is complete
-     */
-    public boolean isHandshakeComplete() {
-        return this.state.isHandshakeComplete();
-    }
-
-    /**
-     * Forwards to RoleChanger. See there.
-     * @param role
-     */
-    void sendRoleRequestIfNotPending(OFControllerRole role) {
-        try {
-            roleChanger.sendRoleRequestIfNotPending(role);
-        } catch (IOException e) {
-             log.error("Disconnecting switch {} due to IO Error: {}",
-                              getSwitchInfoString(), e.getMessage());
-             mainConnection.disconnect();
-        }
-    }
-
-
-    /**
-     * Forwards to RoleChanger. See there.
-     * @param role
-     */
-    void sendRoleRequest(OFControllerRole role) {
-        try {
-            roleChanger.sendRoleRequest(role);
-        } catch (IOException e) {
-             log.error("Disconnecting switch {} due to IO Error: {}",
-                              getSwitchInfoString(), e.getMessage());
-             mainConnection.disconnect();
-        }
-    }
-
-    /**
-     * Dispatches the message to the controller packet pipeline
-     */
-    private void dispatchMessage(OFMessage m) {
-        this.switchManager.handleMessage(this.sw, m, null);
-    }
-
-    /**
-     * Return a string describing this switch based on the already available
-     * information (DPID and/or remote socket)
-     * @return
-     */
-    private String getSwitchInfoString() {
-        if (sw != null)
-            return sw.toString();
-        String channelString;
-        if (mainConnection == null || mainConnection.getRemoteInetAddress() == null) {
-            channelString = "?";
-        } else {
-            channelString = mainConnection.getRemoteInetAddress().toString();
-        }
-        String dpidString;
-        if (featuresReply == null) {
-            dpidString = "?";
-        } else {
-            dpidString = featuresReply.getDatapathId().toString();
-        }
-        return String.format("[%s DPID[%s]]", channelString, dpidString);
-    }
-
-    /**
-     * Update the channels state. Only called from the state machine.
-     * TODO: enforce restricted state transitions
-     * @param state
-     */
-    private void setState(OFSwitchHandshakeState state) {
-        this.state = state;
-        state.logState();
-        state.enterState();
-    }
-
-    private void sendOFAuxSetCxnsRequest(int numAux) {
-        OFBsnSetAuxCxnsRequest request = factory.buildBsnSetAuxCxnsRequest()
-                .setNumAux(numAux)
-                .build();
-        mainConnection.write(request);
-    }
-
-    public void processOFMessage(OFMessage m) {
-        state.processOFMessage(m);
-    }
-
-    /**
-     * Send the configuration requests to tell the switch we want full
-     * packets
-     * @throws IOException
-     */
-    private void sendHandshakeSetConfig() {
-        // Ensure we receive the full packet via PacketIn
-        // FIXME: We don't set the reassembly flags.
-        OFSetConfig configSet = factory.buildSetConfig()
-                .setXid(handshakeTransactionIds--)
-                .setMissSendLen(0xffff)
-                .build();
-
-        // Barrier
-        OFBarrierRequest barrier = factory.buildBarrierRequest()
-                .setXid(handshakeTransactionIds--)
-                .build();
-
-        // Verify (need barrier?)
-        OFGetConfigRequest configReq = factory.buildGetConfigRequest()
-                .setXid(handshakeTransactionIds--)
-                .build();
-        List<OFMessage> msgList = ImmutableList.<OFMessage>of(configSet, barrier, configReq);
-        mainConnection.write(msgList);
-    }
-
-    protected void sendPortDescRequest() {
-        mainConnection.write(factory.portDescStatsRequest(ImmutableSet.<OFStatsRequestFlags>of()));
-    }
-
-    /**
-     * send a description state request
-     */
-    private void sendHandshakeDescriptionStatsRequest() {
-        // Send description stats request to set switch-specific flags
-        OFDescStatsRequest descStatsRequest = factory.buildDescStatsRequest()
-                .setXid(handshakeTransactionIds--)
-                .build();
-        mainConnection.write(descStatsRequest);
-    }
-
-    /** send a BSN GenTable DescStats Request, querying for the tables
-     *  available at the switch.
-     * @return
-     */
-    private long sendHandshakeGenTableDescStatsRequest() {
-        long xid = handshakeTransactionIds--;
-        OFBsnGentableDescStatsRequest descStatsRequest = factory.buildBsnGentableDescStatsRequest()
-                .setXid(xid)
-                .build();
-
-        mainConnection.write(descStatsRequest);
-        return xid;
-    }
-
-    //TODO: Can we nuke this? - jason
-    /**
-     * Send an setL2TableSet message to the switch.
-     */
-    private void sendHandshakeL2TableSet() {
-        // The BsnSetL2Table message is only supported in OF 1.0, so skip if
-        // we're using a later version
-        if (factory.getVersion() != OFVersion.OF_10)
-            return;
-
-        OFBsnSetL2TableRequest m = factory.buildBsnSetL2TableRequest()
-                .setXid(handshakeTransactionIds--)
-                .setL2TableEnable(true)
-                .setL2TablePriority(1000)
-                .build();
-        mainConnection.write(m);
-    }
-
-    OFSwitchHandshakeState getStateForTesting() {
-        return state;
-    }
-
-    void reassertRole(OFControllerRole role){
-        this.roleManager.reassertRole(this, HARole.ofOFRole(role));
-    }
-
-    void useRoleChangerWithOtherTimeoutForTesting(long roleTimeoutMs) {
-        roleChanger = new RoleChanger(TimeUnit.MILLISECONDS.toNanos(roleTimeoutMs));
-    }
-
-    /**
-     * Called by the switch manager when new aux connections have connected.
-     * This alerts the state machine of an aux connection.
-     *
-     * @param connection
-     *            the aux connection
-     */
-    public synchronized void auxConnectionOpened(IOFConnectionBackend connection) {
-        if(log.isDebugEnabled())
-            log.debug("[{}] - Switch Handshake - new aux connection {}",
-                    this.getDpid(), connection.getAuxId());
-        this.state.auxConnectionOpened(connection);
-    }
-
-    /**
-     * Gets the main connection
-     *
-     * @return the main connection
-     */
-    public IOFConnectionBackend getMainConnection() {
-        return this.mainConnection;
-    }
-
-    /**
-     * Determines if this handshake handler is responsible for the supplied
-     * connection.
-     *
-     * @param connection
-     *            an OF connection
-     * @return true if the handler has the connection
-     */
-    public boolean hasConnection(IOFConnectionBackend connection) {
-        if (this.mainConnection.equals(connection)
-            || this.auxConnections.get(connection.getAuxId()) == connection) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    void cleanup() {
-        for (IOFConnectionBackend conn : this.auxConnections.values()) {
-            conn.disconnect();
-        }
-
-        this.mainConnection.disconnect();
-    }
-
-    public String getState() {
-        return this.state.getClass().getSimpleName();
-    }
-
-    public String getQuarantineReason() {
-        if(this.state instanceof QuarantineState) {
-            QuarantineState qs = (QuarantineState) this.state;
-            return qs.getQuarantineReason();
-        }
-        return null;
-    }
-
-    /**
-     * Gets the current connections that this switch handshake handler is
-     * responsible for. Used primarily by the REST API.
-     * @return an immutable list of IOFConnections
-     */
-    public ImmutableList<IOFConnection> getConnections() {
-        ImmutableList.Builder<IOFConnection> builder = ImmutableList.builder();
-
-        builder.add(mainConnection);
-        builder.addAll(auxConnections.values());
-
-        return builder.build();
-    }
-
-
-    /** IOFConnectionListener */
-    @Override
-    public void connectionClosed(IOFConnectionBackend connection) {
-        // Disconnect handler's remaining connections
-        cleanup();
-
-        // Only remove the switch handler when the main connection is
-        // closed
-        if (connection == this.mainConnection) {
-            switchManager.handshakeDisconnected(connection.getDatapathId());
-            if(sw != null) {
-                log.debug("[{}] - main connection {} closed - disconnecting switch",
-                          connection);
-
-                setSwitchStatus(SwitchStatus.DISCONNECTED);
-                switchManager.switchDisconnected(sw);
-            }
-        }
-    }
-
-    @Override
-    public void messageReceived(IOFConnectionBackend connection, OFMessage m) {
-        processOFMessage(m);
-    }
-
-    @Override
-    public boolean isSwitchHandshakeComplete(IOFConnectionBackend connection) {
-        return state.isHandshakeComplete();
-    }
-
-    public void setSwitchStatus(SwitchStatus status) {
-        if(sw != null) {
-            SwitchStatus oldStatus = sw.getStatus();
-            if(oldStatus != status) {
-                sw.setStatus(status);
-                switchManager.switchStatusChanged(sw, oldStatus, status);
-            } else {
-                log.warn("[{}] SwitchStatus change to {} requested, switch is already in status",
-                        mainConnection.getDatapathId());
-            }
-        } else {
-            log.warn("[{}] SwitchStatus change to {} requested, but switch is not allocated yet",
-                    mainConnection.getDatapathId());
-        }
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..51dfddc1a1625f530610f7ab00d407d57c9a9e70
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
@@ -0,0 +1,46 @@
+/**
+*    Copyright 2012, 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.core.internal;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+
+import net.floodlightcontroller.core.OFSwitchBase;
+
+/**
+ * This is the internal representation of an openflow switch.
+ */
+public class OFSwitchImpl extends OFSwitchBase {
+
+    @Override
+    @JsonIgnore
+    public void setSwitchProperties(OFDescriptionStatistics description) {
+        this.description = new OFDescriptionStatistics(description);
+    }
+
+    @Override
+    public OFPortType getPortType(short port_num) {
+        return OFPortType.NORMAL;
+    }
+
+    @Override
+    @JsonIgnore
+    public boolean isFastPort(short port_num) {
+        return false;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java
deleted file mode 100644
index dd1cc86b7566655479c0f87234da9c33f6ed370e..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java
+++ /dev/null
@@ -1,756 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.Executors;
-
-import org.jboss.netty.bootstrap.ServerBootstrap;
-import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.group.ChannelGroup;
-import org.jboss.netty.channel.group.DefaultChannelGroup;
-import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.HAListenerTypeMarker;
-import net.floodlightcontroller.core.HARole;
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.core.IHAListener;
-import net.floodlightcontroller.core.IOFConnectionBackend;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitch.SwitchStatus;
-import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.IOFSwitchDriver;
-import net.floodlightcontroller.core.IOFSwitchListener;
-import net.floodlightcontroller.core.LogicalOFMessageCategory;
-import net.floodlightcontroller.core.PortChangeType;
-import net.floodlightcontroller.core.SwitchDescription;
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
-import net.floodlightcontroller.core.annotations.LogMessageDocs;
-import net.floodlightcontroller.core.internal.Controller.IUpdate;
-import net.floodlightcontroller.core.internal.Controller.ModuleLoaderState;
-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.rest.SwitchRepresentation;
-import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import net.floodlightcontroller.debugevent.IDebugEventService;
-import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
-import net.floodlightcontroller.debugevent.IEventCategory;
-import net.floodlightcontroller.debugevent.MockDebugEventService;
-
-import org.projectfloodlight.openflow.protocol.OFControllerRole;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFAuxId;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-/**
- * The Switch Manager class contains most of the code involved with dealing
- * with switches. The Switch manager keeps track of the switches known to the controller,
- * their status, and any important information about the switch lifecycle. The
- * Switch Manager also provides the switch service, which allows other modules
- * to hook in switch listeners and get basic access to switch information.
- *
- * @author gregor, capveg, sovietaced
- *
- */
-public class OFSwitchManager implements IOFSwitchManager, INewOFConnectionListener, IHAListener, IFloodlightModule, IOFSwitchService {
-    private static final Logger log = LoggerFactory.getLogger(OFSwitchManager.class);
-
-    private volatile OFControllerRole role;
-    private SwitchManagerCounters counters;
-
-    private ConcurrentHashMap<DatapathId, OFSwitchHandshakeHandler> switchHandlers;
-    private ConcurrentHashMap<DatapathId, IOFSwitchBackend> switches;
-
-    private ISwitchDriverRegistry driverRegistry;
-
-    private Set<LogicalOFMessageCategory> logicalOFMessageCategories = new CopyOnWriteArraySet<LogicalOFMessageCategory>();
-    private final List<IAppHandshakePluginFactory> handshakePlugins = new CopyOnWriteArrayList<IAppHandshakePluginFactory>();
-    private int numRequiredConnections = -1;
-    // Event IDs for debug events
-    protected IEventCategory<SwitchEvent> evSwitch;
-
-    // ISwitchService
-    protected Set<IOFSwitchListener> switchListeners;
-
-    // Module Dependencies
-    IFloodlightProviderService floodlightProvider;
-    IDebugEventService debugEventService;
-    IDebugCounterService debugCounterService;
-
-    /** IHAListener Implementation **/
-    @Override
-    public void transitionToActive() {
-        this.role = HARole.ACTIVE.getOFRole();
-    }
-
-    @Override
-    public void transitionToStandby() {
-       this.role = HARole.STANDBY.getOFRole();
-    }
-
-    /** IOFSwitchManager Implementation **/
-
-    @Override public SwitchManagerCounters getCounters() {
-        return this.counters;
-    }
-
-    private void addUpdateToQueue(IUpdate iUpdate) {
-        floodlightProvider.addUpdateToQueue(iUpdate);
-    }
-
-    @Override
-    public synchronized void switchAdded(IOFSwitchBackend sw) {
-        DatapathId dpid = sw.getId();
-        IOFSwitchBackend oldSw = this.switches.put(dpid, sw);
-        // Update event history
-        evSwitch.newEventWithFlush(new SwitchEvent(dpid, "connected"));
-
-        if (oldSw == sw)  {
-            // Note == for object equality, not .equals for value
-            counters.errorActivatedSwitchNotPresent
-                         .increment();
-            log.error("Switch {} added twice?", sw);
-            return;
-        } else if (oldSw != null) {
-            // This happens either when we have switches with duplicate
-            // DPIDs or when a switch reconnects before we saw the
-            // disconnect
-            counters.switchWithSameDpidActivated
-                        .increment();
-            log.warn("New switch added {} for already-added switch {}", sw, oldSw);
-            // We need to disconnect and remove the old switch
-            // TODO: we notify switch listeners that the switch has been
-            // removed and then we notify them that the new one has been
-            // added. One could argue that a switchChanged notification
-            // might be more appropriate in this case....
-            oldSw.cancelAllPendingRequests();
-            addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.REMOVED));
-            oldSw.disconnect();
-        }
-
-    }
-
-    @LogMessageDocs({
-    @LogMessageDoc(level="ERROR",
-            message="Switch {switch} activated but was already active",
-            explanation="A switch that was already activated was " +
-                        "activated again. This should not happen.",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG
-            ),
-    @LogMessageDoc(level="WARN",
-            message="New switch added {switch} for already-added switch {switch}",
-            explanation="A switch with the same DPID as another switch " +
-                    "connected to the controller.  This can be caused by " +
-                    "multiple switches configured with the same DPID, or " +
-                    "by a switch reconnected very quickly after " +
-                    "disconnecting.",
-            recommendation="If this happens repeatedly, it is likely there " +
-                    "are switches with duplicate DPIDs on the network.  " +
-                    "Reconfigure the appropriate switches.  If it happens " +
-                    "very rarely, then it is likely this is a transient " +
-                    "network problem that can be ignored."
-            )
-    })
-    @Override
-    public synchronized void switchStatusChanged(IOFSwitchBackend sw, SwitchStatus oldStatus, SwitchStatus newStatus) {
-        DatapathId dpid = sw.getId();
-        IOFSwitchBackend presentSw = this.switches.get(dpid);
-
-        if (presentSw != sw)  {
-            // Note == for object equality, not .equals for value
-            counters.errorActivatedSwitchNotPresent
-                         .increment();
-            log.warn("Switch {} status change but not present in sync manager", sw);
-            return;
-        }
-        evSwitch.newEventWithFlush(new SwitchEvent(dpid,
-                                                   String.format("%s -> %s",
-                                                                 oldStatus,
-                                                                 newStatus)));
-
-        if(newStatus == SwitchStatus.MASTER  && role != OFControllerRole.ROLE_MASTER) {
-            counters.invalidSwitchActivatedWhileSlave.increment();
-            log.error("Switch {} activated but controller not MASTER", sw);
-            sw.disconnect();
-            return; // only react to switch connections when master
-        }
-
-        if(!oldStatus.isVisible() && newStatus.isVisible()) {
-            // the switch has just become visible. Send 'add' notification to our
-            // listeners
-            addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.ADDED));
-        } else if((oldStatus.isVisible() && !newStatus.isVisible())) {
-            addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.REMOVED));
-        }
-
-        // note: no else if - both may be true
-        if(oldStatus != SwitchStatus.MASTER && newStatus == SwitchStatus.MASTER ) {
-            counters.switchActivated.increment();
-            addUpdateToQueue(new SwitchUpdate(dpid,
-                    SwitchUpdateType.ACTIVATED));
-        } else if(oldStatus == SwitchStatus.MASTER && newStatus != SwitchStatus.MASTER ) {
-            counters.switchDeactivated.increment();
-            addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.DEACTIVATED));
-        }
-    }
-
-    @Override
-    public synchronized void switchDisconnected(IOFSwitchBackend sw) {
-        DatapathId dpid = sw.getId();
-        IOFSwitchBackend presentSw = this.switches.get(dpid);
-
-        if (presentSw != sw)  {
-            // Note == for object equality, not .equals for value
-            counters.errorActivatedSwitchNotPresent
-                         .increment();
-            log.warn("Switch {} disconnect but not present in sync manager", sw);
-            return;
-        }
-
-        counters.switchDisconnected.increment();
-        this.switches.remove(dpid);
-    }
-
-    @Override public void handshakeDisconnected(DatapathId dpid) {
-        this.switchHandlers.remove(dpid);
-    }
-
-    public Iterable<IOFSwitch> getActiveSwitches() {
-        ImmutableList.Builder<IOFSwitch> builder = ImmutableList.builder();
-        for(IOFSwitch sw: switches.values()) {
-            if(sw.getStatus().isControllable())
-                builder.add(sw);
-        }
-        return builder.build();
-    }
-
-    public Map<DatapathId, IOFSwitch> getAllSwitchMap(boolean showInvisible) {
-        if(showInvisible) {
-            return ImmutableMap.<DatapathId, IOFSwitch>copyOf(switches);
-        } else {
-            ImmutableMap.Builder<DatapathId, IOFSwitch> builder = ImmutableMap.builder();
-            for(IOFSwitch sw: switches.values()) {
-                if(sw.getStatus().isVisible())
-                    builder.put(sw.getId(), sw);
-            }
-            return builder.build();
-        }
-    }
-
-    @Override
-    public Map<DatapathId, IOFSwitch> getAllSwitchMap() {
-        return getAllSwitchMap(true);
-    }
-
-    @Override
-    public Set<DatapathId> getAllSwitchDpids() {
-        return getAllSwitchMap().keySet();
-    }
-
-    public Set<DatapathId> getAllSwitchDpids(boolean showInvisible) {
-        return getAllSwitchMap(showInvisible).keySet();
-    }
-
-    @Override
-    public IOFSwitch getSwitch(DatapathId dpid) {
-        return this.switches.get(dpid);
-    }
-
-    @Override
-    public IOFSwitch getActiveSwitch(DatapathId dpid) {
-        IOFSwitchBackend sw = this.switches.get(dpid);
-        if(sw != null && sw.getStatus().isVisible())
-            return sw;
-        else
-            return null;
-    }
-
-    enum SwitchUpdateType {
-        ADDED,
-        REMOVED,
-        ACTIVATED,
-        DEACTIVATED,
-        PORTCHANGED,
-        OTHERCHANGE
-    }
-
-    /**
-     * Update message indicating a switch was added or removed
-     */
-    class SwitchUpdate implements IUpdate {
-        private final DatapathId swId;
-        private final SwitchUpdateType switchUpdateType;
-        private final OFPortDesc port;
-        private final PortChangeType changeType;
-
-        public SwitchUpdate(DatapathId swId, SwitchUpdateType switchUpdateType) {
-            this(swId, switchUpdateType, null, null);
-        }
-
-        public SwitchUpdate(DatapathId swId,
-                            SwitchUpdateType switchUpdateType,
-                            OFPortDesc port,
-                            PortChangeType changeType) {
-            if (switchUpdateType == SwitchUpdateType.PORTCHANGED) {
-                if (port == null) {
-                    throw new NullPointerException("Port must not be null " +
-                            "for PORTCHANGED updates");
-                }
-                if (changeType == null) {
-                    throw new NullPointerException("ChangeType must not be " +
-                            "null for PORTCHANGED updates");
-                }
-            } else {
-                if (port != null || changeType != null) {
-                    throw new IllegalArgumentException("port and changeType " +
-                            "must be null for " + switchUpdateType +
-                            " updates");
-                }
-            }
-            this.swId = swId;
-            this.switchUpdateType = switchUpdateType;
-            this.port = port;
-            this.changeType = changeType;
-        }
-
-        @Override
-        public void dispatch() {
-            if (log.isTraceEnabled()) {
-                log.trace("Dispatching switch update {} {}", swId, switchUpdateType);
-            }
-            if (switchListeners != null) {
-                for (IOFSwitchListener listener : switchListeners) {
-                    switch(switchUpdateType) {
-                        case ADDED:
-                            // don't count here. We have more specific
-                            // counters before the update is created
-                            listener.switchAdded(swId);
-                            break;
-                        case REMOVED:
-                            // don't count here. We have more specific
-                            // counters before the update is created
-                            listener.switchRemoved(swId);
-                            break;
-                        case PORTCHANGED:
-                            counters.switchPortChanged
-                                    .increment();
-                            listener.switchPortChanged(swId, port, changeType);
-                            break;
-                        case ACTIVATED:
-                            // don't count here. We have more specific
-                            // counters before the update is created
-                            listener.switchActivated(swId);
-                            break;
-                        case DEACTIVATED:
-                            // ignore
-                            break;
-                        case OTHERCHANGE:
-                            counters.switchOtherChange
-                                    .increment();
-                            listener.switchChanged(swId);
-                            break;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Handles a new OF Connection
-     * @param IOFConnectionBackend connection an opened OF Connection
-     * @param OFFeaturesReply featuresReply the features reply received for the opened connection.
-     * It is needed for the rest of the switch handshake.
-     */
-    @Override
-    public void connectionOpened(IOFConnectionBackend connection,
-                                 OFFeaturesReply featuresReply) {
-        DatapathId dpid = connection.getDatapathId();
-        OFAuxId auxId = connection.getAuxId();
-
-        log.debug("{} opened", connection);
-
-        if(auxId.equals(OFAuxId.MAIN)) {
-
-            // Create a new switch handshake handler
-            OFSwitchHandshakeHandler handler =
-                    new OFSwitchHandshakeHandler(connection, featuresReply, this,
-                            floodlightProvider.getRoleManager(), floodlightProvider.getTimer());
-
-            OFSwitchHandshakeHandler oldHandler = switchHandlers.put(dpid, handler);
-
-            // Disconnect all the handler's connections
-            if(oldHandler != null){
-                log.debug("{} is a new main connection, killing old handler connections",
-                          connection);
-                oldHandler.cleanup();
-            }
-
-            handler.beginHandshake();
-
-        } else {
-            OFSwitchHandshakeHandler handler = switchHandlers.get(dpid);
-
-            if(handler != null) {
-                handler.auxConnectionOpened(connection);
-            }
-            // Connections have arrived before the switchhandler is ready
-            else {
-                log.warn("{} arrived before main connection, closing connection", connection);
-                connection.disconnect();
-            }
-        }
-    }
-
-    @Override
-    public void addSwitchEvent(DatapathId dpid, String reason, boolean flushNow) {
-        if (flushNow)
-            evSwitch.newEventWithFlush(new SwitchEvent(dpid, reason));
-        else
-            evSwitch.newEventNoFlush(new SwitchEvent(dpid, reason));
-    }
-
-    @Override
-    public synchronized void notifyPortChanged(IOFSwitchBackend sw,
-                           OFPortDesc port,
-                           PortChangeType changeType) {
-        Preconditions.checkNotNull(sw, "switch must not be null");
-        Preconditions.checkNotNull(port, "port must not be null");
-        Preconditions.checkNotNull(changeType, "changeType must not be null");
-
-        if (role != OFControllerRole.ROLE_MASTER) {
-            counters.invalidPortsChanged.increment();
-            return;
-        }
-        if (!this.switches.containsKey(sw.getId())) {
-            counters.invalidPortsChanged.increment();
-            return;
-        }
-
-        if(sw.getStatus().isVisible()) {
-            // no need to count here. SwitchUpdate.dispatch will count
-            // the portchanged
-            SwitchUpdate update = new SwitchUpdate(sw.getId(),
-                    SwitchUpdateType.PORTCHANGED,
-                    port, changeType);
-            addUpdateToQueue(update);
-        }
-    }
-
-    @Override
-    public IOFSwitchBackend  getOFSwitchInstance(IOFConnectionBackend connection,
-                                SwitchDescription description,
-                                OFFactory factory, DatapathId datapathId) {
-        return this.driverRegistry.getOFSwitchInstance(connection, description, factory, datapathId);
-    }
-
-    @Override
-    public void handleMessage(IOFSwitchBackend sw, OFMessage m, FloodlightContext bContext) {
-        floodlightProvider.handleMessage(sw, m, bContext);
-    }
-
-    @Override
-    public void addOFSwitchDriver(String manufacturerDescriptionPrefix,
-                                  IOFSwitchDriver driver) {
-        this.driverRegistry.addSwitchDriver(manufacturerDescriptionPrefix, driver);
-    }
-
-    @Override
-    public ImmutableList<OFSwitchHandshakeHandler> getSwitchHandshakeHandlers() {
-        return ImmutableList.copyOf(this.switchHandlers.values());
-    }
-
-    @Override
-    public int getNumRequiredConnections() {
-        Preconditions.checkState(numRequiredConnections >= 0, "numRequiredConnections not calculated");
-        return numRequiredConnections;
-    }
-
-    public Set<LogicalOFMessageCategory> getLogicalOFMessageCategories() {
-        return logicalOFMessageCategories;
-    }
-
-    private int calcNumRequiredConnections() {
-        if(!this.logicalOFMessageCategories.isEmpty()){
-            // We use tree set here to maintain ordering
-            TreeSet<OFAuxId> auxConnections = new TreeSet<OFAuxId>();
-
-            for(LogicalOFMessageCategory category : this.logicalOFMessageCategories){
-                auxConnections.add(category.getAuxId());
-            }
-
-            OFAuxId first = auxConnections.first();
-            OFAuxId last = auxConnections.last();
-
-            // Check for contiguous set (1....size())
-            if(first.equals(OFAuxId.MAIN)) {
-                if(last.getValue() != auxConnections.size() - 1){
-                    throw new IllegalStateException("Logical OF message categories must maintain contiguous OF Aux Ids! i.e. (0,1,2,3,4,5)");
-                }
-                return auxConnections.size() - 1;
-            } else if(first.equals(OFAuxId.of(1))) {
-                if(last.getValue() != auxConnections.size()){
-                    throw new IllegalStateException("Logical OF message categories must maintain contiguous OF Aux Ids! i.e. (1,2,3,4,5)");
-                }
-                return auxConnections.size();
-            } else {
-                throw new IllegalStateException("Logical OF message categories must start at 0 (MAIN) or 1");
-            }
-        } else {
-            return 0;
-    }
-    }
-
-    /** ISwitchService Implementation **/
-    @Override
-    public void addOFSwitchListener(IOFSwitchListener listener) {
-        this.switchListeners.add(listener);
-    }
-
-    @Override
-    public void removeOFSwitchListener(IOFSwitchListener listener) {
-        this.switchListeners.remove(listener);
-    }
-
-    @Override
-    public void registerLogicalOFMessageCategory(LogicalOFMessageCategory category) {
-        logicalOFMessageCategories.add(category);
-    }
-
-    @Override
-    public boolean isCategoryRegistered(LogicalOFMessageCategory category) {
-        return logicalOFMessageCategories.contains(category);
-    }
-
-    @Override
-    public SwitchRepresentation getSwitchRepresentation(DatapathId dpid) {
-        IOFSwitch sw = this.switches.get(dpid);
-        OFSwitchHandshakeHandler handler = this.switchHandlers.get(dpid);
-
-        if(sw != null && handler != null) {
-            return new SwitchRepresentation(sw, handler);
-        }
-        return null;
-    }
-
-    @Override
-    public List<SwitchRepresentation> getSwitchRepresentations() {
-
-      List<SwitchRepresentation> representations = new ArrayList<SwitchRepresentation>();
-
-      for(DatapathId dpid : this.switches.keySet()) {
-          SwitchRepresentation representation = getSwitchRepresentation(dpid);
-          if(representation != null) {
-              representations.add(representation);
-          }
-      }
-      return representations;
-    }
-
-    @Override
-    public void registerHandshakePlugin(IAppHandshakePluginFactory factory) {
-        Preconditions.checkState(floodlightProvider.getModuleLoaderState() == ModuleLoaderState.INIT,
-                "handshakeplugins can only be registered when the module loader is in state INIT!");
-        handshakePlugins.add(factory);
-    }
-
-    @Override
-    public List<IAppHandshakePluginFactory> getHandshakePlugins() {
-        return handshakePlugins;
-    }
-
-    /* IFloodlightModule Implementation */
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l =
-                new ArrayList<Class<? extends IFloodlightService>>();
-            l.add(IOFSwitchService.class);
-            return l;
-    }
-
-    @Override
-    public Map<Class<? extends IFloodlightService>, IFloodlightService>
-            getServiceImpls() {
-        Map<Class<? extends IFloodlightService>, IFloodlightService> m =
-                new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
-            m.put(IOFSwitchService.class, this);
-            return m;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleDependencies() {
-        Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
-
-        l.add(IFloodlightProviderService.class);
-        l.add(IDebugEventService.class);
-        l.add(IDebugCounterService.class);
-
-        return l;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
-        // Module dependencies
-        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-        debugEventService = context.getServiceImpl(IDebugEventService.class);
-        debugCounterService = context.getServiceImpl(IDebugCounterService.class);
-
-        // Module variables
-        switchHandlers = new ConcurrentHashMap<DatapathId, OFSwitchHandshakeHandler>();
-        switches = new ConcurrentHashMap<DatapathId, IOFSwitchBackend>();
-        floodlightProvider.getTimer();
-        counters = new SwitchManagerCounters(debugCounterService);
-        driverRegistry = new NaiveSwitchDriverRegistry(this);
-
-        this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
-
-        this.counters = new SwitchManagerCounters(debugCounterService);
-
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
-        startUpBase(context);
-        bootstrapNetty();
-    }
-
-    /**
-     * Startup method that includes everything besides the netty boostrap.
-     * This has been isolated for testing.
-     * @param context floodlight module context
-     * @throws FloodlightModuleException
-     */
-    public void startUpBase(FloodlightModuleContext context) throws FloodlightModuleException {
-        // Initial Role
-        role = floodlightProvider.getRole().getOFRole();
-
-        // IRoleListener
-        floodlightProvider.addHAListener(this);
-
-        loadLogicalCategories();
-
-        registerDebugEvents();
-    }
-
-    /**
-     * Bootstraps netty, the server that handles all openflow connections
-     */
-    public void bootstrapNetty() {
-        try {
-            final ServerBootstrap bootstrap = createServerBootStrap();
-
-             bootstrap.setOption("reuseAddr", true);
-             bootstrap.setOption("child.keepAlive", true);
-             bootstrap.setOption("child.tcpNoDelay", true);
-             bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
-
-             ChannelPipelineFactory pfact =
-                     new OpenflowPipelineFactory(this, floodlightProvider.getTimer(), this, debugCounterService);
-             bootstrap.setPipelineFactory(pfact);
-             InetSocketAddress sa = new InetSocketAddress(floodlightProvider.getOFPort());
-             final ChannelGroup cg = new DefaultChannelGroup();
-             cg.add(bootstrap.bind(sa));
-
-             log.info("Listening for switch connections on {}", sa);
-         } catch (Exception e) {
-             throw new RuntimeException(e);
-         }
-    }
-
-    /**
-     * Helper that bootstrapNetty.
-     * @return
-     */
-    private ServerBootstrap createServerBootStrap() {
-        if (floodlightProvider.getWorkerThreads() == 0) {
-            return new ServerBootstrap(
-                    new NioServerSocketChannelFactory(
-                            Executors.newCachedThreadPool(),
-                            Executors.newCachedThreadPool()));
-        } else {
-            return new ServerBootstrap(
-                    new NioServerSocketChannelFactory(
-                            Executors.newCachedThreadPool(),
-                            Executors.newCachedThreadPool(), floodlightProvider.getWorkerThreads()));
-        }
-    }
-
-    /**
-     * Performs startup related actions for logical OF message categories.
-     * Setting the categories list to immutable ensures that unsupported operation
-     * exceptions will be activated if modifications are attempted.
-     */
-    public void loadLogicalCategories() {
-        logicalOFMessageCategories = ImmutableSet.copyOf(logicalOFMessageCategories);
-        numRequiredConnections = calcNumRequiredConnections();
-    }
-
-    /**
-     * Registers an event handler with the debug event service
-     * for switch events.
-     * @throws FloodlightModuleException
-     */
-    private void registerDebugEvents() throws FloodlightModuleException {
-        if (debugEventService == null) {
-            debugEventService = new MockDebugEventService();
-        }
-        evSwitch = debugEventService.buildEvent(SwitchEvent.class)
-                .setModuleName(this.counters.getPrefix())
-                .setEventName("switch-event")
-                .setEventDescription("Switch connected, disconnected or port changed")
-                .setEventType(EventType.ALWAYS_LOG)
-                .setBufferCapacity(100)
-                .register();
-    }
-
-    @Override
-    public String getName() {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
-                                            String name) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
-                                             String name) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-	@Override
-	public void controllerNodeIPsChanged(
-			Map<String, String> curControllerNodeIPs,
-			Map<String, String> addedControllerNodeIPs,
-			Map<String, String> removedControllerNodeIPs) {
-		// TODO Auto-generated method stub
-		
-	}
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java b/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..82a3c67d658ddee3b20f702f2019117a044ccb4b
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java
@@ -0,0 +1,77 @@
+/**
+*    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.core.internal;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.Channels;
+import org.jboss.netty.handler.execution.ExecutionHandler;
+import org.jboss.netty.handler.timeout.IdleStateHandler;
+import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
+import org.jboss.netty.util.ExternalResourceReleasable;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timer;
+
+/**
+ * Creates a ChannelPipeline for a server-side openflow channel
+ * @author readams
+ */
+public class OpenflowPipelineFactory 
+    implements ChannelPipelineFactory, ExternalResourceReleasable {
+
+    protected Controller controller;
+    protected ThreadPoolExecutor pipelineExecutor;
+    protected Timer timer;
+    protected IdleStateHandler idleHandler;
+    protected ReadTimeoutHandler readTimeoutHandler;
+    
+    public OpenflowPipelineFactory(Controller controller,
+                                   ThreadPoolExecutor pipelineExecutor) {
+        super();
+        this.controller = controller;
+        this.pipelineExecutor = pipelineExecutor;
+        this.timer = new HashedWheelTimer();
+        this.idleHandler = new IdleStateHandler(timer, 20, 25, 0);
+        this.readTimeoutHandler = new ReadTimeoutHandler(timer, 30);
+    }
+ 
+    @Override
+    public ChannelPipeline getPipeline() throws Exception {
+        OFChannelHandler handler = new OFChannelHandler(controller);
+        
+        ChannelPipeline pipeline = Channels.pipeline();
+        pipeline.addLast("ofmessagedecoder", new OFMessageDecoder());
+        pipeline.addLast("ofmessageencoder", new OFMessageEncoder());
+        pipeline.addLast("idle", idleHandler);
+        pipeline.addLast("timeout", readTimeoutHandler);
+        pipeline.addLast("handshaketimeout",
+                         new HandshakeTimeoutHandler(handler, timer, 15));
+        if (pipelineExecutor != null)
+            pipeline.addLast("pipelineExecutor",
+                             new ExecutionHandler(pipelineExecutor));
+        pipeline.addLast("handler", handler);
+        return pipeline;
+    }
+
+    @Override
+    public void releaseExternalResources() {
+        timer.stop();        
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/PluginResult.java b/src/main/java/net/floodlightcontroller/core/internal/PluginResult.java
deleted file mode 100644
index e11a527de0a4df91c500bfd5e421fae6c9dd94c9..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/PluginResult.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import javax.annotation.Nonnull;
-
-import net.floodlightcontroller.core.internal.OFSwitchAppHandshakePlugin.PluginResultType;
-
-import com.google.common.base.Preconditions;
-
-/**
- * Class that represents the result of an app handshake plugin.
- *
- */
-public class PluginResult {
-
-    private final PluginResultType result;
-    private final String reason;
-
-    public PluginResult(@Nonnull PluginResultType result) {
-        this.result = result;
-        this.reason = null;
-    }
-
-    public PluginResult(@Nonnull PluginResultType result, String reason) {
-        Preconditions.checkNotNull(result, "result must not be null");
-
-        if(result != PluginResultType.QUARANTINE && reason != null)
-            throw new IllegalStateException("Reason can only be set for Quarantine PluginResult");
-
-        this.result = result;
-        this.reason = reason;
-    }
-
-    public PluginResultType getResultType() {
-        return this.result;
-    }
-
-    public String getReason() {
-        return this.reason;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/internal/RoleManager.java b/src/main/java/net/floodlightcontroller/core/internal/RoleManager.java
deleted file mode 100644
index f37da6707e7e24db99315f16ba02e935a898b00f..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/RoleManager.java
+++ /dev/null
@@ -1,258 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.util.Date;
-import java.util.Map.Entry;
-
-import javax.annotation.Nonnull;
-
-import net.floodlightcontroller.core.HARole;
-import net.floodlightcontroller.core.internal.Controller;
-import net.floodlightcontroller.core.internal.RoleManagerCounters;
-import net.floodlightcontroller.core.IHAListener;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitchBackend;
-import net.floodlightcontroller.core.internal.IOFSwitchService;
-import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler;
-import net.floodlightcontroller.core.internal.Controller.IUpdate;
-
-import net.floodlightcontroller.core.internal.RoleManager;
-import net.floodlightcontroller.core.internal.RoleManager.SwitchRoleUpdate;
-import org.projectfloodlight.openflow.protocol.OFControllerRole;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import net.floodlightcontroller.core.RoleInfo;
-
-/**
- * A utility class to manage the <i>controller roles</i>.
- *
- * A utility class to manage the <i>controller roles</i>  as opposed
- * to the switch roles. The class manages the controllers current role,
- * handles role change requests, and maintains the list of connected
- * switch(-channel) so it can notify the switches of role changes.
- *
- * We need to ensure that every connected switch is always send the
- * correct role. Therefore, switch add, sending of the intial role, and
- * changing role need to use mutexes to ensure this. This has the ugly
- * side-effect of requiring calls between controller and OFChannelHandler
- *
- * This class is fully thread safe. Its method can safely be called from
- * any thread.
- *
- * @author gregor
- *
- */
-public class RoleManager {
-    private volatile RoleInfo currentRoleInfo;
-    private final Controller controller;
-    private final RoleManagerCounters counters;
-    private volatile boolean notifiedLeader;
-
-    private static final Logger log =
-            LoggerFactory.getLogger(RoleManager.class);
-
-    /**
-     * @param role initial role
-     * @param roleChangeDescription initial value of the change description
-     * @throws NullPointerException if role or roleChangeDescription is null
-     */
-    public RoleManager(@Nonnull Controller controller,
-            @Nonnull HARole role,
-            @Nonnull String roleChangeDescription) {
-        Preconditions.checkNotNull(controller, "controller must not be null");
-        Preconditions.checkNotNull(role, "role must not be null");
-        Preconditions.checkNotNull(roleChangeDescription, "roleChangeDescription must not be null");
-
-        this.currentRoleInfo = new RoleInfo(role,
-                                       roleChangeDescription,
-                                       new Date());
-        this.controller = controller;
-        this.counters = new RoleManagerCounters(controller.getDebugCounter());
-    }
-
-    /**
-     * Re-assert a role for the given channel handler.
-     *
-     * The caller specifies the role that should be reasserted. We only
-     * reassert the role if the controller's current role matches the
-     * reasserted role and there is no role request for the reasserted role
-     * pending.
-     * @param ofSwitchHandshakeHandler The OFChannelHandler on which we should reassert.
-     * @param role The role to reassert
-     */
-    public synchronized void reassertRole(OFSwitchHandshakeHandler ofSwitchHandshakeHandler, HARole role) {
-        // check if the requested reassertion actually makes sense
-        if (this.getRole() != role)
-            return;
-        ofSwitchHandshakeHandler.sendRoleRequestIfNotPending(this.getRole().getOFRole());
-    }
-
-    /**
-     * Set the controller's new role and notify switches.
-     *
-     * This method updates the controllers current role and notifies all
-     * connected switches of the new role is different from the current
-     * role. We dampen calls to this method. See class description for
-     * details.
-     *
-     * @param role The new role.
-     * @param roleChangeDescription A textual description of why the role
-     * was changed. For information purposes only.
-     * @throws NullPointerException if role or roleChangeDescription is null
-     */
-    public synchronized void setRole(@Nonnull HARole role, @Nonnull String roleChangeDescription) {
-        Preconditions.checkNotNull(role, "role must not be null");
-        Preconditions.checkNotNull(roleChangeDescription, "roleChangeDescription must not be null");
-
-        if (role == getRole()) {
-            counters.setSameRole.increment();
-            log.debug("Received role request for {} but controller is "
-                    + "already {}. Ignoring it.", role, this.getRole());
-            return;
-        }
-
-        if (this.getRole() == HARole.STANDBY && role == HARole.ACTIVE) {
-            // At this point we are guaranteed that we will execute the code
-            // below exactly once during the lifetime of this process! And
-            // it will be a to MASTER transition
-            counters.setRoleMaster.increment();
-        }
-
-        log.info("Received role request for {} (reason: {})."
-                + " Initiating transition", role, roleChangeDescription);
-
-        currentRoleInfo =
-                new RoleInfo(role, roleChangeDescription, new Date());
-
-        // NOTE: HARoleUpdate will terminate floodlight on transition to STANDBY
-        controller.addUpdateToQueue(new HARoleUpdate(role));
-        controller.addUpdateToQueue(new SwitchRoleUpdate(role));
-
-    }
-
-    @SuppressFBWarnings(value="UG_SYNC_SET_UNSYNC_GET",
-                        justification = "setter is synchronized for mutual exclusion, "
-                                + "currentRoleInfo is volatile, so no sync on getter needed")
-    public synchronized HARole getRole() {
-        return currentRoleInfo.getRole();
-    }
-
-    public synchronized OFControllerRole getOFControllerRole() {
-        return getRole().getOFRole();
-    }
-
-    /**
-     * Return the RoleInfo object describing the current role.
-     *
-     * Return the RoleInfo object describing the current role. The
-     * RoleInfo object is used by REST API users.
-     * @return the current RoleInfo object
-     */
-    public RoleInfo getRoleInfo() {
-        return currentRoleInfo;
-    }
-
-    private void attemptActiveTransition() {
-         if(!switchesHaveAnotherMaster()){
-             // No valid cluster controller connections found, become ACTIVE!
-             setRole(HARole.ACTIVE, "Leader election assigned ACTIVE role");
-             notifiedLeader = false;
-         }
-     }
-
-    /**
-     * Iterates over all the switches and checks to see if they have controller
-     * connections that points towards another master controller.
-     * @return
-     */
-    private boolean switchesHaveAnotherMaster() {
-        IOFSwitchService switchService = controller.getSwitchService();
-
-        for(Entry<DatapathId, IOFSwitch> switchMap : switchService.getAllSwitchMap().entrySet()){
-            IOFSwitchBackend sw = (IOFSwitchBackend) switchMap.getValue();
-            if(sw.hasAnotherMaster()){
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public void notifyControllerConnectionUpdate() {
-        if(notifiedLeader && currentRoleInfo.getRole() != HARole.ACTIVE) {
-            attemptActiveTransition();
-        }
-    }
-
-    /**
-     * Update message indicating controller's role has changed.
-     * RoleManager, which enqueues these updates guarantees that we will
-     * only have a single transition from SLAVE to MASTER.
-     *
-     * When the role update from master to slave is complete, the HARoleUpdate
-     * will terminate floodlight.
-     */
-    private class HARoleUpdate implements IUpdate {
-        private final HARole newRole;
-        public HARoleUpdate(HARole newRole) {
-            this.newRole = newRole;
-        }
-
-        @Override
-        public void dispatch() {
-            if (log.isDebugEnabled()) {
-                log.debug("Dispatching HA Role update newRole = {}",
-                          newRole);
-            }
-            for (IHAListener listener : controller.haListeners.getOrderedListeners()) {
-                if (log.isTraceEnabled()) {
-                    log.trace("Calling HAListener {} with transitionTo{}",
-                              listener.getName(), newRole);
-                }
-                switch(newRole) {
-                    case ACTIVE:
-                        listener.transitionToActive();
-                        break;
-                    case STANDBY:
-                        listener.transitionToStandby();
-                        break;
-                }
-           }
-
-           controller.setNotifiedRole(newRole);
-
-           if(newRole == HARole.STANDBY) {
-               String reason = String.format("Received role request to "
-                       + "transition from ACTIVE to STANDBY (reason: %s)",
-                       getRoleInfo().getRoleChangeDescription());
-               //TODO @Ryan shutdownService.terminate(reason, 0);
-           }
-        }
-    }
-
-    public class SwitchRoleUpdate implements IUpdate {
-        private final HARole role;
-
-        public SwitchRoleUpdate(HARole role) {
-            this.role = role;
-        }
-
-        @Override
-        public void dispatch() {
-            if (log.isDebugEnabled()) {
-                log.debug("Dispatching switch role update newRole = {}, switch role = {}",
-                          this.role, this.role.getOFRole());
-            }
-
-            for (OFSwitchHandshakeHandler h: controller.getSwitchService().getSwitchHandshakeHandlers())
-                h.sendRoleRequest(this.role.getOFRole());
-        }
-    }
-
-    public RoleManagerCounters getCounters() {
-        return this.counters;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/RoleManagerCounters.java b/src/main/java/net/floodlightcontroller/core/internal/RoleManagerCounters.java
deleted file mode 100644
index 04d948339ecedc0c487a57384481f155591eb328..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/RoleManagerCounters.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import net.floodlightcontroller.debugcounter.IDebugCounter;
-import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import net.floodlightcontroller.debugcounter.IDebugCounterService.MetaData;
-
- public class RoleManagerCounters {
-
-        public final String prefix = RoleManager.class.getSimpleName();
-        public final IDebugCounter setSameRole;
-        public final IDebugCounter setRoleMaster;
-
-        public RoleManagerCounters(IDebugCounterService debugCounters) {
-            debugCounters.registerModule(prefix);
-            setSameRole =
-                    debugCounters.registerCounter(
-                                prefix, "set-same-role",
-                                "Controller received a role request for the same " +
-                                "role the controller already had",
-                                MetaData.WARN);
-
-                setRoleMaster =
-                    debugCounters.registerCounter(
-                                prefix, "set-role-master",
-                                "Controller received a role request with role of " +
-                                "MASTER. This counter can be at most 1.");
-        }
-
-        public String getPrefix(){
-            return this.prefix;
-        }
-    }
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/internal/SwitchEvent.java b/src/main/java/net/floodlightcontroller/core/internal/SwitchEvent.java
deleted file mode 100644
index 7a4f36b37cc54e5c9c5d7698ffc04b9ac7adba2d..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/SwitchEvent.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
-import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
-import org.projectfloodlight.openflow.types.DatapathId;
-
-public class SwitchEvent {
-    @EventColumn(name = "dpid", description = EventFieldType.DPID)
-    DatapathId dpid;
-
-    @EventColumn(name = "reason", description = EventFieldType.STRING)
-    String reason;
-
-    public SwitchEvent(DatapathId dpid, String reason) {
-        this.dpid = dpid;
-        this.reason = reason;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/internal/SwitchManagerCounters.java b/src/main/java/net/floodlightcontroller/core/internal/SwitchManagerCounters.java
deleted file mode 100644
index 942809cd45d4a060c865a9355442830e713ae318..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/SwitchManagerCounters.java
+++ /dev/null
@@ -1,208 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import net.floodlightcontroller.debugcounter.IDebugCounter;
-import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import net.floodlightcontroller.debugcounter.IDebugCounterService.MetaData;
-
-public class SwitchManagerCounters {
-
-    public final String prefix = OFSwitchManager.class.getSimpleName();
-    public final IDebugCounter invalidPortsChanged;
-    public final IDebugCounter switchConnected;
-    public final IDebugCounter invalidSwitchActivatedWhileSlave;
-    public final IDebugCounter switchActivated;
-    public final IDebugCounter switchDeactivated;
-    public final IDebugCounter errorActivatedSwitchNotPresent;
-    public final IDebugCounter switchWithSameDpidActivated;
-    public final IDebugCounter switchDisconnected;
-    public final IDebugCounter switchPortChanged;
-    public final IDebugCounter switchOtherChange;
-    public final IDebugCounter switchDisconnectReadTimeout;
-    public final IDebugCounter switchDisconnectHandshakeTimeout;
-    public final IDebugCounter switchDisconnectIOError;
-    public final IDebugCounter switchDisconnectParseError;
-    public final IDebugCounter switchDisconnectSwitchStateException;
-    public final IDebugCounter rejectedExecutionException;
-    public final IDebugCounter switchDisconnectOtherException;
-    public final IDebugCounter unhandledMessage;
-    public final IDebugCounter packetInWhileSwitchIsSlave;
-    public final IDebugCounter roleNotResentBecauseRolePending;
-    public final IDebugCounter epermErrorWhileSwitchIsMaster;
-    public final IDebugCounter roleReplyTimeout;
-    public final IDebugCounter roleReplyReceived;
-    public final IDebugCounter roleReplyErrorUnsupported;
-
-    public SwitchManagerCounters(IDebugCounterService debugCounters) {
-        debugCounters.registerModule(prefix);
-        invalidPortsChanged =
-                debugCounters.registerCounter(
-                            prefix, "invalid-ports-changed",
-                            "Received an unexpected ports changed " +
-                            "notification while the controller was in " +
-                            "SLAVE role.",
-                            MetaData.WARN);
-
-            invalidSwitchActivatedWhileSlave =
-                debugCounters.registerCounter(
-                            prefix, "invalid-switch-activated-while-slave",
-                            "Received an unexpected switchActivated " +
-                            "notification while the controller was in " +
-                            "SLAVE role.",
-                            MetaData.WARN);
-
-            switchActivated =
-                debugCounters.registerCounter(
-                            prefix, "switch-activated",
-                            "A switch connected to this controller is now " +
-                            "in MASTER role");
-
-            switchDeactivated =
-                    debugCounters.registerCounter(
-                                prefix, "switch-activated",
-                                "A switch connected to this controller is now " +
-                                "in SLAVE role");
-
-            errorActivatedSwitchNotPresent = // err
-                debugCounters.registerCounter(
-                            prefix, "error-same-switch-reactivated",
-                            "A switch that was already in active state " +
-                            "was activated again. This indicates a " +
-                            "controller defect",
-                            MetaData.ERROR);
-
-            switchWithSameDpidActivated = // warn
-                debugCounters.registerCounter(
-                            prefix, "switch-with-same-dpid-activated",
-                            "A switch with the same DPID as another switch " +
-                            "connected to the controller. This can be " +
-                            "caused by multiple switches configured with " +
-                            "the same DPID or by a switch reconnecting very " +
-                            "quickly.",
-                            MetaData.WARN);
-
-            switchDisconnected =
-                debugCounters.registerCounter(
-                            prefix, "switch-disconnected",
-                            "FIXME: switch has disconnected");
-
-            switchPortChanged =
-                debugCounters.registerCounter(
-                            prefix, "switch-port-changed",
-                            "Number of times switch ports have changed");
-            switchOtherChange =
-                debugCounters.registerCounter(
-                            prefix, "switch-other-change",
-                            "Number of times other information of a switch " +
-                            "has changed.");
-
-            switchDisconnectReadTimeout =
-                    debugCounters.registerCounter(
-                                prefix, "switch-disconnect-read-timeout",
-                                "Number of times a switch was disconnected due " +
-                                "due the switch failing to send OpenFlow " +
-                                "messages or responding to OpenFlow ECHOs",
-                                MetaData.ERROR);
-                switchDisconnectHandshakeTimeout =
-                    debugCounters.registerCounter(
-                                prefix, "switch-disconnect-handshake-timeout",
-                                "Number of times a switch was disconnected " +
-                                "because it failed to complete the handshake " +
-                                "in time.",
-                                MetaData.ERROR);
-                switchDisconnectIOError =
-                    debugCounters.registerCounter(
-                                prefix, "switch-disconnect-io-error",
-                                "Number of times a switch was disconnected " +
-                                "due to IO errors on the switch connection.",
-                                MetaData.ERROR);
-                switchDisconnectParseError =
-                    debugCounters.registerCounter(
-                                prefix, "switch-disconnect-parse-error",
-                               "Number of times a switch was disconnected " +
-                               "because it sent an invalid packet that could " +
-                               "not be parsed",
-                               MetaData.ERROR);
-
-                switchDisconnectSwitchStateException =
-                    debugCounters.registerCounter(
-                                prefix, "switch-disconnect-switch-state-exception",
-                                "Number of times a switch was disconnected " +
-                                "because it sent messages that were invalid " +
-                                "given the switch connection's state.",
-                                MetaData.ERROR);
-                rejectedExecutionException =
-                    debugCounters.registerCounter(
-                                prefix, "rejected-execution-exception",
-                                "TODO",
-                                MetaData.ERROR);
-
-                switchDisconnectOtherException =
-                    debugCounters.registerCounter(
-                                prefix,  "switch-disconnect-other-exception",
-                                "Number of times a switch was disconnected " +
-                                "due to an exceptional situation not covered " +
-                                "by other counters",
-                                MetaData.ERROR);
-
-                switchConnected =
-                    debugCounters.registerCounter(
-                                prefix, "switch-connected",
-                                "Number of times a new switch connection was " +
-                                "established");
-
-                unhandledMessage =
-                    debugCounters.registerCounter(
-                                prefix, "unhandled-message",
-                                "Number of times an OpenFlow message was " +
-                                "received that the controller ignored because " +
-                                "it was inapproriate given the switch " +
-                                "connection's state.",
-                                MetaData.WARN);
-
-                packetInWhileSwitchIsSlave =
-                        debugCounters.registerCounter(
-                                    prefix, "packet-in-while-switch-is-slave",
-                                    "Number of times a packet in was received " +
-                                    "from a switch that was in SLAVE role. " +
-                                    "Possibly inidicates inconsistent roles.");
-                    epermErrorWhileSwitchIsMaster =
-                        debugCounters.registerCounter(
-                                    prefix, "eperm-error-while-switch-is-master",
-                                    "Number of times a permission error was " +
-                                    "received while the switch was in MASTER role. " +
-                                    "Possibly inidicates inconsistent roles.",
-                                    MetaData.WARN);
-
-                    roleNotResentBecauseRolePending =
-                        debugCounters.registerCounter(
-                                    prefix, "role-not-resent-because-role-pending",
-                                    "The controller tried to reestablish a role " +
-                                    "with a switch but did not do so because a " +
-                                    "previous role request was still pending");
-                    roleReplyTimeout =
-                        debugCounters.registerCounter(
-                                    prefix, "role-reply-timeout",
-                                    "Number of times a role request message did not " +
-                                    "receive the expected reply from a switch",
-                                    MetaData.WARN);
-
-                    roleReplyReceived = // expected RoleReply received
-                        debugCounters.registerCounter(
-                                    prefix, "role-reply-received",
-                                    "Number of times the controller received the " +
-                                    "expected role reply message from a switch");
-
-                    roleReplyErrorUnsupported =
-                        debugCounters.registerCounter(
-                                    prefix, "role-reply-error-unsupported",
-                                    "Number of times the controller received an " +
-                                    "error from a switch in response to a role " +
-                                    "request indicating that the switch does not " +
-                                    "support roles.");
-    }
-
-    public String getPrefix(){
-        return this.prefix;
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/module/ApplicationLoader.java b/src/main/java/net/floodlightcontroller/core/module/ApplicationLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..f56dfa996e90f9550a09fb3ae817ed4685431046
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/ApplicationLoader.java
@@ -0,0 +1,179 @@
+package net.floodlightcontroller.core.module;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+
+/**
+ * Load an application from a configuration directory
+ * @author readams
+ */
+public class ApplicationLoader 
+    implements IFloodlightModule, IApplicationService {
+    
+    /**
+     * Representation for the application configuration
+     * @author readams
+     */
+    public static class Application {
+        private String name;
+        private String[] modules;
+        private Map<String,String> config;
+
+        public String getName() {
+            return name;
+        }
+        public void setName(String name) {
+            this.name = name;
+        }
+        public String[] getModules() {
+            return modules;
+        }
+        public void setModules(String[] modules) {
+            this.modules = modules;
+        }
+        public Map<String, String> getConfig() {
+            return config;
+        }
+        public void setConfig(Map<String, String> config) {
+            this.config = config;
+        }
+    }
+    
+    
+    protected static Logger logger = 
+            LoggerFactory.getLogger(ApplicationLoader.class);
+    protected static ObjectMapper mapper = new ObjectMapper();
+    protected static ObjectReader reader = mapper.reader(Application.class);
+    
+    IModuleService moduleService;
+    
+    private static String APP_RESOURCE_PATH = "apps/";
+    
+    /**
+     * Path containing application description files
+     */
+    protected String applicationPath;
+
+    /**
+     * Application to load
+     */
+    protected String application;
+
+    // *****************
+    // IFloodlightModule
+    // *****************
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(IApplicationService.class);
+        return l;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService>
+            getServiceImpls() {
+
+        Map<Class<? extends IFloodlightService>,
+        IFloodlightService> m =
+        new HashMap<Class<? extends IFloodlightService>,
+                    IFloodlightService>();
+        // We are the class that implements the service
+        m.put(IApplicationService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleDependencies() {
+        return null;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context) 
+            throws FloodlightModuleException {
+        moduleService = context.getServiceImpl(IModuleService.class);
+        
+        Map<String,String> config = context.getConfigParams(this);
+        if (config.containsKey("appsd"))
+            applicationPath = config.get("appsd");
+        if (config.containsKey("application"))
+            application = config.get("application");
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context) 
+            throws FloodlightModuleException {
+        if (application == null) {
+            throw new FloodlightModuleException("No application to load");
+        }
+
+        // attempt to load from application path
+        File appPath;
+        if (applicationPath != null && 
+            (appPath = new File(applicationPath)).exists() && 
+            appPath.isDirectory()) {
+            File[] files = appPath.listFiles();
+            Arrays.sort(files);
+            for (File f : files) {
+                if (f.isFile() && f.getName().matches(".*\\.json$"));
+                try {
+                    if (loadApplication(new FileInputStream(f), f.getPath()))
+                        return;
+                } catch (FileNotFoundException e) {
+                    throw new FloodlightModuleException(e);
+                }
+            }
+        }
+
+        // attempt to load from classpath.  Note here that the file needs
+        // to be named after the application to be successful
+        try {
+            String r = APP_RESOURCE_PATH + application + ".json";
+            InputStream is = getClass().getClassLoader().getResourceAsStream(r);
+            loadApplication(is, "resource: " + r);
+        } catch (Exception e) {
+            throw new FloodlightModuleException(e);
+        }
+        
+    }
+
+    private boolean loadApplication(InputStream is, String path) 
+            throws FloodlightModuleException {
+        Application a;
+        try {
+             a = reader.readValue(is);
+        } catch (Exception e) {
+            throw new FloodlightModuleException("Could not read application " + 
+                                                path, e);
+        }
+        if (application.equals(a.getName())) {
+            Properties p = new Properties();
+            if (a.getConfig() != null)
+                p.putAll(a.getConfig());
+            if (a.getModules() != null) {
+                logger.info("Loading application {}", a.getName());
+                moduleService.loadModulesFromList(Arrays.asList(a.getModules()),
+                                                  p);
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleConfigFileNotFoundException.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleConfigFileNotFoundException.java
deleted file mode 100644
index e20d1e06f74d572590ca63d4660c799b4278a2fd..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleConfigFileNotFoundException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package net.floodlightcontroller.core.module;
-
-public class FloodlightModuleConfigFileNotFoundException extends
-    FloodlightModuleException {
-    private static final long serialVersionUID = 1L;
-
-    public FloodlightModuleConfigFileNotFoundException(String fileName) {
-        super("No such file or directory: " + fileName);
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleContext.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..27c1f968ac0534ecf1bfcd293ce471669016719e
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleContext.java
@@ -0,0 +1,124 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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.core.module;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The service registry for an IFloodlightProvider.
+ * @author alexreimers
+ */
+public class FloodlightModuleContext implements IFloodlightModuleContext {
+    protected Map<Class<? extends IFloodlightService>, IFloodlightService> serviceMap;
+    protected Map<Class<? extends IFloodlightModule>, Map<String, String>> configParams;
+    protected Collection<IFloodlightModule> moduleSet;
+    
+    /**
+     * Creates the ModuleContext for use with this IFloodlightProvider.
+     * This will be used as a module registry for all IFloodlightModule(s).
+     */
+    public FloodlightModuleContext() {
+        serviceMap = 
+                new HashMap<Class<? extends IFloodlightService>,
+                                      IFloodlightService>();
+        configParams =
+                new HashMap<Class<? extends IFloodlightModule>,
+                                Map<String, String>>();
+    }
+    
+    /**
+     * Adds a IFloodlightModule for this Context.
+     * @param clazz the service class
+     * @param service The IFloodlightService to add to the registry
+     */
+    public void addService(Class<? extends IFloodlightService> clazz, 
+                           IFloodlightService service) {
+        serviceMap.put(clazz, service);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends IFloodlightService> T getServiceImpl(Class<T> service) {
+        IFloodlightService s = serviceMap.get(service);
+        return (T)s;
+    }
+    
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getAllServices() {
+        return serviceMap.keySet();
+    }
+    
+    @Override
+    public Collection<IFloodlightModule> getAllModules() {
+        return moduleSet;
+    }
+    
+    public void addModules(Collection<IFloodlightModule> modSet) {
+        if (this.moduleSet == null) 
+            this.moduleSet = new ArrayList<IFloodlightModule>();
+        this.moduleSet.addAll(modSet);
+    }
+
+    @Override
+    public Map<String, String> getConfigParams(IFloodlightModule module) {
+        Class<? extends IFloodlightModule> clazz = module.getClass();
+        return getConfigParams(clazz);
+    }
+
+    @Override
+    public Map<String, String> getConfigParams(Class<? extends IFloodlightModule> clazz) {
+        Map<String, String> retMap = configParams.get(clazz);
+        if (retMap == null) {
+            // Return an empty map if none exists so the module does not
+            // need to null check the map
+            retMap = new HashMap<String, String>();
+            configParams.put(clazz, retMap);
+        }
+
+        // also add any configuration parameters for superclasses, but
+        // only if more specific configuration does not override it
+        for (Class<? extends IFloodlightModule> c : configParams.keySet()) {
+            if (c.isAssignableFrom(clazz)) {
+                for (Map.Entry<String, String> ent : configParams.get(c).entrySet()) {
+                    if (!retMap.containsKey(ent.getKey())) {
+                        retMap.put(ent.getKey(), ent.getValue());
+                    }
+                }
+            }
+        }
+
+        return retMap;
+    }
+    
+    /**
+     * Adds a configuration parameter for a module
+     * @param mod The fully qualified module name to add the parameter to
+     * @param key The configuration parameter key
+     * @param value The configuration parameter value
+     */
+    public void addConfigParam(IFloodlightModule mod, String key, String value) {
+        Map<String, String> moduleParams = configParams.get(mod.getClass());
+        if (moduleParams == null) {
+            moduleParams = new HashMap<String, String>();
+            configParams.put(mod.getClass(), moduleParams);
+        }
+        moduleParams.put(key, value);
+    }
+ }
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleException.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleException.java
new file mode 100644
index 0000000000000000000000000000000000000000..5cddd37fccb8564ae7e31b6f2418a2339ce354c7
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleException.java
@@ -0,0 +1,37 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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.core.module;
+
+public class FloodlightModuleException extends Exception {
+	private static final long serialVersionUID = 1L;
+
+	public FloodlightModuleException(String error) {
+		super(error);
+	}
+
+    public FloodlightModuleException() {
+        super();
+    }
+
+    public FloodlightModuleException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public FloodlightModuleException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..32e4fc031e26eafee38bd282e0a1b21e0b73ebfb
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
@@ -0,0 +1,501 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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.core.module;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Queue;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Finds all Floodlight modules in the class path and loads/starts them.
+ * @author alexreimers
+ *
+ */
+public class FloodlightModuleLoader implements IModuleService {
+    protected static Logger logger = 
+            LoggerFactory.getLogger(FloodlightModuleLoader.class);
+
+    protected static Map<Class<? extends IFloodlightService>,
+                  Collection<IFloodlightModule>> serviceMap;
+    protected static Map<IFloodlightModule,
+                  Collection<Class<? extends 
+                                   IFloodlightService>>> moduleServiceMap;
+    protected static Map<String, IFloodlightModule> moduleNameMap;
+    protected static Object lock = new Object();
+
+    protected static Set<String> initedSet = new HashSet<String>();
+    protected static Set<String> startedSet = new HashSet<String>();;
+    
+    protected FloodlightModuleContext floodlightModuleContext;
+    
+    public static final String COMPILED_CONF_FILE = 
+            "floodlightdefault.properties";
+    public static final String FLOODLIGHT_MODULES_KEY =
+            "floodlight.modules";
+    public static final String FLOODLIGHT_CONFD =
+            "floodlight.confd";
+
+    public FloodlightModuleLoader() {
+        floodlightModuleContext = new FloodlightModuleContext();
+        floodlightModuleContext.addService(IModuleService.class, this);
+    }
+    
+    /**
+     * Finds all IFloodlightModule(s) in the classpath. It creates 3 Maps.
+     * serviceMap -> Maps a service to a module
+     * moduleServiceMap -> Maps a module to all the services it provides
+     * moduleNameMap -> Maps the string name to the module
+     * @throws FloodlightModuleException If two modules are specified in the configuration
+     * that provide the same service.
+     */
+    protected static void findAllModules(Collection<String> mList) throws FloodlightModuleException {
+        synchronized (lock) {
+            if (serviceMap != null) return;
+            serviceMap = 
+                    new HashMap<Class<? extends IFloodlightService>,
+                                Collection<IFloodlightModule>>();
+            moduleServiceMap = 
+                    new HashMap<IFloodlightModule,
+                                Collection<Class<? extends 
+                                           IFloodlightService>>>();
+            moduleNameMap = new HashMap<String, IFloodlightModule>();
+            
+            // Get all the current modules in the classpath
+            ClassLoader cl = Thread.currentThread().getContextClassLoader();
+            ServiceLoader<IFloodlightModule> moduleLoader
+                = ServiceLoader.load(IFloodlightModule.class, cl);
+            // Iterate for each module, iterate through and add it's services
+            Iterator<IFloodlightModule> moduleIter = moduleLoader.iterator();
+            while (moduleIter.hasNext()) {
+                IFloodlightModule m = null;
+                try {
+                    m = moduleIter.next();
+                } catch (ServiceConfigurationError sce) {
+                    logger.error("Could not find module: {}", sce.getMessage());
+                    continue;
+                }
+            //}
+            //for (IFloodlightModule m : moduleLoader) {
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Found module " + m.getClass().getName());
+                }
+
+                // Set up moduleNameMap
+                moduleNameMap.put(m.getClass().getCanonicalName(), m);
+
+                // Set up serviceMap
+                Collection<Class<? extends IFloodlightService>> servs =
+                        m.getModuleServices();
+                if (servs != null) {
+                    moduleServiceMap.put(m, servs);
+                    for (Class<? extends IFloodlightService> s : servs) {
+                        Collection<IFloodlightModule> mods = 
+                                serviceMap.get(s);
+                        if (mods == null) {
+                            mods = new ArrayList<IFloodlightModule>();
+                            serviceMap.put(s, mods);
+                        }
+                        mods.add(m);
+                        // Make sure they haven't specified duplicate modules in the config
+                        int dupInConf = 0;
+                        for (IFloodlightModule cMod : mods) {
+                            if (mList.contains(cMod.getClass().getCanonicalName()))
+                                dupInConf += 1;
+                        }
+                        
+                        if (dupInConf > 1) {
+                            String duplicateMods = "";
+                            for (IFloodlightModule mod : mods) {
+                                duplicateMods += mod.getClass().getCanonicalName() + ", ";
+                            }
+                            throw new FloodlightModuleException("ERROR! The configuraiton" +
+                                    " file specifies more than one module that provides the service " +
+                                    s.getCanonicalName() +". Please specify only ONE of the " +
+                                    "following modules in the config file: " + duplicateMods);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Loads the modules from a specified configuration file.
+     * @param fName The configuration file path
+     * @return An IFloodlightModuleContext with all the modules to be started
+     * @throws FloodlightModuleException
+     */
+    @LogMessageDocs({
+        @LogMessageDoc(level="INFO",
+                message="Loading modules from file {file name}",
+                explanation="The controller is initializing its module " +
+                        "configuration from the specified properties file"),
+        @LogMessageDoc(level="INFO",
+                message="Loading default modules",
+                explanation="The controller is initializing its module " +
+                        "configuration to the default configuration"),
+        @LogMessageDoc(level="ERROR",
+                message="Could not load module configuration file",
+                explanation="The controller failed to read the " +
+                        "module configuration file",
+                recommendation="Verify that the module configuration is " +
+                        "present. " + LogMessageDoc.CHECK_CONTROLLER),
+        @LogMessageDoc(level="ERROR",
+                message="Could not load default modules",
+                explanation="The controller failed to read the default " +
+                        "module configuration",
+                recommendation=LogMessageDoc.CHECK_CONTROLLER)
+    })
+    public IFloodlightModuleContext loadModulesFromConfig(String fName) 
+            throws FloodlightModuleException {
+        Properties prop = new Properties();
+        Collection<String> configMods;
+        
+        File f = new File(fName);
+        if (f.isFile()) {
+            logger.info("Loading modules from file {}", f.getPath());
+            configMods = loadProperties(null, f, prop);
+        } else {
+            logger.info("Loading default modules");
+            InputStream is = this.getClass().getClassLoader().
+                                    getResourceAsStream(COMPILED_CONF_FILE);
+            configMods = loadProperties(is, null, prop);
+        }
+
+        return loadModulesFromList(configMods, prop);
+    }
+    
+    private Collection<String> loadProperties(InputStream is, 
+                                              File confFile, 
+                                              Properties prop) {
+        try {
+            Properties fprop = new Properties();
+            if (is != null) {
+                fprop.load(is);
+            } else {
+                fprop.load(new FileInputStream(confFile));
+            }
+            prop.putAll(fprop);
+        } catch (Exception e) {
+            logger.error("Could not load module configuration file", e);
+            System.exit(1);
+        }
+        
+        Collection<String> configMods = new ArrayList<String>();
+        String moduleList = prop.getProperty(FLOODLIGHT_MODULES_KEY);
+        if (moduleList != null) {
+            moduleList = moduleList.replaceAll("\\s", "");
+            configMods.addAll(Arrays.asList(moduleList.split(",")));
+            prop.remove(FLOODLIGHT_MODULES_KEY);
+        }
+
+        String confdStr = prop.getProperty(FLOODLIGHT_CONFD);
+        prop.remove(FLOODLIGHT_CONFD);
+        if (confdStr != null) {
+            File confd = new File(confdStr);
+            if (confd.exists() && confd.isDirectory()) {
+                File[] files = confd.listFiles();
+                Arrays.sort(files);
+                for (File f : files) {
+                    if (f.isFile() && 
+                        f.getName().matches(".*\\.properties$"))
+                        configMods.addAll(loadProperties(null, f, prop));
+                }
+            }
+        }
+
+        return configMods;
+    }
+    
+    /**
+     * Loads modules (and their dependencies) specified in the list
+     * @param mList The array of fully qualified module names
+     * @param ignoreList The list of Floodlight services NOT to 
+     * load modules for. Used for unit testing.
+     * @return The ModuleContext containing all the loaded modules
+     * @throws FloodlightModuleException
+     */
+    protected IFloodlightModuleContext loadModulesFromList(Collection<String> configMods, Properties prop, 
+            Collection<IFloodlightService> ignoreList) throws FloodlightModuleException {
+        logger.debug("Starting module loader");
+        if (logger.isDebugEnabled() && ignoreList != null)
+            logger.debug("Not loading module services " + ignoreList.toString());
+
+        findAllModules(configMods);
+        
+        Collection<IFloodlightModule> moduleSet = new ArrayList<IFloodlightModule>();
+        Map<Class<? extends IFloodlightService>, IFloodlightModule> moduleMap =
+                new HashMap<Class<? extends IFloodlightService>,
+                            IFloodlightModule>();
+
+        Queue<String> moduleQ = new LinkedList<String>();
+        // Add the explicitly configured modules to the q
+        moduleQ.addAll(configMods);
+        Set<String> modsVisited = new HashSet<String>();
+        
+        while (!moduleQ.isEmpty()) {
+            String moduleName = moduleQ.remove();
+            if (modsVisited.contains(moduleName))
+                continue;
+            modsVisited.add(moduleName);
+            IFloodlightModule module = moduleNameMap.get(moduleName);
+            if (module == null) {
+                throw new FloodlightModuleException("Module " + 
+                        moduleName + " not found");
+            }
+            // If the module provides a service that is in the
+            // services ignorelist don't load it.
+            if ((ignoreList != null) && (module.getModuleServices() != null)) {
+                for (IFloodlightService ifs : ignoreList) {
+                    for (Class<?> intsIgnore : ifs.getClass().getInterfaces()) {
+                        //System.out.println(intsIgnore.getName());
+                        // Check that the interface extends IFloodlightService
+                        //if (intsIgnore.isAssignableFrom(IFloodlightService.class)) {
+                        //System.out.println(module.getClass().getName());
+                        if (intsIgnore.isAssignableFrom(module.getClass())) {
+                            // We now ignore loading this module.
+                            logger.debug("Not loading module " + 
+                                         module.getClass().getCanonicalName() +
+                                         " because interface " +
+                                         intsIgnore.getCanonicalName() +
+                                         " is in the ignore list.");
+                            
+                            continue;
+                        }
+                        //}
+                    }
+                }
+            }
+            
+            // Add the module to be loaded
+            addModule(moduleMap, moduleSet, module);
+            // Add it's dep's to the queue
+            Collection<Class<? extends IFloodlightService>> deps = 
+                    module.getModuleDependencies();
+            if (deps != null) {
+                for (Class<? extends IFloodlightService> c : deps) {
+                    IFloodlightModule m = moduleMap.get(c);
+                    if (m == null) {
+                        Collection<IFloodlightModule> mods = serviceMap.get(c);
+                        // Make sure only one module is loaded
+                        if ((mods == null) || (mods.size() == 0)) {
+                            throw new FloodlightModuleException("ERROR! Could not " +
+                                    "find an IFloodlightModule that provides service " +
+                                    c.toString());
+                        } else if (mods.size() == 1) {
+                            IFloodlightModule mod = mods.iterator().next();
+                            if (!modsVisited.contains(mod.getClass().getCanonicalName()))
+                                moduleQ.add(mod.getClass().getCanonicalName());
+                        } else {
+                            boolean found = false;
+                            for (IFloodlightModule moduleDep : mods) {
+                                if (configMods.contains(moduleDep.getClass().getCanonicalName())) {
+                                    // Module will be loaded, we can continue
+                                    found = true;
+                                    break;
+                                }
+                            }
+                            if (!found) {
+                                String duplicateMods = "";
+                                for (IFloodlightModule mod : mods) {
+                                    duplicateMods += mod.getClass().getCanonicalName() + ", ";
+                                }
+                                throw new FloodlightModuleException("ERROR! Found more " + 
+                                    "than one (" + mods.size() + ") IFloodlightModules that provides " +
+                                    "service " + c.toString() + 
+                                    ". This service is required for " + moduleName + 
+                                    ". Please specify one of the following modules in the config: " + 
+                                    duplicateMods);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        
+        floodlightModuleContext.addModules(moduleSet);
+        parseConfigParameters(prop);
+        initModules(moduleSet);
+        startupModules(moduleSet);
+        
+        return floodlightModuleContext;
+    }
+    
+    @Override
+    public IFloodlightModuleContext loadModulesFromList(Collection<String> configMods, Properties prop) 
+            throws FloodlightModuleException {
+        return loadModulesFromList(configMods, prop, null);
+    }
+    
+    /**
+     * Add a module to the set of modules to load and register its services
+     * @param moduleMap the module map
+     * @param moduleSet the module set
+     * @param module the module to add
+     */
+    protected void addModule(Map<Class<? extends IFloodlightService>, 
+                                           IFloodlightModule> moduleMap,
+                            Collection<IFloodlightModule> moduleSet,
+                            IFloodlightModule module) {
+        if (!moduleSet.contains(module)) {
+            Collection<Class<? extends IFloodlightService>> servs =
+                    moduleServiceMap.get(module);
+            if (servs != null) {
+                for (Class<? extends IFloodlightService> c : servs)
+                    moduleMap.put(c, module);
+            }
+            moduleSet.add(module);
+        }
+    }
+
+    /**
+     * Allocate  service implementations and then init all the modules
+     * @param moduleSet The set of modules to call their init function on
+     * @throws FloodlightModuleException If a module can not properly be loaded
+     */
+    protected void initModules(Collection<IFloodlightModule> moduleSet) 
+                                           throws FloodlightModuleException {
+        for (IFloodlightModule module : moduleSet) {
+            if (initedSet.contains(module.getClass().getCanonicalName()))
+                continue;
+            
+            // Get the module's service instance(s)
+            Map<Class<? extends IFloodlightService>, 
+                IFloodlightService> simpls = module.getServiceImpls();
+
+            // add its services to the context
+            if (simpls != null) {
+                for (Entry<Class<? extends IFloodlightService>, 
+                        IFloodlightService> s : simpls.entrySet()) {
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("Setting " + s.getValue() + 
+                                     "  as provider for " + 
+                                     s.getKey().getCanonicalName());
+                    }
+                    if (floodlightModuleContext.getServiceImpl(s.getKey()) == null) {
+                        floodlightModuleContext.addService(s.getKey(),
+                                                           s.getValue());
+                    } else {
+                        throw new FloodlightModuleException("Cannot set "
+                                                            + s.getValue()
+                                                            + " as the provider for "
+                                                            + s.getKey().getCanonicalName()
+                                                            + " because "
+                                                            + floodlightModuleContext.getServiceImpl(s.getKey())
+                                                            + " already provides it");
+                    }
+                }
+            }
+        }
+        
+        for (IFloodlightModule module : moduleSet) {
+            if (initedSet.contains(module.getClass().getCanonicalName()))
+                continue;
+            initedSet.add(module.getClass().getCanonicalName());
+            
+            // init the module
+            if (logger.isDebugEnabled()) {
+                logger.debug("Initializing " + 
+                             module.getClass().getCanonicalName());
+            }
+            module.init(floodlightModuleContext);
+        }
+    }
+    
+    /**
+     * Call each loaded module's startup method
+     * @param moduleSet the module set to start up
+     * @throws FloodlightModuleException 
+     */
+    protected void startupModules(Collection<IFloodlightModule> moduleSet) 
+            throws FloodlightModuleException {
+        for (IFloodlightModule m : moduleSet) {
+            if (startedSet.contains(m.getClass().getCanonicalName()))
+                continue;
+            startedSet.add(m.getClass().getCanonicalName());
+
+            if (logger.isDebugEnabled()) {
+                logger.debug("Starting " + m.getClass().getCanonicalName());
+            }
+            m.startUp(floodlightModuleContext);
+        }
+    }
+    
+    /**
+     * Parses configuration parameters for each module
+     * @param prop The properties file to use
+     */
+    @LogMessageDoc(level="WARN",
+                   message="Module {module} not found or loaded. " +
+                           "Not adding configuration option {key} = {value}",
+                   explanation="Ignoring a configuration parameter for a " +
+                        "module that is not loaded.")
+    protected void parseConfigParameters(Properties prop) {
+        if (prop == null) return;
+        
+        Enumeration<?> e = prop.propertyNames();
+        while (e.hasMoreElements()) {
+            String key = (String) e.nextElement();
+            // Ignore module list key
+            if (key.equals(FLOODLIGHT_MODULES_KEY)) {
+                continue;
+            }
+            
+            String configValue = null;
+            int lastPeriod = key.lastIndexOf(".");
+            String moduleName = key.substring(0, lastPeriod);
+            String configKey = key.substring(lastPeriod + 1);
+            // Check to see if it's overridden on the command line
+            String systemKey = System.getProperty(key);
+            if (systemKey != null) {
+                configValue = systemKey;
+            } else {
+                configValue = prop.getProperty(key);
+            }
+            
+            IFloodlightModule mod = moduleNameMap.get(moduleName);
+            if (mod == null) {
+                logger.warn("Module {} not found or loaded. " +
+                            "Not adding configuration option {} = {}", 
+                            new Object[]{moduleName, configKey, configValue});
+            } else {
+                floodlightModuleContext.addConfigParam(mod, configKey, configValue);
+            }
+        }
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModulePriority.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModulePriority.java
deleted file mode 100644
index d2e561fbf435049f16fe80c885941c3e50deae40..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/module/FloodlightModulePriority.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- *    Copyright 2013, Big Switch Networks, Inc.
- *
- *    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.core.module;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Set a module priority value so if there are multiple modules that provide
- * a given service, and there is a unique module with maximum priority,
- * we will use that module in preference to lower-priority modules rather
- * than requiring users to manually specify a module to load.  This makes it
- * possible to define a default provider that uses the DEFAULT_PROVIDER priority
- * while the normal modules omit the annotation or specify NORMAL priority.
- * @author readams
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface FloodlightModulePriority {
-    public enum Priority {
-        MINIMUM(0),
-        TEST(10),
-        EXTRA_LOW(20),
-        LOW(30),
-        NORMAL(40),
-        DEFAULT_PROVIDER(50),
-        HIGH(60),
-        EXTRA_HIGH(70);
-
-        private final int value;
-        
-        private Priority(int value) {
-            this.value = value;
-        }
-
-        public int value() {
-            return value;
-        }
-    }
-
-    public Priority value() default Priority.NORMAL;
-}
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightServices.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightServices.java
deleted file mode 100644
index c5d24b72313ee1234ca5beea1a7c9cafef229f38..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/module/FloodlightServices.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package net.floodlightcontroller.core.module;
-
-public @interface FloodlightServices {
-
-}
diff --git a/src/main/java/net/floodlightcontroller/core/module/IApplicationService.java b/src/main/java/net/floodlightcontroller/core/module/IApplicationService.java
new file mode 100644
index 0000000000000000000000000000000000000000..60a916930a06185f5a11199bd1cd839d9ebf8f2b
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/IApplicationService.java
@@ -0,0 +1,5 @@
+package net.floodlightcontroller.core.module;
+
+public interface IApplicationService extends IFloodlightService {
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java b/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java
new file mode 100644
index 0000000000000000000000000000000000000000..982e4be26a7e073dd700599a96a4393697088ed3
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java
@@ -0,0 +1,92 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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.core.module;
+
+import java.util.Collection;
+import java.util.Map;
+
+
+/**
+ * Defines an interface for loadable Floodlight modules.
+ * 
+ * At a high level, these functions are called in the following order:
+ * <ol>
+ * <li> getServices() : what services does this module provide
+ * <li> getDependencies() : list the dependencies
+ * <li> init() : internal initializations (don't touch other modules)
+ * <li> startUp() : external initializations (<em>do</em> touch other modules)
+ * </ol>
+ * 
+ * @author alexreimers
+ */
+public interface IFloodlightModule {
+    
+    /**
+     * Return the list of interfaces that this module implements.
+     * All interfaces must inherit IFloodlightService
+     * @return
+     */
+    
+    public Collection<Class<? extends IFloodlightService>> getModuleServices();
+    
+    /**
+     * Instantiate (as needed) and return objects that implement each
+     * of the services exported by this module.  The map returned maps
+     * the implemented service to the object.  The object could be the
+     * same object or different objects for different exported services.
+     * @return The map from service interface class to service implementation
+     */
+    public Map<Class<? extends IFloodlightService>,
+               IFloodlightService> getServiceImpls();
+    
+    /**
+     * Get a list of Modules that this module depends on.  The module system
+     * will ensure that each these dependencies is resolved before the 
+     * subsequent calls to init().
+     * @return The Collection of IFloodlightServices that this module depends
+     *         on.
+     */
+    
+    public Collection<Class<? extends IFloodlightService>> getModuleDependencies();
+    
+    /**
+     * This is a hook for each module to do its <em>internal</em> initialization, 
+     * e.g., call setService(context.getService("Service"))
+     * 
+     * All module dependencies are resolved when this is called, but not every module 
+     * is initialized.
+     * 
+     * @param context
+     * @throws FloodlightModuleException
+     */
+    
+    void init(FloodlightModuleContext context) throws FloodlightModuleException;
+    
+    /**
+     * This is a hook for each module to do its <em>external</em> initializations,
+     * e.g., register for callbacks or query for state in other modules
+     * 
+     * It is expected that this function will not block and that modules that want
+     * non-event driven CPU will spawn their own threads.
+     * 
+     * @param context
+     * @throws FloodlightModuleException 
+     */
+    
+    void startUp(FloodlightModuleContext context) 
+            throws FloodlightModuleException; 
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/IFloodlightModuleContext.java b/src/main/java/net/floodlightcontroller/core/module/IFloodlightModuleContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..46dea092c2eaa20b180b2176ddd3babbb2d24b26
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/IFloodlightModuleContext.java
@@ -0,0 +1,59 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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.core.module;
+
+import java.util.Collection;
+import java.util.Map;
+
+	
+public interface IFloodlightModuleContext {	
+    /**
+     * Retrieves a casted version of a module from the registry.
+     * @param name The IFloodlightService object type
+     * @return The IFloodlightService
+     * @throws FloodlightModuleException If the module was not found 
+     * or a ClassCastException was encountered.
+     */
+    public <T extends IFloodlightService> T getServiceImpl(Class<T> service);
+    
+    /**
+     * Returns all loaded services
+     * @return A collection of service classes that have been loaded
+     */
+    public Collection<Class<? extends IFloodlightService>> getAllServices();
+    
+    /**
+     * Returns all loaded modules
+     * @return All Floodlight modules that are going to be loaded
+     */
+    public Collection<IFloodlightModule> getAllModules();
+
+    /**
+     * Gets module specific configuration parameters.
+     * @param module The module to get the configuration parameters for
+     * @return A key, value map of the configuration options
+     */
+    public Map<String, String> getConfigParams(IFloodlightModule module);
+
+    /**
+     * Gets module specific configuration parameters.
+     * @param clazz The class of the module to get configuration parameters for
+     * @return A key, value map of the configuration options
+     */
+    public Map<String, String> getConfigParams(Class<? extends
+                                                     IFloodlightModule> clazz);
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/IFloodlightService.java b/src/main/java/net/floodlightcontroller/core/module/IFloodlightService.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a5f4ca653a3fb5e09b651e87d3f302d8506ce14
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/IFloodlightService.java
@@ -0,0 +1,27 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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.core.module;
+
+/**
+ * This is the base interface for any IFloodlightModule package that provides 
+ * a service.
+ * @author alexreimers
+ *
+ */
+public abstract interface IFloodlightService {
+    // This space is intentionally left blank....don't touch it
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/IModuleService.java b/src/main/java/net/floodlightcontroller/core/module/IModuleService.java
new file mode 100644
index 0000000000000000000000000000000000000000..440ad2de6240709ef9e8a068e4b557f6b1444d82
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/IModuleService.java
@@ -0,0 +1,18 @@
+package net.floodlightcontroller.core.module;
+
+import java.util.Collection;
+import java.util.Properties;
+
+public interface IModuleService extends IFloodlightService {
+    /**
+     * Loads modules (and their dependencies) specified in the list.
+     * @param configMods The collection of fully qualified module names to load.
+     * @param prop The list of properties that are configuration options.
+     * @return The ModuleContext containing all the loaded modules.
+     * @throws FloodlightModuleException
+     */
+    public IFloodlightModuleContext 
+        loadModulesFromList(Collection<String> configMods, 
+                            Properties prop) throws FloodlightModuleException; 
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/ModuleLoaderResource.java b/src/main/java/net/floodlightcontroller/core/module/ModuleLoaderResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4406117effee39794485dcedac4885fbea0a3ad
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/ModuleLoaderResource.java
@@ -0,0 +1,120 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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.core.module;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Returns list of modules loaded by Floodlight.
+ * @author Rob Sherwood
+ */
+public class ModuleLoaderResource extends ServerResource {
+    protected static Logger log = 
+            LoggerFactory.getLogger(ModuleLoaderResource.class);
+    
+    /**
+     * Retrieves information about loaded modules.
+     * @return Information about loaded modules.
+     */
+    @Get("json")
+    public Map<String, Object> retrieve() {
+    	return retrieveInternal(false);
+    }
+    
+    /**
+     * Retrieves all modules and their dependencies available
+     * to Floodlight.
+     * @param loadedOnly Whether to return all modules available or only the ones loaded.
+     * @return Information about modules available or loaded.
+     */
+    public Map<String, Object> retrieveInternal(boolean loadedOnly) {    
+        Map<String, Object> model = new HashMap<String, Object>();
+
+        Set<String> loadedModules = new HashSet<String>();
+        for (Object val : getContext().getAttributes().values()) {
+        	if ((val instanceof IFloodlightModule) || (val instanceof IFloodlightService)) {
+        		String serviceImpl = val.getClass().getCanonicalName();
+        		loadedModules.add(serviceImpl);
+        		// log.debug("Tracking serviceImpl " + serviceImpl);
+        	}
+        }
+
+        for (String moduleName : 
+        				FloodlightModuleLoader.moduleNameMap.keySet() ) {
+        	Map<String,Object> moduleInfo = new HashMap<String, Object>();
+
+        	IFloodlightModule module = 
+        				FloodlightModuleLoader.moduleNameMap.get(
+        						moduleName);
+        		
+        	Collection<Class<? extends IFloodlightService>> deps = 
+        			module.getModuleDependencies();
+        	if ( deps == null)
+            	deps = new HashSet<Class<? extends IFloodlightService>>();
+        	Map<String,Object> depsMap = new HashMap<String, Object> ();
+        	for (Class<? extends IFloodlightService> service : deps) {
+        		Object serviceImpl = getContext().getAttributes().get(service.getCanonicalName());
+        		if (serviceImpl != null)
+        			depsMap.put(service.getCanonicalName(), serviceImpl.getClass().getCanonicalName());
+        		else
+        			depsMap.put(service.getCanonicalName(), "<unresolved>");
+
+        	}
+            moduleInfo.put("depends", depsMap);
+        	
+            Collection<Class<? extends IFloodlightService>> provides = 
+            		module.getModuleServices();
+        	if ( provides == null)
+            	provides = new HashSet<Class<? extends IFloodlightService>>();
+        	Map<String,Object> providesMap = new HashMap<String,Object>();
+        	for (Class<? extends IFloodlightService> service : provides) {
+        		providesMap.put(service.getCanonicalName(), module.getServiceImpls().get(service).getClass().getCanonicalName());
+        	}
+        	moduleInfo.put("provides", providesMap);            		
+
+    		moduleInfo.put("loaded", false);	// not loaded, by default
+
+        	// check if this module is loaded directly
+        	if (loadedModules.contains(module.getClass().getCanonicalName())) {
+        		moduleInfo.put("loaded", true);  			
+        	} else {
+        		// if not, then maybe one of the services it exports is loaded
+        		for (Class<? extends IFloodlightService> service : provides) {
+        			String modString = module.getServiceImpls().get(service).getClass().getCanonicalName();
+        			if (loadedModules.contains(modString))
+                		moduleInfo.put("loaded", true);
+        			/* else 
+        				log.debug("ServiceImpl not loaded " + modString); */
+        		}
+        	}
+
+        	if ((Boolean)moduleInfo.get("loaded")|| !loadedOnly )
+        		model.put(moduleName, moduleInfo);
+        }            
+        return model;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/Run.java b/src/main/java/net/floodlightcontroller/core/module/Run.java
deleted file mode 100644
index 4bf8a2ed41d270282b5dbda582a8ac7c32ec448f..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/module/Run.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.floodlightcontroller.core.module;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Indicate the run() method of a floodlight module
- * @author readams
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Run {
-    /** declares this run method as the application main method. Will be called last and is not expected to
-     *  return. It is a configuration error to have more than one module declaring a main method.
-     * @return
-     */
-    boolean mainLoop() default false;
-}
diff --git a/src/main/java/net/floodlightcontroller/core/rest/AggregateStatistics.java b/src/main/java/net/floodlightcontroller/core/rest/AggregateStatistics.java
deleted file mode 100644
index 3d0fe680e544ffa5a7701ad42f0037fe8de9037c..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/rest/AggregateStatistics.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package net.floodlightcontroller.core.rest;
-
-import org.projectfloodlight.openflow.protocol.OFAggregateStatsReply;
-import org.projectfloodlight.openflow.types.U64;
-
-public class AggregateStatistics {
-
-    private final U64 packetCount;
-    private final U64 byteCount;
-    private final long flowCount;
-
-    private AggregateStatistics(U64 packetCount, U64 byteCount, long flowCount) {
-        this.packetCount = packetCount;
-        this.byteCount = byteCount;
-        this.flowCount = flowCount;
-    }
-
-    public static AggregateStatistics of(U64 packetCount, U64 byteCount,
-            long flowCount) {
-        return new AggregateStatistics(packetCount, byteCount, flowCount);
-    }
-
-    public static AggregateStatistics of(OFAggregateStatsReply statsReply) {
-        return new AggregateStatistics(statsReply.getPacketCount(),
-                statsReply.getByteCount(), statsReply.getFlowCount());
-    }
-
-    public U64 getPacketCount() {
-        return packetCount;
-    }
-
-    public U64 getByteCount() {
-        return byteCount;
-    }
-
-    public long getFlowCount() {
-        return flowCount;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/rest/SwitchRepresentation.java b/src/main/java/net/floodlightcontroller/core/rest/SwitchRepresentation.java
deleted file mode 100644
index 03a46f462b68300c61639052b03a7931bfcc4861..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/rest/SwitchRepresentation.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package net.floodlightcontroller.core.rest;
-
-import java.net.SocketAddress;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-
-import net.floodlightcontroller.core.IOFConnection;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler;
-import org.projectfloodlight.openflow.protocol.OFCapabilities;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.types.DatapathId;
-
-import com.google.common.base.Preconditions;
-
-/**
- * REST representation of an OF Switch. Stitches together data from different
- * areas of the platform to provide a complete, centralized representation.
- * @author Jason Parraga <Jason.Parraga@bigswitch.com>
- *
- */
-public class SwitchRepresentation {
-
-    private final long buffers;
-    private final Set<OFCapabilities> capabilities;
-    private final Short tables;
-    private final SocketAddress inetAddress;
-    private final Collection<OFPortDesc> sortedPorts;
-    private final boolean isConnected;
-    private final Date connectedSince;
-    private final DatapathId dpid;
-    private final Map<Object, Object> attributes;
-    private final boolean isActive;
-
-    private final Collection<IOFConnection> connections;
-    private final String handshakeState;
-    private final String quarantineReason;
-
-    public SwitchRepresentation(@Nonnull IOFSwitch sw, @Nonnull OFSwitchHandshakeHandler handshakeHandler) {
-        Preconditions.checkNotNull(sw, "switch must not be null");
-        Preconditions.checkNotNull(handshakeHandler, "handshakeHandler must not be null");
-
-        // IOFSwitch
-        this.buffers = sw.getBuffers();
-        this.capabilities = sw.getCapabilities();
-        this.tables = sw.getTables();
-        this.inetAddress = sw.getInetAddress();
-        this.sortedPorts = sw.getSortedPorts();
-        this.isConnected = sw.isConnected();
-        this.connectedSince = sw.getConnectedSince();
-        this.dpid = sw.getId();
-        this.attributes = sw.getAttributes();
-        this.isActive = sw.isActive();
-
-        // OFSwitchHandshakeHandler
-        this.connections = handshakeHandler.getConnections();
-        this.handshakeState = handshakeHandler.getState();
-        this.quarantineReason = handshakeHandler.getQuarantineReason();
-    }
-
-    public long getBuffers() {
-        return this.buffers;
-    }
-
-    public Short getTables() {
-        return this.tables;
-    }
-
-    public Set<OFCapabilities> getCapabilities() {
-        return this.capabilities;
-    }
-
-    public SocketAddress getInetAddress() {
-        return this.inetAddress;
-    }
-
-    public Collection<OFPortDesc> getSortedPorts() {
-        return this.sortedPorts;
-    }
-
-    public boolean isConnected() {
-        return this.isConnected;
-    }
-
-    public Date getConnectedSince() {
-        return this.connectedSince;
-    }
-
-    public DatapathId getDpid() {
-        return this.dpid;
-    }
-
-    public Map<Object, Object> getAttributes() {
-        return this.attributes;
-    }
-
-    public boolean isActive() {
-        return this.isActive;
-    }
-
-    public Collection<IOFConnection> getConnections() {
-        return this.connections;
-    }
-
-    public String getHandshakeState() {
-        return this.handshakeState;
-    }
-
-    public String getQuarantineReason() {
-        return this.quarantineReason;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/rest/TableStatistics.java b/src/main/java/net/floodlightcontroller/core/rest/TableStatistics.java
deleted file mode 100644
index 480ff2004e0eae6f133fb79a94adc318b6b57cf4..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/rest/TableStatistics.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package net.floodlightcontroller.core.rest;
-
-import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
-import org.projectfloodlight.openflow.types.TableId;
-import org.projectfloodlight.openflow.types.U64;
-
-public class TableStatistics {
-
-    private final TableId tableId;
-    private final long activeCount;
-    private final U64 lookupCount;
-    private final U64 matchedCount;
-
-    private TableStatistics(TableId tableId, long activeCount, U64 lookupCount, U64 matchedCount) {
-        this.tableId = tableId;
-        this.activeCount = activeCount;
-        this.lookupCount = lookupCount;
-        this.matchedCount = matchedCount;
-    }
-
-    public static TableStatistics of(TableId tableId, long activeCount, U64 lookupCount, U64 matchedCount) {
-        return new TableStatistics(tableId, activeCount, lookupCount, matchedCount);
-    }
-
-    public static TableStatistics of(OFTableStatsEntry entry) {
-        return new TableStatistics(entry.getTableId(),
-                entry.getActiveCount(), entry.getLookupCount(), entry.getMatchedCount());
-    }
-
-    public TableId getTableId() {
-        return tableId;
-    }
-
-    public long getActiveCount() {
-        return activeCount;
-    }
-
-    public U64 getLookupCount() {
-        return lookupCount;
-    }
-
-    public U64 getMatchedCount() {
-        return matchedCount;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java b/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java
index 2f40532961b5912b2981f4ce5fbd75d668b1beb8..0e91bc9b488d6009eaaac15641aba1b0cde5a998 100644
--- a/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java
+++ b/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java
@@ -17,7 +17,7 @@
 
 package net.floodlightcontroller.core.types;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFMessage;
 
 import net.floodlightcontroller.core.IOFSwitch;
 
diff --git a/src/main/java/net/floodlightcontroller/core/util/URIUtil.java b/src/main/java/net/floodlightcontroller/core/util/URIUtil.java
deleted file mode 100644
index 01a44ccf0cda6782ebbcaef9c5874361c4c272b0..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/util/URIUtil.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package net.floodlightcontroller.core.util;
-
-import java.net.URI;
-
-public class URIUtil {
-
-    public static URI createURI(String hostname, int port) {
-        return URI.create("tcp://" + hostname + ":" + port);
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
index cea740239ce1bfa20ad0d705135d507beaa188bb..c957e6356ba9833bb2b40e331881cccd528b40a1 100644
--- a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
@@ -25,12 +25,10 @@ import java.util.Map;
 import java.util.Set;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
-
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsType;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.util.HexString;
 import org.restlet.resource.Get;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,26 +50,26 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
     public Map<String, Object> retrieveInternal(String statType) {
         HashMap<String, Object> model = new HashMap<String, Object>();
 
-        OFStatsType type = null;
+        OFStatisticsType type = null;
         REQUESTTYPE rType = null;
 
         if (statType.equals("port")) {
-            type = OFStatsType.PORT;
+            type = OFStatisticsType.PORT;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("queue")) {
-            type = OFStatsType.QUEUE;
+            type = OFStatisticsType.QUEUE;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("flow")) {
-            type = OFStatsType.FLOW;
+            type = OFStatisticsType.FLOW;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("aggregate")) {
-            type = OFStatsType.AGGREGATE;
+            type = OFStatisticsType.AGGREGATE;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("desc")) {
-            type = OFStatsType.DESC;
+            type = OFStatisticsType.DESC;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("table")) {
-            type = OFStatsType.TABLE;
+            type = OFStatisticsType.TABLE;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("features")) {
             rType = REQUESTTYPE.OFFEATURES;
@@ -82,11 +80,11 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
         IFloodlightProviderService floodlightProvider =
                 (IFloodlightProviderService)getContext().getAttributes().
                     get(IFloodlightProviderService.class.getCanonicalName());
-        Set<DatapathId> switchDpids = floodlightProvider.getAllSwitchDpids();
+        Set<Long> switchDpids = floodlightProvider.getAllSwitchDpids();
         List<GetConcurrentStatsThread> activeThreads = new ArrayList<GetConcurrentStatsThread>(switchDpids.size());
         List<GetConcurrentStatsThread> pendingRemovalThreads = new ArrayList<GetConcurrentStatsThread>();
         GetConcurrentStatsThread t;
-        for (DatapathId l : switchDpids) {
+        for (Long l : switchDpids) {
             t = new GetConcurrentStatsThread(l, rType, type);
             activeThreads.add(t);
             t.start();
@@ -100,9 +98,9 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
             for (GetConcurrentStatsThread curThread : activeThreads) {
                 if (curThread.getState() == State.TERMINATED) {
                     if (rType == REQUESTTYPE.OFSTATS) {
-                        model.put(HexString.toHexString(curThread.getSwitchId().getLong()), curThread.getStatisticsReply());
+                        model.put(HexString.toHexString(curThread.getSwitchId()), curThread.getStatisticsReply());
                     } else if (rType == REQUESTTYPE.OFFEATURES) {
-                        model.put(HexString.toHexString(curThread.getSwitchId().getLong()), curThread.getFeaturesReply());
+                        model.put(HexString.toHexString(curThread.getSwitchId()), curThread.getFeaturesReply());
                     }
                     pendingRemovalThreads.add(curThread);
                 }
@@ -132,13 +130,13 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
     }
 
     protected class GetConcurrentStatsThread extends Thread {
-        private List<OFStatsReply> switchReply;
-        private DatapathId switchId;
-        private OFStatsType statType;
+        private List<OFStatistics> switchReply;
+        private long switchId;
+        private OFStatisticsType statType;
         private REQUESTTYPE requestType;
         private OFFeaturesReply featuresReply;
 
-        public GetConcurrentStatsThread(DatapathId switchId, REQUESTTYPE requestType, OFStatsType statType) {
+        public GetConcurrentStatsThread(long switchId, REQUESTTYPE requestType, OFStatisticsType statType) {
             this.switchId = switchId;
             this.requestType = requestType;
             this.statType = statType;
@@ -146,7 +144,7 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
             this.featuresReply = null;
         }
 
-        public List<OFStatsReply> getStatisticsReply() {
+        public List<OFStatistics> getStatisticsReply() {
             return switchReply;
         }
 
@@ -154,7 +152,7 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
             return featuresReply;
         }
 
-        public DatapathId getSwitchId() {
+        public long getSwitchId() {
             return switchId;
         }
 
diff --git a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java
index 457cc91c20fc15d854abeb148eccc27daef1c2d1..eeaebe22c38aafb04834f2bac82e51be991e21be 100644
--- a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java
@@ -23,16 +23,14 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Collection;
-import java.util.Set;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.ImmutablePort;
 import net.floodlightcontroller.util.FilterIterator;
 
-import org.projectfloodlight.openflow.protocol.OFCapabilities;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.util.HexString;
 import org.restlet.data.Form;
 import org.restlet.data.Status;
 import org.restlet.resource.Get;
@@ -54,7 +52,7 @@ public class ControllerSwitchesResource extends ServerResource {
             this.sw = sw;
         }
 
-        public Set<OFActionType> getActions() {
+        public int getActions() {
             return sw.getActions();
         }
 
@@ -85,11 +83,11 @@ public class ControllerSwitchesResource extends ServerResource {
             return rv;
         }
 
-        public long getBuffers() {
+        public int getBuffers() {
             return sw.getBuffers();
         }
 
-        public Set<OFCapabilities> getCapabilities() {
+        public int getCapabilities() {
             return sw.getCapabilities();
         }
 
@@ -116,8 +114,8 @@ public class ControllerSwitchesResource extends ServerResource {
             return addr.toString();
         }
 
-        public Collection<OFPortDesc> getPorts() {
-            return sw.getPorts();
+        public Collection<OFPhysicalPort> getPorts() {
+            return ImmutablePort.ofPhysicalPortListOf(sw.getPorts());
         }
     }
 
@@ -160,13 +158,13 @@ public class ControllerSwitchesResource extends ServerResource {
                 (IFloodlightProviderService)getContext().getAttributes().
                     get(IFloodlightProviderService.class.getCanonicalName());
 
-        DatapathId switchDPID = null;
+        Long switchDPID = null;
 
         Form form = getQuery();
         String dpid = form.getFirstValue("dpid", true);
         if (dpid != null) {
             try {
-                switchDPID = DatapathId.of(dpid);
+                switchDPID = HexString.toLong(dpid);
             } catch (Exception e) {
                 setStatus(Status.CLIENT_ERROR_BAD_REQUEST, DPID_ERROR);
                 return null;
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java
index f8f9ff0e643e369cd3e342ddd933a302b4340cae..34aa2eaa763f2953fa6b03ad95a82c25683add11 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java
@@ -23,7 +23,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.projectfloodlight.openflow.types.DatapathId;
+import org.openflow.util.HexString;
 import org.restlet.resource.Get;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -47,8 +47,8 @@ public class SwitchCounterCategoriesResource extends CounterResourceBase {
         String layer = (String) getRequestAttributes().get("layer");
 
         if (switchID.equalsIgnoreCase("all")) {
-            for (DatapathId dpid : floodlightProvider.getAllSwitchDpids()) {
-                switchID = dpid.toString();
+            for (Long dpid : floodlightProvider.getAllSwitchDpids()) {
+                switchID = HexString.toHexString(dpid);
 
                 getOneSwitchCounterCategoriesJson(model, switchID, counterName, layer);
             }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java
index f078dd8c198687537a1a1365026b40400ab7bc95..34755ea083536a430652842a231fd22944e27552 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java
@@ -22,7 +22,7 @@ import java.net.URLDecoder;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.projectfloodlight.openflow.types.DatapathId;
+import org.openflow.util.HexString;
 import org.restlet.resource.Get;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -46,8 +46,8 @@ public class SwitchCounterResource extends CounterResourceBase {
 
         if (switchID.equalsIgnoreCase("all")) {
             getOneSwitchCounterJson(model, ICounterStoreService.CONTROLLER_NAME, counterName);
-            for (DatapathId dpid : floodlightProvider.getAllSwitchDpids()) {
-                switchID = dpid.toString();
+            for (Long dpid : floodlightProvider.getAllSwitchDpids()) {
+                switchID = HexString.toHexString(dpid);
 
                 getOneSwitchCounterJson(model, switchID, counterName);
             }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
index aa48eb3c1c63deb2f603f0668ffe5edc1999dd95..6b4a46318fb7dbac07fd628ed23fcc44b8fb146a 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
@@ -26,23 +26,17 @@ import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
 
-import org.projectfloodlight.openflow.protocol.OFFactories;
-import org.projectfloodlight.openflow.protocol.OFFactory;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
-import org.projectfloodlight.openflow.protocol.OFMatch;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFAggregateStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFAggregateStatsReply;
-import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFPortStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFQueueStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFStatsType;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.util.HexString;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-import org.projectfloodlight.openflow.types.DatapathId;
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.statistics.OFAggregateStatisticsRequest;
+import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
+import org.openflow.protocol.statistics.OFPortStatisticsRequest;
+import org.openflow.protocol.statistics.OFQueueStatisticsRequest;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.util.HexString;
 import org.restlet.resource.ResourceException;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
@@ -73,34 +67,21 @@ public class SwitchResourceBase extends ServerResource {
                    		"from the switch",
                    recommendation=LogMessageDoc.CHECK_SWITCH + " " +
                    		LogMessageDoc.GENERIC_ACTION)
-    protected List<OFStatsReply> getSwitchStatistics(DatapathId switchId,
-                                                     OFStatsType statType) {
+    protected List<OFStatistics> getSwitchStatistics(long switchId,
+                                                     OFStatisticsType statType) {
         IFloodlightProviderService floodlightProvider =
                 (IFloodlightProviderService)getContext().getAttributes().
                     get(IFloodlightProviderService.class.getCanonicalName());
 
         IOFSwitch sw = floodlightProvider.getSwitch(switchId);
-        
-        OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
-        OFFlowStatsRequest flowStatsRequest = factory.buildFlowStatsRequest()
-            .build();
-        
-        Future<List<OFFlowStatsReply>> future = sw.queryStatistics(flowStatsRequest);
-        return future.get();
-        
-        
-        sw.get
-        
-        Future<List<OFStatsReply>> future;
-        List<OFStatsReply> values = null;
-        if (sw != null) 
-        	{
-        	OFFactory
-            OFStatsRequest<> req = new OFFactory.
-            req.cre(statType);
+        Future<List<OFStatistics>> future;
+        List<OFStatistics> values = null;
+        if (sw != null) {
+            OFStatisticsRequest req = new OFStatisticsRequest();
+            req.setStatisticType(statType);
             int requestLength = req.getLengthU();
-            if (statType == OFStatsType.FLOW) {
-                OFStatsRequest specificReq = new OFFlowStatisticsRequest();
+            if (statType == OFStatisticsType.FLOW) {
+                OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest();
                 OFMatch match = new OFMatch();
                 match.setWildcards(0xffffffff);
                 specificReq.setMatch(match);
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
index d7b4c01290368ce9b89b5a36c05c2aa236219926..e6d66e2c24db29bad055be5d9a0132778e7ffe87 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
@@ -18,7 +18,7 @@ package net.floodlightcontroller.core.web;
 
 import java.util.HashMap;
 
-import org.projectfloodlight.openflow.types.DatapathId;
+import org.openflow.util.HexString;
 import org.restlet.resource.ServerResource;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -53,7 +53,7 @@ public class SwitchRoleResource extends ServerResource {
             return model;
         }
 
-        DatapathId dpid = DatapathId.of(switchId);
+        Long dpid = HexString.toLong(switchId);
         IOFSwitch sw = floodlightProvider.getSwitch(dpid);
         if (sw == null)
             return null;
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
index a70d120ae59ff618d8ae57a3b59601cb2e66bbec..57771f718bfa51295220deb2a3d9e0e88c4223e3 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
@@ -20,8 +20,7 @@ package net.floodlightcontroller.core.web;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.projectfloodlight.openflow.protocol.OFStatsType;
-import org.projectfloodlight.openflow.types.DatapathId;
+import org.openflow.protocol.statistics.OFStatisticsType;
 import org.restlet.resource.Get;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,17 +42,17 @@ public class SwitchStatisticsResource extends SwitchResourceBase {
         String statType = (String) getRequestAttributes().get("statType");
         
         if (statType.equals("port")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.PORT);
+            values = getSwitchStatistics(switchId, OFStatisticsType.PORT);
         } else if (statType.equals("queue")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.QUEUE);
+            values = getSwitchStatistics(switchId, OFStatisticsType.QUEUE);
         } else if (statType.equals("flow")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.FLOW);
+            values = getSwitchStatistics(switchId, OFStatisticsType.FLOW);
         } else if (statType.equals("aggregate")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.AGGREGATE);
+            values = getSwitchStatistics(switchId, OFStatisticsType.AGGREGATE);
         } else if (statType.equals("desc")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.DESC);
+            values = getSwitchStatistics(switchId, OFStatisticsType.DESC);
         } else if (statType.equals("table")) {
-            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.TABLE);
+            values = getSwitchStatistics(switchId, OFStatisticsType.TABLE);
         } else if (statType.equals("features")) {
             values = getSwitchFeaturesReply(switchId);
         }
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.java
index f5f3aea8c93f9a5769ad3eb8aa536755cf83e802..ce4d3ba3c51480ad3ab3b488c398727efb6d85b4 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.java
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/ByteArrayMACSerializer.java
@@ -23,7 +23,7 @@ import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.util.HexString;
 
 /**
  * Serialize a MAC as colon-separated hexadecimal
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/DPIDSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/DPIDSerializer.java
index d07a254680074dc53bcd4095bf7dca98b39253e0..6df067ead245a209b12ce20347c237913a8f7b29 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/DPIDSerializer.java
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/DPIDSerializer.java
@@ -23,7 +23,7 @@ import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.util.HexString;
 
 /**
  * Serialize a DPID as colon-separated hexadecimal
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/MACSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/MACSerializer.java
index c7ea09b8364fa9b6e740da82b2a3f55ec6458fb8..c797681edf2e8779365293188e89f51b9b4c30a1 100644
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/MACSerializer.java
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/MACSerializer.java
@@ -23,7 +23,7 @@ import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.util.HexString;
 
 /**
  * Serialize a MAC as colon-separated hexadecimal
diff --git a/src/main/java/net/floodlightcontroller/counter/CounterStore.java b/src/main/java/net/floodlightcontroller/counter/CounterStore.java
index d3067e60d5a75ec31e3b5ae911a3f5c8633e6137..bfe3b963f82b61bc0529005e4edd5b1f0b4d5164 100644
--- a/src/main/java/net/floodlightcontroller/counter/CounterStore.java
+++ b/src/main/java/net/floodlightcontroller/counter/CounterStore.java
@@ -24,7 +24,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
@@ -34,10 +33,8 @@ import net.floodlightcontroller.counter.CounterValue.CounterType;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.types.DatapathId;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -72,12 +69,12 @@ public class CounterStore implements IFloodlightModule, ICounterStoreService {
         }
 
     protected class CounterKeyTuple {
-        OFType msgType;
-        DatapathId dpid;
+        byte msgType;
+        long dpid;
         short l3type;
         byte l4type;
 
-        public CounterKeyTuple(OFType msgType, DatapathId dpid, short l3type, byte l4type){
+        public CounterKeyTuple(byte msgType, long dpid, short l3type, byte l4type){
             this.msgType = msgType;
             this.dpid = dpid;
             this.l3type = l3type;
@@ -102,8 +99,8 @@ public class CounterStore implements IFloodlightModule, ICounterStoreService {
         public int hashCode() {
             final int prime = 283;
             int result = 1;
-            result = prime * result + msgType.hashCode();
-            result = prime * result + (int) (dpid.getLong() ^ (dpid.getLong() >>> 32));
+            result = prime * result + msgType;
+            result = prime * result + (int) (dpid ^ (dpid >>> 32));
             result = prime * result + l3type;
             result = prime * result + l4type;
             return result;
@@ -158,7 +155,7 @@ public class CounterStore implements IFloodlightModule, ICounterStoreService {
 
     @Override
     public void updatePacketInCountersLocal(IOFSwitch sw, OFMessage m, Ethernet eth) {
-        if (((OFPacketIn)m).getData().length <= 0) {
+        if (((OFPacketIn)m).getPacketData().length <= 0) {
             return;
         }
         CounterKeyTuple countersKey = this.getCountersKey(sw, m, eth);
@@ -294,7 +291,7 @@ public class CounterStore implements IFloodlightModule, ICounterStoreService {
     //*******************************
 
     protected CounterKeyTuple getCountersKey(IOFSwitch sw, OFMessage m, Ethernet eth) {
-        OFType mtype = m.getType();
+        byte mtype = m.getType().getTypeValue();
         short l3type = 0;
         byte l4type = 0;
 
@@ -325,7 +322,7 @@ public class CounterStore implements IFloodlightModule, ICounterStoreService {
         int l3type = eth.getEtherType() & 0xffff;
         String switchIdHex = sw.getStringId();
         String etherType = String.format("%04x", eth.getEtherType());
-        String packetName = m.getType().getClass().getName();
+        String packetName = m.getType().toClass().getName();
         packetName = packetName.substring(packetName.lastIndexOf('.')+1);
 
         // L2 Type
@@ -473,7 +470,7 @@ public class CounterStore implements IFloodlightModule, ICounterStoreService {
 
         /* String values for names */
         String switchIdHex = sw.getStringId();
-        String packetName = m.getType().getClass().getName();
+        String packetName = m.getType().toClass().getName();
         packetName = packetName.substring(packetName.lastIndexOf('.')+1);
 
         String controllerFMCounterName =
diff --git a/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java b/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java
index 79bf4548d6e6a6fc677eb3ebd5da3c2918808e55..c0cbd55916086103bb4df820ca1b33974ed3dcca 100644
--- a/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java
+++ b/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java
@@ -19,7 +19,7 @@ package net.floodlightcontroller.counter;
 import java.util.List;
 import java.util.Map;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFMessage;
 
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.IFloodlightService;
diff --git a/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java b/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java
index eff67dcacfa1a85b48c8fdaf820250046310912e..bdcc690b349c4497d8ca7b645b23a03d3af2ce85 100644
--- a/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java
+++ b/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java
@@ -23,7 +23,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFMessage;
 
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java b/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java
deleted file mode 100644
index 8da964aa2d4c203801de60af38a968aacd52ae30..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java
+++ /dev/null
@@ -1,338 +0,0 @@
-package net.floodlightcontroller.debugcounter;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.TreeMap;
-import java.util.regex.Pattern;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-
-/**
- * A node in the counter hierarchy tree. We use a single tree and "merge" the
- * counter modules into this single tree.
- *
- * <li> Adding modules or counters to the tree must happen at the root of the tree.
- * <li> The root and the first level of the tree (root and module) are a shim
- * layers that con't have an actual counter value. We represent this with a
- * null counter.
- *
- * @author gregor
- */
-class CounterNode implements Iterable<DebugCounterImpl> {
-    private static final String QUOTED_SEP = Pattern.quote("/");
-
-    /** path/hierarchy of this counter without leading /. An empty string
-     * represents the root. A string without a / is a module name
-     */
-    private final String hierarchy;
-    /**
-     * The path/hierarchy elements split into a list
-     */
-    private final List<String> hierarchyElements;
-    /**
-     * The actual counter instance for this node. Can be null for
-     * root level and module level.
-     */
-    private final DebugCounterImpl counter;
-    private final TreeMap<String,CounterNode> children = new TreeMap<>();
-
-    /**
-     * convert module name and counter hierarchy into list of
-     * hierarchy elements
-     * @param moduleName
-     * @param counterHierarchy
-     * @return
-     */
-    static List<String>
-    getHierarchyElements(String moduleName, String counterHierarchy) {
-        DebugCounterServiceImpl.verifyModuleNameSanity(moduleName);
-        List<String> ret = new ArrayList<>();
-        ret.add(moduleName);
-        if (counterHierarchy == null || counterHierarchy.isEmpty()) {
-            return ret;
-        }
-        for (String element: counterHierarchy.split(QUOTED_SEP)) {
-            ret.add(element);
-        }
-        return ret;
-    }
-
-    private CounterNode(List<String> hierarchyElements,
-                        DebugCounterImpl counter) {
-        super();
-        this.hierarchyElements = ImmutableList.copyOf(hierarchyElements);
-        this.hierarchy = Joiner.on("/").join(hierarchyElements);
-        this.counter = counter;
-    }
-
-    /**
-     * Create a new counter hierarchy tree and return the root
-     * @return
-     */
-    public static CounterNode newTree() {
-        return new CounterNode(ImmutableList.<String>of(), null);
-    }
-
-    /** verify that this node is the root */
-    private void verifyIsRoot() {
-        if (hierarchyElements.size() != 0) {
-            throw new IllegalStateException("This not is not the root. Can "
-                    + "only call addCounter() on the root node. Current node: "
-                    + hierarchy);
-        }
-    }
-
-
-
-    /**
-     *  return the full hierarchy as string, including module name
-     */
-    @Nonnull
-    String getHierarchy() {
-        return hierarchy;
-    }
-
-    /**
-     * @return the list of hierarchy elements for this node
-     */
-    @Nonnull
-    List<String> getHierarchyElements() {
-        return hierarchyElements;
-    }
-
-    /**
-     * @return this node's counters
-     */
-    @Nullable
-    DebugCounterImpl getCounter() {
-        return counter;
-    }
-
-    /**
-     * Reset this counter all counter below it in the hierarchy
-     */
-    void resetHierarchy() {
-        for (DebugCounterImpl cur: this) {
-            cur.reset();
-        }
-    }
-
-    /**
-     * Return an Iterable over all DebugCounterImpls at and below this
-     * node. Note we return an Iterable<DebugCounterImpls> not
-     * Iterable<IDebugCounter> on purpose.
-     * @return
-     */
-    Iterable<DebugCounterImpl> getCountersInHierarchy() {
-        return this;
-    }
-
-
-    /**
-     * Lookup the CounterNode identified by the hieraryElements if it exists.
-     * Returns null if no such CounterNode is found. Must only be called on
-     * the root of the tree.
-     * @param hierarchyElements
-     * @return
-     */
-    CounterNode lookup(List<String> hierarchyElements) {
-        CounterNode cur = this;
-        for (String element: hierarchyElements) {
-            cur = cur.children.get(element);
-            if (cur == null) {
-                break;
-            }
-        }
-        return cur;
-    }
-
-    /**
-     * Add the given moduleName to the tree. Can only be called on the root.
-     * If the module already exists, the all counters of the module will
-     * be reset.
-     * @param moduleName
-     * @return true if the module was newly added, false if the module already
-     * existed
-     */
-    boolean addModule(@Nonnull String moduleName) {
-        verifyIsRoot();
-        if (children.containsKey(moduleName)) {
-            children.get(moduleName).resetHierarchy();
-            return false;
-        } else {
-            CounterNode newNode =
-                    new CounterNode(ImmutableList.of(moduleName), null);
-            children.put(moduleName, newNode);
-            return true;
-        }
-    }
-
-    /**
-     * Add the given Counter to the hierarchy. If the counterHierarcy already
-     * exists, reset the hierarchy
-     * @param counter
-     * @return null if the counterHierarchy is newly registered, otherwise
-     * returns the already registered DebugCounterImpl instance
-     * @throws IllegalArgumentException if the parent of the counter does not
-     * yet exist
-     */
-    @Nullable
-    DebugCounterImpl addCounter(@Nonnull DebugCounterImpl counter) {
-        verifyIsRoot();
-        ArrayList<String> path = new ArrayList<>();
-        path.add(counter.getModuleName());
-        for (String element: counter.getCounterHierarchy().split(QUOTED_SEP)) {
-            path.add(element);
-        }
-        String newCounterName = path.get(path.size()-1);
-
-        CounterNode parent = lookup(path.subList(0, path.size()-1));
-        if (parent == null) {
-            throw new IllegalArgumentException("Missing hierarchy level for "
-                    + "counter: " + counter.getModuleName() + " "
-                    + counter.getCounterHierarchy());
-        }
-        if (parent.children.containsKey(newCounterName)) {
-            CounterNode old = parent.children.get(newCounterName);
-            // FIXME: we should check that old and new has the same
-            // description and meta-data, otherwise we should probably thrown
-            // and exception and refuse the operation.
-            old.resetHierarchy();
-            return old.counter;
-        } else {
-            CounterNode newNode = new CounterNode(path, counter);
-            parent.children.put(newCounterName, newNode);
-            return counter;
-        }
-    }
-
-
-    /**
-     * Iterator over the counters in the counter hierarchy.
-     * Iteration order is a pre-order tree walk. Children of a node are
-     * visited in sorted order.
-     * @author gregor
-     */
-    private final static class CounterIterator implements Iterator<DebugCounterImpl> {
-        // NOTE: since some counters
-        ArrayDeque<CounterNode> stack = new ArrayDeque<>();
-        CounterNode curNode = null;
-        private CounterIterator(CounterNode root) {
-            stack.push(root);
-            gotoNextNode();
-        }
-
-        private void gotoNextNode() {
-            while (true) {
-                curNode = null;
-                if (stack.isEmpty()) {
-                    break;
-                }
-                curNode = stack.pop();
-                for (CounterNode child: curNode.children.descendingMap().values()) {
-                    stack.push(child);
-                }
-                if (curNode.counter != null) {
-                    break;
-                }
-            }
-        }
-
-        @Override
-        public boolean hasNext() {
-            return curNode != null;
-        }
-
-        @Override
-        public DebugCounterImpl next() {
-            if (curNode == null) {
-                throw new NoSuchElementException();
-            }
-            DebugCounterImpl ret = curNode.counter;
-            gotoNextNode();
-            return ret;
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    @Override
-    public Iterator<DebugCounterImpl> iterator() {
-        return new CounterIterator(this);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result
-                 + ((children == null) ? 0 : children.hashCode());
-        result = prime * result
-                 + ((counter == null) ? 0 : counter.hashCode());
-        result = prime * result
-                 + ((hierarchy == null) ? 0 : hierarchy.hashCode());
-        result = prime
-                 * result
-                 + ((hierarchyElements == null) ? 0
-                                               : hierarchyElements.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (getClass() != obj.getClass()) return false;
-        CounterNode other = (CounterNode) obj;
-        if (children == null) {
-            if (other.children != null) return false;
-        } else if (!children.equals(other.children)) return false;
-        if (counter == null) {
-            if (other.counter != null) return false;
-        } else if (!counter.equals(other.counter)) return false;
-        if (hierarchy == null) {
-            if (other.hierarchy != null) return false;
-        } else if (!hierarchy.equals(other.hierarchy)) return false;
-        if (hierarchyElements == null) {
-            if (other.hierarchyElements != null) return false;
-        } else if (!hierarchyElements.equals(other.hierarchyElements))
-                                                                      return false;
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return toString(0);
-    }
-
-    public String toString(int indent) {
-        StringBuilder builder = new StringBuilder();
-        for (int i = 0; i < indent; i++) {
-            builder.append(" ");
-        }
-        builder.append("hierarchy=");
-        builder.append(hierarchy);
-        builder.append(", counter=");
-        builder.append(counter);
-        builder.append(", children=");
-        builder.append(children.keySet());
-        builder.append("\n");
-        for (CounterNode child: children.values()) {
-            builder.append(child.toString(indent + 3));
-        }
-        return builder.toString();
-    }
-
-
-
-}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bb1ce16757a4faa363205c346887ad1fbbc0d3e
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java
@@ -0,0 +1,741 @@
+package net.floodlightcontroller.debugcounter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+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.debugcounter.web.DebugCounterRoutable;
+import net.floodlightcontroller.restserver.IRestApiService;
+
+/**
+ * This class implements a central store for all counters used for debugging the
+ * system. For counters based on traffic-type, see ICounterStoreService.
+ *
+ * @author Saurav
+ */
+public class DebugCounter implements IFloodlightModule, IDebugCounterService {
+    protected static Logger log = LoggerFactory.getLogger(DebugCounter.class);
+
+    /**
+     * registered counters need a counter id
+     */
+    protected AtomicInteger counterIdCounter = new AtomicInteger();
+
+    /**
+     * The counter value
+     */
+    protected class MutableLong {
+        long value = 0;
+        public void increment() { value += 1; }
+        public void increment(long incr) { value += incr; }
+        public long get() { return value; }
+        public void set(long val) { value = val; }
+      }
+
+    /**
+     * protected class to store counter information
+     */
+    public static class CounterInfo {
+        String moduleCounterHierarchy;
+        String counterDesc;
+        CounterType ctype;
+        String moduleName;
+        String counterHierarchy;
+        int counterId;
+        boolean enabled;
+        String[] metaData;
+
+        public CounterInfo(int counterId, boolean enabled,
+                           String moduleName, String counterHierarchy,
+                           String desc, CounterType ctype, String... metaData) {
+            this.moduleCounterHierarchy = moduleName + "/" + counterHierarchy;
+            this.moduleName = moduleName;
+            this.counterHierarchy = counterHierarchy;
+            this.counterDesc = desc;
+            this.ctype = ctype;
+            this.counterId = counterId;
+            this.enabled = enabled;
+            this.metaData = metaData;
+        }
+
+        public String getModuleCounterHierarchy() { return moduleCounterHierarchy; }
+        public String getCounterDesc() { return counterDesc; }
+        public CounterType getCtype() { return ctype; }
+        public String getModuleName() { return moduleName; }
+        public String getCounterHierarchy() { return counterHierarchy; }
+        public int getCounterId() { return counterId; }
+        public boolean isEnabled() { return enabled; }
+        public String[] getMetaData() { return metaData; }
+    }
+
+    //******************
+    //   Global stores
+    //******************
+
+    /**
+     * Counter info for a debug counter
+     */
+    public class DebugCounterInfo {
+        CounterInfo cinfo;
+        AtomicLong cvalue;
+
+        public DebugCounterInfo(CounterInfo cinfo) {
+            this.cinfo = cinfo;
+            this.cvalue = new AtomicLong();
+        }
+        public CounterInfo getCounterInfo() {
+            return cinfo;
+        }
+        public Long getCounterValue() {
+            return cvalue.get();
+        }
+    }
+
+    /**
+     * Global debug-counter storage across all threads. These are
+     * updated from the local per thread counters by the flush counters method.
+     */
+    protected static DebugCounterInfo[] allCounters =
+                            new DebugCounterInfo[MAX_COUNTERS];
+
+
+    /**
+     * per module counters, indexed by the module name and storing three levels
+     * of Counter information in the form of CounterIndexStore
+     */
+    protected ConcurrentHashMap<String, ConcurrentHashMap<String, CounterIndexStore>>
+        moduleCounters = new ConcurrentHashMap<String,
+                                                ConcurrentHashMap<String,
+                                                                   CounterIndexStore>>();
+
+    protected class CounterIndexStore {
+        int index;
+        Map<String, CounterIndexStore> nextLevel;
+
+        public CounterIndexStore(int index, Map<String,CounterIndexStore> cis) {
+            this.index = index;
+            this.nextLevel = cis;
+        }
+    }
+
+    /**
+     * fast global cache for counter ids that are currently active
+     */
+    protected Set<Integer> currentCounters = Collections.newSetFromMap(
+                                         new ConcurrentHashMap<Integer,Boolean>());
+
+    //******************
+    // Thread local stores
+    //******************
+
+    /**
+     * Thread local storage of counter info
+     */
+    protected class LocalCounterInfo {
+        boolean enabled;
+        MutableLong cvalue;
+
+        public LocalCounterInfo(boolean enabled) {
+            this.enabled = enabled;
+            this.cvalue = new MutableLong();
+        }
+    }
+
+    /**
+     * Thread local debug counters used for maintaining counters local to a thread.
+     */
+    protected final ThreadLocal<LocalCounterInfo[]> threadlocalCounters =
+            new ThreadLocal<LocalCounterInfo[]>() {
+        @Override
+        protected LocalCounterInfo[] initialValue() {
+            return new LocalCounterInfo[MAX_COUNTERS];
+        }
+    };
+
+    /**
+     * Thread local cache for counter ids that are currently active.
+     */
+    protected final ThreadLocal<Set<Integer>> threadlocalCurrentCounters =
+            new ThreadLocal<Set<Integer>>() {
+        @Override
+        protected Set<Integer> initialValue() {
+            return new HashSet<Integer>();
+        }
+    };
+
+    //*******************************
+    //   IDebugCounter
+    //*******************************
+
+    protected class CounterImpl implements IDebugCounter {
+        private final int counterId;
+
+        public CounterImpl(int counterId) {
+            this.counterId = counterId;
+        }
+
+        @Override
+        public void updateCounterWithFlush() {
+            if (!validCounterId()) return;
+            updateCounter(counterId, 1, true);
+        }
+
+        @Override
+        public void updateCounterNoFlush() {
+            if (!validCounterId()) return;
+            updateCounter(counterId, 1, false);
+        }
+
+        @Override
+        public void updateCounterWithFlush(int incr) {
+            if (!validCounterId()) return;
+            updateCounter(counterId, incr, true);
+        }
+
+        @Override
+        public void updateCounterNoFlush(int incr) {
+            if (!validCounterId()) return;
+            updateCounter(counterId, incr, false);
+        }
+
+        @Override
+        public long getCounterValue() {
+            if (!validCounterId()) return -1;
+            return allCounters[counterId].cvalue.get();
+        }
+
+        private boolean validCounterId() {
+            if (counterId < 0 || counterId >= MAX_COUNTERS) {
+                log.error("Invalid counterId invoked");
+                return false;
+            }
+            return true;
+        }
+
+    }
+
+   //*******************************
+   //   IDebugCounterService
+   //*******************************
+
+   @Override
+   public IDebugCounter registerCounter(String moduleName, String counterHierarchy,
+                           String counterDescription, CounterType counterType,
+                           String... metaData)
+               throws MaxCountersRegistered, MaxHierarchyRegistered,
+                      MissingHierarchicalLevel {
+       // check if counter already exists
+       if (!moduleCounters.containsKey(moduleName)) {
+           moduleCounters.putIfAbsent(moduleName,
+                new ConcurrentHashMap<String, CounterIndexStore>());
+       }
+       RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
+       if (rci.allLevelsFound) {
+           // counter exists
+           log.info("Counter exists for {}/{} -- resetting counters", moduleName,
+                    counterHierarchy);
+           resetCounterHierarchy(moduleName, counterHierarchy);
+           return new CounterImpl(rci.ctrIds[rci.foundUptoLevel-1]);
+       }
+       // check for validity of counter
+       if (rci.levels.length > MAX_HIERARCHY) {
+           String err = "Registry of counterHierarchy " + counterHierarchy +
+                   " exceeds max hierachy " + MAX_HIERARCHY + ".. aborting";
+           throw new MaxHierarchyRegistered(err);
+       }
+       if (rci.foundUptoLevel < rci.levels.length-1) {
+           String needToRegister = "";
+           for (int i=0; i<=rci.foundUptoLevel; i++) {
+               needToRegister += rci.levels[i];
+           }
+           String err = "Attempting to register hierarchical counterHierarchy " +
+                   counterHierarchy + " but parts of hierarchy missing. " +
+                   "Please register " +  needToRegister + " first";
+           throw new MissingHierarchicalLevel(err);
+       }
+
+       // get a new counter id
+       int counterId = counterIdCounter.getAndIncrement();
+       if (counterId >= MAX_COUNTERS) {
+           throw new MaxCountersRegistered("max counters reached");
+       }
+       // create storage for counter
+       boolean enabled = (counterType == CounterType.ALWAYS_COUNT) ? true : false;
+       CounterInfo ci = new CounterInfo(counterId, enabled, moduleName,
+                                        counterHierarchy, counterDescription,
+                                        counterType, metaData);
+       allCounters[counterId] = new DebugCounterInfo(ci);
+
+       // account for the new counter in the module counter hierarchy
+       addToModuleCounterHierarchy(moduleName, counterId, rci);
+
+       // finally add to active counters
+       if (enabled) {
+           currentCounters.add(counterId);
+       }
+       return new CounterImpl(counterId);
+   }
+
+   private void updateCounter(int counterId, int incr, boolean flushNow) {
+       if (counterId < 0 || counterId >= MAX_COUNTERS) return;
+
+       LocalCounterInfo[] thiscounters =  this.threadlocalCounters.get();
+       if (thiscounters[counterId] == null) {
+           // seeing this counter for the first time in this thread - create local
+           // store by consulting global store
+           DebugCounterInfo dc = allCounters[counterId];
+           if (dc != null) {
+               thiscounters[counterId] = new LocalCounterInfo(dc.cinfo.enabled);
+               if (dc.cinfo.enabled) {
+                   Set<Integer> thisset = this.threadlocalCurrentCounters.get();
+                   thisset.add(counterId);
+               }
+           } else {
+               log.error("updateCounter seen locally for counter {} but no global"
+                          + "storage exists for it yet .. not updating", counterId);
+               return;
+           }
+       }
+
+       // update local store if enabled locally for updating
+       LocalCounterInfo lc = thiscounters[counterId];
+       if (lc.enabled) {
+           lc.cvalue.increment(incr);
+           if (flushNow) {
+               DebugCounterInfo dc = allCounters[counterId];
+               if (dc.cinfo.enabled) {
+                   // globally enabled - flush now
+                   dc.cvalue.addAndGet(lc.cvalue.get());
+                   lc.cvalue.set(0);
+               } else {
+                   // global counter is disabled - don't flush, disable locally
+                   lc.enabled = false;
+                   Set<Integer> thisset = this.threadlocalCurrentCounters.get();
+                   thisset.remove(counterId);
+               }
+           }
+       }
+   }
+
+   @Override
+   public void flushCounters() {
+       LocalCounterInfo[] thiscounters =  this.threadlocalCounters.get();
+       Set<Integer> thisset = this.threadlocalCurrentCounters.get();
+       ArrayList<Integer> temp = new ArrayList<Integer>();
+
+       for (int counterId : thisset) {
+           LocalCounterInfo lc = thiscounters[counterId];
+           if (lc.cvalue.get() > 0) {
+               DebugCounterInfo dc = allCounters[counterId];
+               if (dc.cinfo.enabled) {
+                   // globally enabled - flush now
+                   dc.cvalue.addAndGet(lc.cvalue.get());
+                   lc.cvalue.set(0);
+               } else {
+                   // global counter is disabled - don't flush, disable locally
+                   lc.enabled = false;
+                   temp.add(counterId);
+               }
+           }
+       }
+       for (int cId : temp) {
+           thisset.remove(cId);
+       }
+
+       // At this point it is possible that the thread-local set does not
+       // include a counter that has been enabled and is present in the global set.
+       // We need to sync thread-local currently enabled set of counterIds with
+       // the global set.
+       Sets.SetView<Integer> sv = Sets.difference(currentCounters, thisset);
+       for (int counterId : sv) {
+           if (thiscounters[counterId] != null) {
+               thiscounters[counterId].enabled = true;
+               thisset.add(counterId);
+           }
+       }
+   }
+
+   @Override
+   public void resetCounterHierarchy(String moduleName, String counterHierarchy) {
+       RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
+       if (!rci.allLevelsFound) {
+           String missing = rci.levels[rci.foundUptoLevel];
+           log.error("Cannot reset counter hierarchy - missing counter {}", missing);
+           return;
+       }
+       // reset at this level
+       allCounters[rci.ctrIds[rci.foundUptoLevel-1]].cvalue.set(0);
+       // reset all levels below
+       ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
+       for (int index : resetIds) {
+           allCounters[index].cvalue.set(0);
+       }
+   }
+
+   @Override
+   public void resetAllCounters() {
+       RetCtrInfo rci = new RetCtrInfo();
+       rci.levels = "".split("/");
+       for (String moduleName : moduleCounters.keySet()) {
+           ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
+           for (int index : resetIds) {
+               allCounters[index].cvalue.set(0);
+           }
+       }
+   }
+
+   @Override
+   public void resetAllModuleCounters(String moduleName) {
+       Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
+       RetCtrInfo rci = new RetCtrInfo();
+       rci.levels = "".split("/");
+
+       if (target != null) {
+           ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
+           for (int index : resetIds) {
+               allCounters[index].cvalue.set(0);
+           }
+       } else {
+           if (log.isDebugEnabled())
+               log.debug("No module found with name {}", moduleName);
+       }
+   }
+
+   @Override
+   public void enableCtrOnDemand(String moduleName, String counterHierarchy) {
+       RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
+       if (!rci.allLevelsFound) {
+           String missing = rci.levels[rci.foundUptoLevel];
+           log.error("Cannot enable counter - counter not found {}", missing);
+           return;
+       }
+       // enable specific counter
+       DebugCounterInfo dc = allCounters[rci.ctrIds[rci.foundUptoLevel-1]];
+       dc.cinfo.enabled = true;
+       currentCounters.add(dc.cinfo.counterId);
+   }
+
+   @Override
+   public void disableCtrOnDemand(String moduleName, String counterHierarchy) {
+       RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
+       if (!rci.allLevelsFound) {
+           String missing = rci.levels[rci.foundUptoLevel];
+           log.error("Cannot disable counter - counter not found {}", missing);
+           return;
+       }
+       // disable specific counter
+       DebugCounterInfo dc = allCounters[rci.ctrIds[rci.foundUptoLevel-1]];
+       if (dc.cinfo.ctype == CounterType.COUNT_ON_DEMAND) {
+           dc.cinfo.enabled = false;
+           dc.cvalue.set(0);
+           currentCounters.remove(dc.cinfo.counterId);
+       }
+   }
+
+   @Override
+   public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
+                                                     String counterHierarchy) {
+       RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
+       if (!rci.allLevelsFound) {
+           String missing = rci.levels[rci.foundUptoLevel];
+           log.error("Cannot fetch counter - counter not found {}", missing);
+           return Collections.emptyList();
+       }
+       ArrayList<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
+       // get counter and all below it
+       DebugCounterInfo dc = allCounters[rci.ctrIds[rci.foundUptoLevel-1]];
+       dcilist.add(dc);
+       ArrayList<Integer> belowIds = getHierarchyBelow(moduleName, rci);
+       for (int index : belowIds) {
+           dcilist.add(allCounters[index]);
+       }
+       return dcilist;
+   }
+
+   @Override
+   public List<DebugCounterInfo> getAllCounterValues() {
+       List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
+       RetCtrInfo rci = new RetCtrInfo();
+       rci.levels = "".split("/");
+
+       for (String moduleName : moduleCounters.keySet()) {
+           ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
+           for (int index : resetIds) {
+               dcilist.add(allCounters[index]);
+           }
+       }
+       return dcilist;
+   }
+
+   @Override
+   public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
+       List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>();
+       RetCtrInfo rci = new RetCtrInfo();
+       rci.levels = "".split("/");
+
+       if (moduleCounters.containsKey(moduleName)) {
+           ArrayList<Integer> resetIds = getHierarchyBelow(moduleName, rci);
+           for (int index : resetIds) {
+               dcilist.add(allCounters[index]);
+           }
+       }
+       return dcilist;
+   }
+
+   @Override
+   public boolean containsModuleCounterHierarchy(String moduleName,
+                                                 String counterHierarchy) {
+       if (!moduleCounters.containsKey(moduleName)) return false;
+       RetCtrInfo rci = getCounterId(moduleName, counterHierarchy);
+       return rci.allLevelsFound;
+   }
+
+   @Override
+   public boolean containsModuleName(String moduleName) {
+       return  (moduleCounters.containsKey(moduleName)) ? true : false;
+   }
+
+   @Override
+   public List<String> getModuleList() {
+       List<String> retval = new ArrayList<String>();
+       retval.addAll(moduleCounters.keySet());
+       return retval;
+   }
+
+   @Override
+   public List<String> getModuleCounterList(String moduleName) {
+       if (!moduleCounters.containsKey(moduleName))
+           return Collections.emptyList();
+
+       List<String> retval = new ArrayList<String>();
+       RetCtrInfo rci = new RetCtrInfo();
+       rci.levels = "".split("/");
+
+       ArrayList<Integer> cids = getHierarchyBelow(moduleName, rci);
+       for (int index : cids) {
+           retval.add(allCounters[index].cinfo.counterHierarchy);
+       }
+       return retval;
+   }
+
+   //*******************************
+   //   Internal Methods
+   //*******************************
+
+   protected class RetCtrInfo {
+       boolean allLevelsFound; // counter indices found all the way down the hierarchy
+       boolean hierarchical; // true if counterHierarchy is hierarchical
+       int foundUptoLevel;
+       int[]  ctrIds;
+       String[] levels;
+
+       public RetCtrInfo() {
+           ctrIds = new int[MAX_HIERARCHY];
+           for (int i=0; i<MAX_HIERARCHY; i++) {
+               ctrIds[i] = -1;
+           }
+       }
+
+       @Override
+       public boolean equals(Object oth) {
+           if (!(oth instanceof RetCtrInfo)) return false;
+           RetCtrInfo other = (RetCtrInfo)oth;
+           if (other.allLevelsFound != this.allLevelsFound) return false;
+           if (other.hierarchical != this.hierarchical) return false;
+           if (other.foundUptoLevel != this.foundUptoLevel) return false;
+           if (!Arrays.equals(other.ctrIds, this.ctrIds)) return false;
+           if (!Arrays.equals(other.levels, this.levels)) return false;
+           return true;
+       }
+
+   }
+
+   protected RetCtrInfo getCounterId(String moduleName, String counterHierarchy) {
+       RetCtrInfo rci = new RetCtrInfo();
+       Map<String, CounterIndexStore> templevel = moduleCounters.get(moduleName);
+       rci.levels = counterHierarchy.split("/");
+       if (rci.levels.length > 1) rci.hierarchical = true;
+       if (templevel == null) {
+           log.error("moduleName {} does not exist in debugCounters", moduleName);
+           return rci;
+       }
+
+       /*
+       if (rci.levels.length > MAX_HIERARCHY) {
+           // chop off all array elems greater that MAX_HIERARCHY
+           String[] temp = new String[MAX_HIERARCHY];
+           System.arraycopy(rci.levels, 0, temp, 0, MAX_HIERARCHY);
+           rci.levels = temp;
+       }
+       */
+       for (int i=0; i<rci.levels.length; i++) {
+           if (templevel != null) {
+               CounterIndexStore cis = templevel.get(rci.levels[i]) ;
+               if (cis == null) {
+                   // could not find counterHierarchy part at this level
+                   break;
+               } else {
+                   rci.ctrIds[i] = cis.index;
+                   templevel = cis.nextLevel;
+                   rci.foundUptoLevel++;
+                   if (i == rci.levels.length-1) {
+                       rci.allLevelsFound = true;
+                   }
+               }
+           } else {
+               // there are no more levels, which means that some part of the
+               // counterHierarchy has no corresponding map
+               break;
+           }
+       }
+       return rci;
+   }
+
+   protected void addToModuleCounterHierarchy(String moduleName, int counterId,
+                                            RetCtrInfo rci) {
+       Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
+       if (target == null) return;
+       CounterIndexStore cis = null;
+
+       for (int i=0; i<rci.foundUptoLevel; i++) {
+           cis = target.get(rci.levels[i]);
+           target = cis.nextLevel;
+       }
+       if (cis != null) {
+           if (cis.nextLevel == null)
+               cis.nextLevel = new ConcurrentHashMap<String, CounterIndexStore>();
+           cis.nextLevel.put(rci.levels[rci.foundUptoLevel],
+                             new CounterIndexStore(counterId, null));
+       } else {
+           target.put(rci.levels[rci.foundUptoLevel],
+                      new CounterIndexStore(counterId, null));
+       }
+   }
+
+   // given a partial hierarchical counter, return the rest of the hierarchy
+   protected ArrayList<Integer> getHierarchyBelow(String moduleName, RetCtrInfo rci) {
+       Map<String, CounterIndexStore> target = moduleCounters.get(moduleName);
+       CounterIndexStore cis = null;
+       ArrayList<Integer> retval = new ArrayList<Integer>();
+       if (target == null) return retval;
+
+       // get to the level given
+       for (int i=0; i<rci.foundUptoLevel; i++) {
+           cis = target.get(rci.levels[i]);
+           target = cis.nextLevel;
+       }
+
+       if (target == null || rci.foundUptoLevel == MAX_HIERARCHY) {
+           // no more levels
+           return retval;
+       } else {
+           // recursively get all ids
+           getIdsAtLevel(target, retval, rci.foundUptoLevel+1);
+       }
+
+       return retval;
+   }
+
+   protected void getIdsAtLevel(Map<String, CounterIndexStore> hcy,
+                                ArrayList<Integer> retval, int level) {
+       if (level > MAX_HIERARCHY) return;
+       if (hcy == null || retval == null) return;
+
+       // Can return the counter names as well but for now ids are enough.
+       for (CounterIndexStore cistemp : hcy.values()) {
+           retval.add(cistemp.index); // value at this level
+           if (cistemp.nextLevel != null) {
+               getIdsAtLevel(cistemp.nextLevel, retval, level+1);
+           }
+       }
+   }
+
+   protected void printAllCounterIds() {
+       log.info("<moduleCounterHierarchy>");
+       Set<String> keys = moduleCounters.keySet();
+       for (String key : keys) {
+           log.info("ModuleName: {}", key);
+           Map<String, CounterIndexStore> lev1 = moduleCounters.get(key);
+           for (String key1 : lev1.keySet()) {
+               CounterIndexStore cis1 = lev1.get(key1);
+               log.info(" L1 {}:{}", key1, new Object[] {cis1.index, cis1.nextLevel});
+               if (cis1.nextLevel != null) {
+                   Map<String, CounterIndexStore> lev2 = cis1.nextLevel;
+                   for (String key2 : lev2.keySet()) {
+                       CounterIndexStore cis2 = lev2.get(key2);
+                       log.info("  L2 {}:{}", key2, new Object[] {cis2.index,
+                                                                  cis2.nextLevel});
+                       if (cis2.nextLevel != null) {
+                           Map<String, CounterIndexStore> lev3 = cis2.nextLevel;
+                           for (String key3 : lev3.keySet()) {
+                               CounterIndexStore cis3 = lev3.get(key3);
+                               log.info("   L3 {}:{}", key3, new Object[] {cis3.index,
+                                                                          cis3.nextLevel});
+                           }
+                       }
+                   }
+               }
+           }
+       }
+       log.info("<\\moduleCounterHierarchy>");
+   }
+
+   //*******************************
+   //   IFloodlightModule
+   //*******************************
+
+   @Override
+   public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+       Collection<Class<? extends IFloodlightService>> l =
+               new ArrayList<Class<? extends IFloodlightService>>();
+       l.add(IDebugCounterService.class);
+       return l;
+   }
+
+   @Override
+   public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+       Map<Class<? extends IFloodlightService>, IFloodlightService> m =
+               new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
+       m.put(IDebugCounterService.class, this);
+       return m;
+   }
+
+   @Override
+   public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+       ArrayList<Class<? extends IFloodlightService>> deps =
+               new ArrayList<Class<? extends IFloodlightService>>();
+       deps.add(IRestApiService.class);
+       return deps;
+   }
+
+   @Override
+   public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+
+   }
+
+   @Override
+   public void startUp(FloodlightModuleContext context) {
+       IRestApiService restService =
+               context.getServiceImpl(IRestApiService.class);
+       restService.addRestletRoutable(new DebugCounterRoutable());
+   }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterImpl.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterImpl.java
deleted file mode 100644
index c0aa316d953dc90a65c565f1d34719c8d19ddd5f..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterImpl.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package net.floodlightcontroller.debugcounter;
-
-import java.util.Collection;
-import java.util.concurrent.atomic.AtomicLong;
-
-import javax.annotation.Nonnull;
-
-import net.floodlightcontroller.debugcounter.IDebugCounterService.MetaData;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-
-
-class DebugCounterImpl implements IDebugCounter {
-    private final String moduleName;
-    private final String counterHierarchy;
-    private final String description;
-    private final ImmutableSet<IDebugCounterService.MetaData> metaData;
-
-    private final AtomicLong value = new AtomicLong();
-
-
-    DebugCounterImpl(@Nonnull String moduleName,
-                     @Nonnull String counterHierarchy,
-                     @Nonnull String description,
-                     @Nonnull Collection<MetaData> metaData) {
-        this.moduleName = moduleName;
-        this.counterHierarchy = counterHierarchy;
-        this.description = description;
-        this.metaData = Sets.immutableEnumSet(metaData);
-    }
-
-    @Nonnull
-    String getModuleName() {
-        return moduleName;
-    }
-
-
-    @Nonnull
-    String getCounterHierarchy() {
-        return counterHierarchy;
-    }
-
-
-    @Nonnull
-    String getDescription() {
-        return description;
-    }
-
-    @Nonnull
-    ImmutableSet<IDebugCounterService.MetaData> getMetaData() {
-        return metaData;
-    }
-
-    public void reset() {
-        value.set(0);
-    }
-
-    @Override
-    public void increment() {
-        value.incrementAndGet();
-    }
-
-    @Override
-    public void add(long increment) {
-        if (increment < 0) {
-            throw new IllegalArgumentException("increment must be > 0. Was "
-                    + increment);
-        }
-        value.addAndGet(increment);
-    }
-
-    @Override
-    public long getCounterValue() {
-        return value.get();
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime
-                 * result
-                 + ((counterHierarchy == null) ? 0
-                                              : counterHierarchy.hashCode());
-        result = prime * result
-                 + ((description == null) ? 0 : description.hashCode());
-        result = prime * result
-                 + ((metaData == null) ? 0 : metaData.hashCode());
-        result = prime * result
-                 + ((moduleName == null) ? 0 : moduleName.hashCode());
-        result = prime * result + ((value == null) ? 0 : value.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (getClass() != obj.getClass()) return false;
-        DebugCounterImpl other = (DebugCounterImpl) obj;
-        if (counterHierarchy == null) {
-            if (other.counterHierarchy != null) return false;
-        } else if (!counterHierarchy.equals(other.counterHierarchy))
-                                                                    return false;
-        if (description == null) {
-            if (other.description != null) return false;
-        } else if (!description.equals(other.description)) return false;
-        if (metaData == null) {
-            if (other.metaData != null) return false;
-        } else if (!metaData.equals(other.metaData)) return false;
-        if (moduleName == null) {
-            if (other.moduleName != null) return false;
-        } else if (!moduleName.equals(other.moduleName)) return false;
-        if (value == null) {
-            if (other.value != null) return false;
-        } else if (value.get() != other.value.get()) return false;
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("[");
-        builder.append(moduleName);
-        builder.append(" ");
-        builder.append(counterHierarchy);
-        builder.append(", description=");
-        builder.append(description);
-        builder.append(", metaData=");
-        builder.append(metaData);
-        builder.append(", value=");
-        builder.append(value);
-        builder.append("]");
-        return builder.toString();
-    }
-
-
-
-
-}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResource.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResource.java
deleted file mode 100644
index 941802c31d4bd2b536002f0a094b6b781af78e32..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResource.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package net.floodlightcontroller.debugcounter;
-
-import java.util.Set;
-
-import javax.annotation.concurrent.Immutable;
-
-import net.floodlightcontroller.debugcounter.IDebugCounterService.MetaData;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-
-/**
- * Resource class for DebugCounter
- * Serves the REST api with dynamic data
- */
-@Immutable
-public class DebugCounterResource {
-
-    public static final String MODULE_NAME_PREDICATE = "modulename";
-    public static final String HIERARCHY_PREDICATE = "hierarchy";
-    private static final Joiner joiner = Joiner.on(", ");
-
-
-    private final Long counterValue;
-    private final String counterDesc;
-    private final String counterHierarchy;
-    private final String moduleName;
-    private final ImmutableSet<MetaData> metadata;
-    private final String metadataString;
-
-    public DebugCounterResource(DebugCounterImpl counter) {
-        this.moduleName = counter.getModuleName();
-        this.counterHierarchy = counter.getCounterHierarchy();
-        this.counterDesc = counter.getDescription();
-        this.metadata = counter.getMetaData();
-        this.counterValue = counter.getCounterValue();
-        this.metadataString = joiner.join(metadata);
-    }
-
-    public Long getCounterValue() {
-        return counterValue;
-    }
-
-    public String getCounterDesc() {
-        return counterDesc;
-    }
-
-    public String getCounterHierarchy() {
-        return counterHierarchy;
-    }
-
-    public String getModuleName() {
-        return moduleName;
-    }
-
-    public Set<MetaData> getMetadata() {
-        return metadata;
-    }
-
-    public String getMetadataString() {
-        return metadataString;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result
-                 + ((counterDesc == null) ? 0 : counterDesc.hashCode());
-        result = prime
-                 * result
-                 + ((counterHierarchy == null) ? 0
-                                              : counterHierarchy.hashCode());
-        result = prime * result
-                 + ((counterValue == null) ? 0 : counterValue.hashCode());
-        result = prime * result
-                 + ((metadata == null) ? 0 : metadata.hashCode());
-        result = prime
-                 * result
-                 + ((metadataString == null) ? 0 : metadataString.hashCode());
-        result = prime * result
-                 + ((moduleName == null) ? 0 : moduleName.hashCode());
-        return result;
-    }
-
-    /**
-     * Compare all fields, not only the "key" fields
-     */
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (getClass() != obj.getClass()) return false;
-        DebugCounterResource other = (DebugCounterResource) obj;
-        if (counterDesc == null) {
-            if (other.counterDesc != null) return false;
-        } else if (!counterDesc.equals(other.counterDesc)) return false;
-        if (counterHierarchy == null) {
-            if (other.counterHierarchy != null) return false;
-        } else if (!counterHierarchy.equals(other.counterHierarchy))
-                                                                    return false;
-        if (counterValue == null) {
-            if (other.counterValue != null) return false;
-        } else if (!counterValue.equals(other.counterValue)) return false;
-        if (metadata == null) {
-            if (other.metadata != null) return false;
-        } else if (!metadata.equals(other.metadata)) return false;
-        if (metadataString == null) {
-            if (other.metadataString != null) return false;
-        } else if (!metadataString.equals(other.metadataString))
-                                                                return false;
-        if (moduleName == null) {
-            if (other.moduleName != null) return false;
-        } else if (!moduleName.equals(other.moduleName)) return false;
-        return true;
-    }
-
-
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResourceBase.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResourceBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..9edd47473a75564334c217b240002612d31e6219
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResourceBase.java
@@ -0,0 +1,16 @@
+package net.floodlightcontroller.debugcounter;
+
+import org.restlet.resource.ResourceException;
+import org.restlet.resource.ServerResource;
+
+public class DebugCounterResourceBase extends ServerResource {
+
+    protected IDebugCounterService debugCounter;
+
+    @Override
+    protected void doInit() throws ResourceException {
+        super.doInit();
+        debugCounter = (IDebugCounterService)getContext().getAttributes().
+                get(IDebugCounterService.class.getCanonicalName());
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterServiceImpl.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterServiceImpl.java
deleted file mode 100644
index 2e2fe499f8ff592cfc9837091f0cd22fbe6be4b2..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterServiceImpl.java
+++ /dev/null
@@ -1,251 +0,0 @@
-package net.floodlightcontroller.debugcounter;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import javax.annotation.Nonnull;
-import javax.annotation.concurrent.GuardedBy;
-
-import org.projectfloodlight.core.IShutdownListener;
-import org.projectfloodlight.core.IShutdownService;
-import net.floodlightcontroller.core.module.FloodlightModuleContext;
-import net.floodlightcontroller.core.module.IFloodlightModule;
-import net.floodlightcontroller.core.module.IFloodlightService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DebugCounterServiceImpl implements IFloodlightModule, IDebugCounterService {
-    protected static final Logger logger =
-            LoggerFactory.getLogger(DebugCounterServiceImpl.class);
-
-    /**
-     * The tree of counters.
-     */
-    private final CounterNode root = CounterNode.newTree();
-
-    /**
-     * protects the counter hierarchy tree. The writeLock is required to
-     * change to hierarchy, i.e., adding nodes. The readLock is required
-     * to query the counters or to reset them.
-     */
-    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
-    static void verifyStringSanity(String str, String name) {
-        if (str == null) {
-            if (name == null) {
-                throw new NullPointerException();
-            } else {
-                throw new NullPointerException(name + " must not be null");
-            }
-        }
-        if (str.isEmpty()) {
-            if (name == null) {
-                throw new IllegalArgumentException();
-            } else {
-                throw new IllegalArgumentException(name + " must not be empty");
-            }
-        }
-    }
-
-    static void verifyModuleNameSanity(String moduleName) {
-        verifyStringSanity(moduleName, "moduleName");
-        if (moduleName.contains("/")) {
-            throw new IllegalArgumentException("moduleName must not contain /");
-        }
-    }
-
-    @Override
-    public boolean registerModule(String moduleName) {
-        verifyModuleNameSanity(moduleName);
-        lock.writeLock().lock();
-        try {
-            return root.addModule(moduleName);
-        } finally {
-            lock.writeLock().unlock();
-        }
-    }
-
-    @Override
-    public IDebugCounter registerCounter(@Nonnull String moduleName,
-                                         @Nonnull String counterHierarchy,
-                                         @Nonnull String counterDescription,
-                                         @Nonnull MetaData... metaData) {
-        verifyModuleNameSanity(moduleName);
-        verifyStringSanity(counterHierarchy, "counterHierarchy");
-        if (counterDescription == null) {
-            throw new Exception("counterDescription must not be null");
-        }
-        if (metaData == null) {
-            // somebody passing in a null array. sigh.
-            throw new NullPointerException("metaData must not be null");
-        }
-        DebugCounterImpl counter =
-                new DebugCounterImpl(moduleName, counterHierarchy,
-                                     counterDescription,
-                                     Arrays.asList(metaData));
-        lock.writeLock().lock();
-        try {
-            DebugCounterImpl oldCounter = root.addCounter(counter);
-            if (oldCounter != null && logger.isDebugEnabled()) {
-                logger.debug("Counter {} {} already registered. Resetting hierarchy",
-                          moduleName, counterHierarchy);
-            }
-            return oldCounter;
-        } finally {
-            lock.writeLock().unlock();
-        }
-    }
-
-    @GuardedBy("lock.readLock")
-    private boolean resetInternal(List<String> hierarchyElements) {
-        CounterNode node = root.lookup(hierarchyElements);
-        if (node == null) {
-            return false;
-        }
-        node.resetHierarchy();
-        return true;
-    }
-
-    @Override
-    public boolean resetCounterHierarchy(String moduleName,
-                                         String counterHierarchy) {
-        verifyModuleNameSanity(moduleName);
-        verifyStringSanity(counterHierarchy, "counterHierarchy");
-        lock.readLock().lock();
-        try {
-            return resetInternal(CounterNode.getHierarchyElements(moduleName, counterHierarchy));
-        } finally {
-            lock.readLock().unlock();
-        }
-    }
-
-    @Override
-    public void resetAllCounters() {
-        lock.readLock().lock();
-        try {
-            root.resetHierarchy();
-        } finally {
-            lock.readLock().unlock();
-        }
-    }
-
-
-    @Override
-    public boolean resetAllModuleCounters(String moduleName) {
-        verifyModuleNameSanity(moduleName);
-        lock.readLock().lock();
-        try {
-            return resetInternal(Collections.singletonList(moduleName));
-        } finally {
-            lock.readLock().unlock();
-        }
-    }
-
-    @GuardedBy("lock.readLock")
-    private List<DebugCounterResource> getCountersFromNode(CounterNode node) {
-        if (node == null) {
-            return Collections.emptyList();
-        }
-        List<DebugCounterResource> ret = new ArrayList<>();
-        for (DebugCounterImpl counter: node.getCountersInHierarchy()) {
-            ret.add(new DebugCounterResource(counter));
-        }
-        return ret;
-    }
-
-    @Override
-    public List<DebugCounterResource>
-    getCounterHierarchy(String moduleName, String counterHierarchy) {
-        verifyModuleNameSanity(moduleName);
-        verifyStringSanity(counterHierarchy, "counterHierarchy");
-        List<String> hierarchyElements =
-                CounterNode.getHierarchyElements(moduleName, counterHierarchy);
-        lock.readLock().lock();
-        try {
-            return getCountersFromNode(root.lookup(hierarchyElements));
-        } finally {
-            lock.readLock().unlock();
-        }
-    }
-
-    @Override
-    public List<DebugCounterResource> getAllCounterValues() {
-        lock.readLock().lock();
-        try {
-            return getCountersFromNode(root);
-        } finally {
-            lock.readLock().unlock();
-        }
-    }
-
-    @Override
-    public List<DebugCounterResource> getModuleCounterValues(String moduleName) {
-        verifyModuleNameSanity(moduleName);
-        List<String> hierarchyElements = Collections.singletonList(moduleName);
-        lock.readLock().lock();
-        try {
-            return getCountersFromNode(root.lookup(hierarchyElements));
-        } finally {
-            lock.readLock().unlock();
-        }
-    }
-
-    private class ShutdownListenenerDelegate implements IShutdownListener {
-        @Override
-        public void floodlightIsShuttingDown() {
-            for (DebugCounterResource counter: getAllCounterValues()) {
-                logger.info("Module {} counterHierarchy {} value {}",
-                            counter.getModuleName(),
-                            counter.getCounterHierarchy(),
-                            counter.getCounterValue());
-            }
-        }
-    }
-
-
-   //*******************************
-   //   IFloodlightModule
-   //*******************************
-
-   @Override
-   public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-       Collection<Class<? extends IFloodlightService>> l =
-               new ArrayList<Class<? extends IFloodlightService>>();
-       l.add(IDebugCounterService.class);
-       return l;
-   }
-
-   @Override
-   public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
-       Map<Class<? extends IFloodlightService>, IFloodlightService> m =
-               new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
-       m.put(IDebugCounterService.class, this);
-       return m;
-   }
-
-   @Override
-   public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
-       ArrayList<Class<? extends IFloodlightService>> deps =
-               new ArrayList<Class<? extends IFloodlightService>>();
-       deps.add(IShutdownService.class);
-       return deps;
-   }
-
-   @Override
-   public void init(FloodlightModuleContext context) {
-   }
-
-   @Override
-   public void startUp(FloodlightModuleContext context) {
-       IShutdownService shutdownService =
-               context.getServiceImpl(IShutdownService.class);
-       shutdownService.registerShutdownListener(new ShutdownListenenerDelegate());
-   }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounter.java b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounter.java
new file mode 100644
index 0000000000000000000000000000000000000000..dbde1854e9c6f7707e983eedf5bfe6fef299d7ec
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounter.java
@@ -0,0 +1,38 @@
+package net.floodlightcontroller.debugcounter;
+
+public interface IDebugCounter {
+    /**
+     * Increments the counter by 1 thread-locally, and immediately flushes to
+     * the global counter storage. This method should be used for counters that
+     * are updated outside the OF message processing pipeline.
+     */
+    void updateCounterWithFlush();
+
+    /**
+     * Increments the counter by 1 thread-locally. Flushing to the global
+     * counter storage is delayed (happens with flushCounters() in IDebugCounterService),
+     * resulting in higher performance. This method should be used for counters
+     * updated in the OF message processing pipeline.
+     */
+    void updateCounterNoFlush();
+
+    /**
+     * Increments the counter thread-locally by the 'incr' specified, and immediately
+     * flushes to the global counter storage. This method should be used for counters
+     * that are updated outside the OF message processing pipeline.
+     */
+    void updateCounterWithFlush(int incr);
+
+    /**
+     * Increments the counter thread-locally by the 'incr' specified. Flushing to the global
+     * counter storage is delayed (happens with flushCounters() in IDebugCounterService),
+     * resulting in higher performance. This method should be used for counters
+     * updated in the OF message processing pipeline.
+     */
+    void updateCounterNoFlush(int incr);
+
+    /**
+     * Retrieve the value of the counter from the global counter store
+     */
+    long getCounterValue();
+}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java
new file mode 100644
index 0000000000000000000000000000000000000000..538e60dad148c600e3802b53271ed6e111d8f6b9
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java
@@ -0,0 +1,259 @@
+package net.floodlightcontroller.debugcounter;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.debugcounter.DebugCounter.DebugCounterInfo;
+
+import java.util.List;
+
+public interface IDebugCounterService extends IFloodlightService {
+
+    /**
+     * Different counter types. Counters that are meant to be counted-on-demand
+     * need to be separately enabled/disabled.
+     */
+    public enum CounterType {
+        ALWAYS_COUNT,
+        COUNT_ON_DEMAND
+    }
+
+    /**
+     * Debug Counter Qualifiers
+     */
+    public static final String CTR_MDATA_WARN = "warn";
+    public static final String CTR_MDATA_ERROR = "error";
+
+    /**
+     *  A limit on the maximum number of counters that can be created
+     */
+    public static final int MAX_COUNTERS = 5000;
+
+    /**
+     * Exception thrown when MAX_COUNTERS have been registered
+     */
+    public class MaxCountersRegistered extends CounterException {
+        private static final long serialVersionUID = 3173747663719376745L;
+        String errormsg;
+        public MaxCountersRegistered(String errormsg) {
+            this.errormsg = errormsg;
+        }
+        @Override
+        public String getMessage() {
+            return this.errormsg;
+        }
+    }
+    /**
+     * Exception thrown when MAX_HIERARCHY has been reached
+     */
+    public class MaxHierarchyRegistered extends CounterException {
+        private static final long serialVersionUID = 967431358683523871L;
+        String errormsg;
+        public MaxHierarchyRegistered(String errormsg) {
+            this.errormsg = errormsg;
+        }
+        @Override
+        public String getMessage() {
+            return this.errormsg;
+        }
+    }
+    /**
+     * Exception thrown when attempting to register a hierarchical counter
+     * where higher levels of the hierarchy have not been pre-registered
+     */
+    public class MissingHierarchicalLevel extends CounterException {
+        private static final long serialVersionUID = 517315311533995739L;
+        String errormsg;
+        public MissingHierarchicalLevel(String errormsg) {
+            this.errormsg = errormsg;
+        }
+        @Override
+        public String getMessage() {
+            return this.errormsg;
+        }
+    }
+
+    public class CounterException extends Exception {
+        private static final long serialVersionUID = 2219781500857866035L;
+    }
+
+    /**
+     *  maximum levels of hierarchy
+     *  Example of moduleName/counterHierarchy:
+     *           switch/00:00:00:00:01:02:03:04/pktin/drops where
+     *           moduleName ==> "switch"  and
+     *           counterHierarchy of 3 ==> "00:00:00:00:01:02:03:04/pktin/drops"
+     */
+    public static final int MAX_HIERARCHY = 3;
+
+    /**
+     * All modules that wish to have the DebugCounterService count for them, must
+     * register their counters by making this call (typically from that module's
+     * 'startUp' method). The counter can then be updated, displayed, reset etc.
+     * using the registered moduleName and counterHierarchy.
+     *
+     * @param moduleName           the name of the module which is registering the
+     *                             counter eg. linkdiscovery or controller or switch
+     * @param counterHierarchy     the hierarchical counter name specifying all
+     *                             the hierarchical levels that come above it.
+     *                             For example: to register a drop counter for
+     *                             packet-ins from a switch, the counterHierarchy
+     *                             can be "00:00:00:00:01:02:03:04/pktin/drops"
+     *                             It is necessary that counters in hierarchical levels
+     *                             above have already been pre-registered - in this
+     *                             example: "00:00:00:00:01:02:03:04/pktin" and
+     *                             "00:00:00:00:01:02:03:04"
+     * @param counterDescription   a descriptive string that gives more information
+     *                             of what the counter is measuring. For example,
+     *                             "Measures the number of incoming packets seen by
+     *                             this module".
+     * @param counterType          One of CounterType. On-demand counter types
+     *                             need to be explicitly enabled/disabled using other
+     *                             methods in this API -- i.e. registering them is
+     *                             not enough to start counting.
+     * @param metaData             variable arguments that qualify a counter
+     *                             eg. warn, error etc.
+     * @return                     IDebugCounter with update methods that can be
+     *                             used to update a counter.
+     * @throws MaxCountersRegistered
+     * @throws MaxHierarchyRegistered
+     * @throws MissingHierarchicalLevel
+     */
+    public IDebugCounter registerCounter(String moduleName, String counterHierarchy,
+                             String counterDescription, CounterType counterType,
+                             String... metaData)
+                throws MaxCountersRegistered, MaxHierarchyRegistered,
+                       MissingHierarchicalLevel;
+
+    /**
+     * Flush all thread-local counter values (from the current thread)
+     * to the global counter store. This method is not intended for use by any
+     * module. It's typical usage is from floodlight core and it is meant
+     * to flush those counters that are updated in the packet-processing pipeline,
+     * typically with the 'updateCounterNoFlush" methods in IDebugCounter.
+     */
+    public void flushCounters();
+
+    /**
+     * Resets the value of counters in the hierarchy to zero. Note that the reset
+     * applies to the level of counter hierarchy specified AND ALL LEVELS BELOW it
+     * in the hierarchy.
+     * For example: If a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops"
+     *              specifying a reset hierarchy: "00:00:00:00:01:02:03:04"
+     *              will reset all counters for the switch dpid specified;
+     *              while specifying a reset hierarchy: ""00:00:00:00:01:02:03:04/pktin"
+     *              will reset the pktin counter and all levels below it (like drops)
+     *              for the switch dpid specified.
+     */
+    void resetCounterHierarchy(String moduleName, String counterHierarchy);
+
+    /**
+     * Resets the values of all counters in the system.
+     */
+    public void resetAllCounters();
+
+    /**
+     * Resets the values of all counters belonging
+     * to a module with the given 'moduleName'.
+     */
+    public void resetAllModuleCounters(String moduleName);
+
+    /**
+     * This method applies only to CounterType.COUNT_ON_DEMAND. It is used to
+     * enable counting on the counter. Note that this step is necessary to start
+     * counting for these counter types - merely registering the counter is not
+     * enough (as is the case for CounterType.ALWAYS_COUNT). Newly
+     * enabled counters start from an initial value of zero.
+     *
+     * Enabling a counter in a counterHierarchy enables only THAT counter. It
+     * does not enable any other part of the counterHierarchy. For example, if
+     * a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", where the
+     * 'pktin' and 'drops' counters are CounterType.COUNT_ON_DEMAND, then enabling
+     * the 'pktin' counter by specifying the counterHierarchy as
+     * "00:00:00:00:01:02:03:04/pktin" does NOT enable the 'drops' counter.
+     */
+    public void enableCtrOnDemand(String moduleName, String counterHierarchy);
+
+    /**
+     * This method applies only to CounterType.COUNT_ON_DEMAND. It is used to
+     * enable counting on the counter. Note that disabling a counter results in a loss
+     * of the counter value. When re-enabled the counter will restart from zero.
+     *
+     * Disabling a counter in a counterHierarchy disables only THAT counter. It
+     * does not disable any other part of the counterHierarchy. For example, if
+     * a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", where the
+     * 'pktin' and 'drops' counters are CounterType.COUNT_ON_DEMAND, then disabling
+     * the 'pktin' counter by specifying the counterHierarchy as
+     * "00:00:00:00:01:02:03:04/pktin" does NOT disable the 'drops' counter.
+     */
+    public void disableCtrOnDemand(String moduleName, String counterHierarchy);
+
+    /**
+     * Get counter value and associated information for the specified counterHierarchy.
+     * Note that information on the level of counter hierarchy specified
+     * AND ALL LEVELS BELOW it in the hierarchy will be returned.
+     *
+     * For example,
+     * if a hierarchy exists like "00:00:00:00:01:02:03:04/pktin/drops", then
+     * specifying a counterHierarchy of "00:00:00:00:01:02:03:04/pktin" in the
+     * get call will return information on the 'pktin' as well as the 'drops'
+     * counters for the switch dpid specified.
+     *
+     * @return A list of DebugCounterInfo or an empty list if the counter
+     *         could not be found
+     */
+    public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
+                                                      String counterHierarchy);
+
+    /**
+     * Get counter values and associated information for all counters in the
+     * system
+     *
+     * @return the list of values/info or an empty list
+     */
+    public  List<DebugCounterInfo> getAllCounterValues();
+
+    /**
+     * Get counter values and associated information for all counters associated
+     * with a module.
+     *
+     * @param moduleName
+     * @return the list of values/info or an empty list
+     */
+    public  List<DebugCounterInfo> getModuleCounterValues(String moduleName);
+
+    /**
+     * Convenience method to figure out if the the given 'counterHierarchy' corresponds
+     * to a registered counterHierarchy for 'moduleName'. Note that the counter may or
+     * may not be enabled for counting, but if it is registered the method will
+     * return true.
+     *
+     * @param param
+     * @return false if moduleCounterHierarchy is not a registered counter
+     */
+    public boolean containsModuleCounterHierarchy(String moduleName,
+                                                  String counterHierarchy);
+
+    /**
+     * Convenience method to figure out if the the given 'moduleName' corresponds
+     * to a registered moduleName or not. Note that the module may or may not have
+     * a counter enabled for counting, but if it is registered the method will
+     * return true.
+     *
+     * @param param
+     * @return false if moduleName is not a registered counter
+     */
+    public boolean containsModuleName(String moduleName);
+
+    /**
+     * Returns a list of moduleNames registered for debug counters or an empty
+     * list if no counters have been registered in the system
+     */
+    public List<String> getModuleList();
+
+    /**
+     * Returns a list of all counters registered for a specific moduleName
+     * or a empty list
+     */
+    public List<String> getModuleCounterList(String moduleName);
+
+
+}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java b/src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java
deleted file mode 100644
index 3540519639911602788f965e52d2793f27d0f737..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package net.floodlightcontroller.debugcounter;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.projectfloodlight.core.module.FloodlightModuleContext;
-import org.projectfloodlight.core.module.FloodlightModuleException;
-import org.projectfloodlight.core.module.IFloodlightModule;
-import org.projectfloodlight.core.module.IFloodlightService;
-
-public class MockDebugCounterService implements IFloodlightModule, IDebugCounterService {
-
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> services =
-                new ArrayList<Class<? extends IFloodlightService>>(1);
-        services.add(IDebugCounterService.class);
-        return services;
-    }
-
-    @Override
-    public Map<Class<? extends IFloodlightService>, IFloodlightService>
-            getServiceImpls() {
-        Map<Class<? extends IFloodlightService>,
-            IFloodlightService> m =
-                new HashMap<Class<? extends IFloodlightService>,
-                    IFloodlightService>();
-        m.put(IDebugCounterService.class, this);
-        return m;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleDependencies() {
-        return null;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-
-    }
-
-    @Override
-    public boolean registerModule(String moduleName) {
-        return true;
-    }
-
-    @Override
-    public IDebugCounter registerCounter(String moduleName,
-                                         String counterHierarchy,
-                                         String counterDescription,
-                                         MetaData... metaData) {
-        return new MockCounterImpl();
-    }
-
-    @Override
-    public boolean
-    resetCounterHierarchy(String moduleName, String counterHierarchy) {
-        return true;
-    }
-
-    @Override
-    public void resetAllCounters() {
-    }
-
-    @Override
-    public boolean resetAllModuleCounters(String moduleName) {
-        return true;
-    }
-
-    @Override
-    public List<DebugCounterResource>
-    getCounterHierarchy(String moduleName, String counterHierarchy) {
-        return Collections.emptyList();
-    }
-
-    @Override
-    public List<DebugCounterResource> getAllCounterValues() {
-        return Collections.emptyList();
-    }
-
-    @Override
-    public List<DebugCounterResource>
-    getModuleCounterValues(String moduleName) {
-        return Collections.emptyList();
-    }
-
-    public static class MockCounterImpl implements IDebugCounter {
-        @Override
-        public void increment() {
-        }
-
-        @Override
-        public void add(long incr) {
-        }
-
-        @Override
-        public long getCounterValue() {
-            return -1;
-        }
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java b/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java
new file mode 100644
index 0000000000000000000000000000000000000000..5dc7b319219de1acb202ffdf3df1b347127bb10c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java
@@ -0,0 +1,162 @@
+package net.floodlightcontroller.debugcounter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.debugcounter.DebugCounter.DebugCounterInfo;
+
+public class NullDebugCounter implements IFloodlightModule, IDebugCounterService {
+
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> services =
+                new ArrayList<Class<? extends IFloodlightService>>(1);
+        services.add(IDebugCounterService.class);
+        return services;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService>
+            getServiceImpls() {
+        Map<Class<? extends IFloodlightService>,
+            IFloodlightService> m =
+                new HashMap<Class<? extends IFloodlightService>,
+                    IFloodlightService>();
+        m.put(IDebugCounterService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleDependencies() {
+        return null;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context) {
+
+    }
+
+
+    @Override
+    public void flushCounters() {
+
+    }
+
+    @Override
+    public void resetAllCounters() {
+
+    }
+
+    @Override
+    public void resetAllModuleCounters(String moduleName) {
+
+    }
+
+
+    @Override
+    public void resetCounterHierarchy(String moduleName, String counterHierarchy) {
+
+    }
+
+    @Override
+    public void enableCtrOnDemand(String moduleName, String counterHierarchy) {
+
+    }
+
+    @Override
+    public void disableCtrOnDemand(String moduleName, String counterHierarchy) {
+
+    }
+
+    @Override
+    public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
+                                                      String counterHierarchy) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<DebugCounterInfo> getAllCounterValues() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean containsModuleCounterHierarchy(String moduleName,
+                                             String counterHierarchy) {
+        return false;
+    }
+
+    @Override
+    public boolean containsModuleName(String moduleName) {
+        return false;
+    }
+
+    @Override
+    public
+            IDebugCounter
+            registerCounter(String moduleName, String counterHierarchy,
+                            String counterDescription,
+                            CounterType counterType, String... metaData)
+                                 throws MaxCountersRegistered {
+        return new NullCounterImpl();
+    }
+
+    @Override
+    public List<String> getModuleList() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<String> getModuleCounterList(String moduleName) {
+        return Collections.emptyList();
+    }
+
+    public class NullCounterImpl implements IDebugCounter {
+
+        @Override
+        public void updateCounterWithFlush() {
+
+        }
+
+        @Override
+        public void updateCounterNoFlush() {
+
+        }
+
+        @Override
+        public void updateCounterWithFlush(int incr) {
+        }
+
+        @Override
+        public void updateCounterNoFlush(int incr) {
+
+        }
+
+        @Override
+        public long getCounterValue() {
+            return -1;
+        }
+
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java
deleted file mode 100644
index 7e71d5490faacbd4710d4d9b8411fedc9bc5c9eb..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package net.floodlightcontroller.debugevent;
-
-import java.util.List;
-
-import javax.annotation.concurrent.Immutable;
-
-import org.projectfloodlight.db.data.annotation.DBProperty;
-import org.projectfloodlight.debugevent.DebugEventService.EventInfo;
-import org.projectfloodlight.debugevent.IDebugEventService.EventType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ComparisonChain;
-import com.google.common.collect.ImmutableList;
-
-/**
- * All the Immutable Resource classes for REST API.
- */
-@Immutable
-public class DebugEventResource {
-
-    protected static final Logger logger = LoggerFactory.getLogger(DebugEventResource.class);
-    public static final String MODULE_NAME_PREDICATE = "module-name";
-    public static final String EVENT_NAME_PREDICATE = "event-name";
-    public static final String LAST_PREDICATE = "num-of-events";
-    public static final String EVENT_ID = "event-id";
-    public static final String EVENT_INSTANCE_ID = "event-instance-id";
-    public static final String ACKED = "acked";
-
-    /**
-     * Resource class for {@link EventInfo}. Used to create Immutable objects
-     * returned in response to REST calls.
-     */
-    @Immutable
-    public static class EventInfoResource implements
-        Comparable<EventInfoResource> {
-
-        private final int eventId;
-        private final boolean enabled;
-        private final int bufferCapacity;
-        private final EventType etype;
-        private final String eventDesc;
-        private final String eventName;
-        private final String moduleName;
-        private final int numOfEvents;
-        private final boolean ackable;
-        public final ImmutableList<EventResource> events;
-
-        public EventInfoResource(EventInfo eventInfo,
-                                 List<EventResource> events) {
-            super();
-            this.eventId = eventInfo.getEventId();
-            this.enabled = eventInfo.isEnabled();
-            this.bufferCapacity = eventInfo.getBufferCapacity();
-            this.etype = eventInfo.getEtype();
-            this.eventDesc = eventInfo.getEventDesc();
-            this.eventName = eventInfo.getEventName();
-            this.moduleName = eventInfo.getModuleName();
-            this.numOfEvents = eventInfo.getNumOfEvents();
-            this.ackable = eventInfo.isAckable();
-            this.events = ImmutableList.copyOf(events);
-        }
-
-        @DBProperty(value = "enabled")
-        public boolean isEnabled() {
-            return enabled;
-        }
-
-        @DBProperty(value = "buffer-capacity")
-        public int getBufferCapacity() {
-            return bufferCapacity;
-        }
-
-        @DBProperty(value = "etype")
-        public EventType getEtype() {
-            return etype;
-        }
-
-        @DBProperty(value = "event-desc")
-        public String getEventDesc() {
-            return eventDesc;
-        }
-
-        @DBProperty(value = "event-name")
-        public String getEventName() {
-            return eventName;
-        }
-
-        @DBProperty(value = "module-name")
-        public String getModuleName() {
-            return moduleName;
-        }
-
-        @DBProperty(value = "num-of-events")
-        public int getNumOfEvents() {
-            return numOfEvents;
-        }
-
-        @DBProperty(value = "ackable")
-        public boolean isAckable() {
-            return ackable;
-        }
-
-        @DBProperty(value = "event")
-        public List<EventResource> getEvents() {
-            return events;
-        }
-
-        @DBProperty(value = "event-id")
-        public int getEventId() {
-            return eventId;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + (ackable ? 1231 : 1237);
-            result = prime * result + bufferCapacity;
-            result = prime * result + (enabled ? 1231 : 1237);
-            result = prime * result
-                     + ((etype == null) ? 0 : etype.hashCode());
-            result = prime * result
-                     + ((eventDesc == null) ? 0 : eventDesc.hashCode());
-            result = prime * result + eventId;
-            result = prime * result
-                     + ((eventName == null) ? 0 : eventName.hashCode());
-            result = prime * result
-                     + ((events == null) ? 0 : events.hashCode());
-            result = prime * result
-                     + ((moduleName == null) ? 0 : moduleName.hashCode());
-            result = prime * result + numOfEvents;
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) return true;
-            if (obj == null) return false;
-            if (getClass() != obj.getClass()) return false;
-            EventInfoResource other = (EventInfoResource) obj;
-            if (ackable != other.ackable) return false;
-            if (bufferCapacity != other.bufferCapacity) return false;
-            if (enabled != other.enabled) return false;
-            if (etype != other.etype) return false;
-            if (eventDesc == null) {
-                if (other.eventDesc != null) return false;
-            } else if (!eventDesc.equals(other.eventDesc)) return false;
-            if (eventId != other.eventId) return false;
-            if (eventName == null) {
-                if (other.eventName != null) return false;
-            } else if (!eventName.equals(other.eventName)) return false;
-            if (events == null) {
-                if (other.events != null) return false;
-            } else if (!events.equals(other.events)) return false;
-            if (moduleName == null) {
-                if (other.moduleName != null) return false;
-            } else if (!moduleName.equals(other.moduleName)) return false;
-            if (numOfEvents != other.numOfEvents) return false;
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder();
-            builder.append("EventInfoResource [eventId=");
-            builder.append(eventId);
-            builder.append(", enabled=");
-            builder.append(enabled);
-            builder.append(", bufferCapacity=");
-            builder.append(bufferCapacity);
-            builder.append(", etype=");
-            builder.append(etype);
-            builder.append(", eventDesc=");
-            builder.append(eventDesc);
-            builder.append(", eventName=");
-            builder.append(eventName);
-            builder.append(", moduleName=");
-            builder.append(moduleName);
-            builder.append(", numOfEvents=");
-            builder.append(numOfEvents);
-            builder.append(", ackable=");
-            builder.append(ackable);
-            builder.append(", events=");
-            builder.append(events);
-            builder.append("]");
-            return builder.toString();
-        }
-
-        /**
-         * The natural order of this class is ascending on eventId and
-         * consistent with equals.
-         */
-        @Override
-        public int compareTo(EventInfoResource o) {
-            return ComparisonChain.start().compare(eventId, o.eventId)
-                                  .compareFalseFirst(enabled, o.enabled)
-                                  .compare(bufferCapacity, o.bufferCapacity)
-                                  .compare(etype, o.etype)
-                                  .compare(eventDesc, o.eventDesc)
-                                  .compare(eventName, o.eventName)
-                                  .compare(moduleName, o.moduleName)
-                                  .compare(numOfEvents, o.numOfEvents)
-                                  .result();
-        }
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEventService.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEventService.java
deleted file mode 100644
index 113a42002ffdd43a35c903a029024e599d302bf4..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/DebugEventService.java
+++ /dev/null
@@ -1,711 +0,0 @@
-package net.floodlightcontroller.debugevent;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.projectfloodlight.core.IShutdownListener;
-import org.projectfloodlight.core.IShutdownService;
-import org.projectfloodlight.core.module.FloodlightModuleContext;
-import org.projectfloodlight.core.module.IFloodlightModule;
-import org.projectfloodlight.core.module.IFloodlightService;
-import org.projectfloodlight.debugevent.DebugEventResource.EventInfoResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
-
-/**
- * This class implements a central store for all events used for debugging the
- * system. The basic idea is that given the functionality provided by this
- * class, it should be unnecessary to resort to scraping through system
- * DEBUG/TRACE logs to understand behavior in a running system.
- *
- * @author Saurav
- */
-public class DebugEventService implements IFloodlightModule, IDebugEventService {
-    protected static final Logger log = LoggerFactory.getLogger(DebugEventService.class);
-
-    /**
-     * Every registered event type gets an event id AtomicInt to make the get
-     * operation thread-safe
-     */
-    private final AtomicInteger eventIdCounter = new AtomicInteger();
-
-    /**
-     * Unique Event Instance Id for ack-ing
-     */
-    private final AtomicLong eventInstanceId = new AtomicLong(Long.MAX_VALUE);
-
-    private static final int PCT_LOCAL_CAP = 10; // % of global capacity
-    private static final int MIN_LOCAL_CAPACITY = 10; // elements
-
-    /**
-     * EnumMap from {@link EventFieldType} to {@link CustomFormatter}
-     */
-    static final ImmutableMap<EventFieldType, CustomFormatter<?>> customFormatter =
-            new ImmutableMap.Builder<EventFieldType, CustomFormatter<?>>()
-            .put(EventFieldType.DPID, new CustomFormatterDpid())
-            .put(EventFieldType.IPv4, new CustomFormatterIpv4())
-              .put(EventFieldType.MAC, new CustomFormatterMac())
-              .put(EventFieldType.STRING, new CustomFormatterString())
-              .put(EventFieldType.OBJECT, new CustomFormatterObject())
-              .put(EventFieldType.PRIMITIVE, new CustomFormatterPrimitive())
-              .put(EventFieldType.COLLECTION_IPV4, new CustomFormatterCollectionIpv4())
-              .put(EventFieldType.COLLECTION_ATTACHMENT_POINT, new CustomFormatterCollectionAttachmentPoint())
-              .put(EventFieldType.COLLECTION_OBJECT, new CustomFormatterCollectionObject())
-              .put(EventFieldType.SREF_COLLECTION_OBJECT, new CustomFormatterSrefCollectionObject())
-              .put(EventFieldType.SREF_OBJECT, new CustomFormatterSrefObject())
-              .build();
-
-    /**
-     * Event Information
-     */
-    public static class EventInfo {
-        private final int eventId;
-        private final boolean enabled;
-        private final int bufferCapacity;
-        private int numOfEvents;
-        private final EventType etype;
-        private final String eventDesc;
-        private final String eventName;
-        private final String moduleName;
-        private final String moduleEventName;
-        private final Class<?> eventClass;
-        private final boolean ackable;
-
-        public EventInfo(int eventId, boolean enabled, boolean ackable,
-                         int bufferCapacity, EventType etype,
-                         Class<?> eventClass, String eventDesc,
-                         String eventName, String moduleName) {
-            this.enabled = enabled;
-            this.ackable = ackable;
-            this.eventId = eventId;
-            this.bufferCapacity = bufferCapacity;
-            this.numOfEvents = bufferCapacity;
-            this.etype = etype;
-            this.eventClass = eventClass;
-            this.eventDesc = eventDesc;
-            this.eventName = eventName;
-            this.moduleName = moduleName;
-            this.moduleEventName = moduleName + "/" + eventName;
-        }
-
-        public int getEventId() {
-            return eventId;
-        }
-
-        public boolean isEnabled() {
-            return enabled;
-        }
-
-        public boolean isAckable() {
-            return ackable;
-        }
-
-        public int getBufferCapacity() {
-            return bufferCapacity;
-        }
-
-        public int getNumOfEvents() {
-            return numOfEvents;
-        }
-
-        public EventType getEtype() {
-            return etype;
-        }
-
-        public String getEventDesc() {
-            return eventDesc;
-        }
-
-        public String getEventName() {
-            return eventName;
-        }
-
-        public String getModuleName() {
-            return moduleName;
-        }
-
-        public String getModuleEventName() {
-            return moduleEventName;
-        }
-    }
-
-    // ******************
-    // Global stores
-    // ******************
-
-    /**
-     * Event history for a particular event-id is stored in a circular buffer
-     */
-    protected static class DebugEventHistory {
-        EventInfo einfo;
-        LinkedBlockingDeque<Event> circularEventBuffer;
-
-        public DebugEventHistory(EventInfo einfo, int capacity) {
-            this.einfo = einfo;
-            this.circularEventBuffer = new LinkedBlockingDeque<Event>(
-                                                                      capacity);
-        }
-    }
-
-    /**
-     * Global storage for all event types and their corresponding event buffers.
-     * A particular event type is accessed by directly indexing into the Map
-     * with the corresponding event-id. <br/>
-     * It is a <b>Map</b> with <br/>
-     * <b>Key</b> Integer eventId <br/>
-     * <b>Value</b> DebugEventHistory
-     */
-    protected final ConcurrentHashMap<Integer, DebugEventHistory> allEvents = new ConcurrentHashMap<Integer, DebugEventHistory>();
-
-    /**
-     * Global storage for all event ids registered for a module. The map is
-     * indexed by the module name and event name and returns the event-ids that
-     * correspond to the event types registered by that module (for example
-     * module 'linkdiscovery' may register events that have ids 0 and 1 that
-     * correspond to link up/down events, and receiving malformed LLDP packets,
-     * respectively).
-     */
-    protected final ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>> moduleEvents = new ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>>();
-
-    /**
-     * A collection of event ids that are currently enabled for logging
-     */
-    protected final Set<Integer> currentEvents = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
-
-    // ******************
-    // Thread local stores
-    // ******************
-
-    /**
-     * Thread local storage for events
-     */
-    protected static class LocalEventHistory {
-        private boolean enabled;
-        private final int capacity;
-        private ArrayList<Event> eventList;
-
-        public LocalEventHistory(boolean enabled, int maxCapacity) {
-            this.enabled = enabled;
-            this.eventList = new ArrayList<Event>(maxCapacity);
-            this.capacity = maxCapacity;
-        }
-
-        public boolean add(Event e) {
-            if (this.eventList.size() < capacity) {
-                this.eventList.add(e);
-                return true;
-            }
-            return false;
-        }
-
-        public int drainTo(List<Event> eventList) {
-            int size = this.eventList.size();
-            Iterator<Event> iter = this.eventList.iterator();
-            while (iter.hasNext()) {
-                eventList.add(iter.next());
-            }
-            this.eventList.clear();
-            return size;
-        }
-
-        public boolean isFull() {
-            if (eventList.size() == capacity) return true;
-            return false;
-        }
-
-        public boolean isEmpty() {
-            return this.eventList.isEmpty();
-        }
-    }
-
-    /**
-     * Thread local event buffers used for maintaining event history local to a
-     * thread. Eventually this locally maintained information is flushed into
-     * the global event buffers. <br/>
-     * It is a <b>Map</b> with <br/>
-     * <b>Key</b> Integer eventId <br/>
-     * <b>Value</b> LocalEventHistory
-     */
-    protected final ThreadLocal<Map<Integer, LocalEventHistory>> threadlocalEvents = new ThreadLocal<Map<Integer, LocalEventHistory>>() {
-        @Override
-        protected Map<Integer, LocalEventHistory> initialValue() {
-            return new HashMap<Integer, LocalEventHistory>();
-        }
-    };
-
-    /**
-     * Thread local cache for event-ids that are currently active.
-     */
-    protected final ThreadLocal<Set<Integer>> threadlocalCurrentEvents = new ThreadLocal<Set<Integer>>() {
-        @Override
-        protected Set<Integer> initialValue() {
-            return new HashSet<Integer>();
-        }
-    };
-
-    // *******************************
-    // IEventCategory
-    // *******************************
-
-    protected class EventCategory<T> implements IEventCategory<T> {
-        private final int eventId;
-
-        public EventCategory(int evId) {
-            this.eventId = evId;
-        }
-
-        @Override
-        public void newEventNoFlush(Object event) {
-            if (!validEventId()) return;
-            newEvent(eventId, false, event);
-        }
-
-        @Override
-        public void newEventWithFlush(Object event) {
-            if (!validEventId()) return;
-            newEvent(eventId, true, event);
-        }
-
-        private boolean validEventId() {
-            if (eventId < 0) {
-                throw new IllegalStateException();
-            }
-            return true;
-        }
-    }
-
-    public class EventCategoryBuilder<T> {
-        private int eventId;
-        private String moduleName;
-        private String eventName;
-        private String eventDescription;
-        private EventType eventType;
-        private Class<T> eventClass;
-        private int bufferCapacity;
-        private boolean ackable;
-
-        public EventCategoryBuilder(Class<T> evClass) {
-            this.eventId = eventIdCounter.incrementAndGet();
-            this.eventClass = evClass;
-        }
-
-        public EventCategoryBuilder<T> setModuleName(String moduleName) {
-            this.moduleName = moduleName;
-            return this;
-        }
-
-        public EventCategoryBuilder<T> setEventName(String eventName) {
-            this.eventName = eventName;
-            return this;
-        }
-
-        public EventCategoryBuilder<T> setEventDescription(String eventDescription) {
-            this.eventDescription = eventDescription;
-            return this;
-        }
-
-        public EventCategoryBuilder<T> setEventType(EventType et) {
-            this.eventType = et;
-            return this;
-        }
-
-        public EventCategoryBuilder<T> setBufferCapacity(int bufferCapacity) {
-            this.bufferCapacity = bufferCapacity;
-            return this;
-        }
-
-        public EventCategoryBuilder<T> setAckable(boolean ackable) {
-            this.ackable = ackable;
-            return this;
-        }
-
-        /**
-         * Build a new {@link EventCategory<T>} <br/>
-         * Requires the following parameters to be set before being called:
-         *
-         * @param moduleName
-         *            module registering event eg. linkdiscovery, virtualrouting.
-         * @param eventName
-         *            name given to event.
-         * @param eventDescription
-         *            A descriptive string describing the event.
-         * @param eventType
-         *            EventType for this event. On-demand events have to be
-         *            explicitly enabled using other methods in this API
-         * @param eventClass
-         *            A user defined class that annotates the fields with
-         *            @EventColumn. This class specifies the fields/columns for this
-         *            event.
-         * @param bufferCapacity
-         *            Number of events to store for this event in a circular buffer.
-         *            Older events will be discarded once the buffer is full.
-         * @param ackable
-         *            is the event used as part of ackable-event framework boolean
-         *
-         * @return IEventCategory with <b>newEvent</b> method that can be used
-         * to create instances of event of the given eventClass
-         */
-        public EventCategory<T> register() {
-            // register event id for moduleName
-            moduleEvents.putIfAbsent(moduleName,
-                                     new ConcurrentHashMap<String, Integer>());
-            Integer eventExists = moduleEvents.get(moduleName)
-                                              .putIfAbsent(eventName, eventId);
-            if (eventExists != null) {
-                log.error("Duplicate event registration for moduleName {} eventName {}",
-                          moduleName, eventName);
-                return new EventCategory<T>(eventExists);
-            }
-
-            // create storage for event-type
-            boolean enabled = (eventType == EventType.ALWAYS_LOG) ? true : false;
-            EventInfo ei = new EventInfo(eventId, enabled, ackable,
-                                         bufferCapacity, eventType, eventClass,
-                                         eventDescription, eventName, moduleName);
-            allEvents.put(eventId, new DebugEventHistory(ei, bufferCapacity));
-            if (enabled) {
-                currentEvents.add(eventId);
-            }
-
-            return new EventCategory<T>(this.eventId);
-        }
-    }
-
-    // *******************************
-    // IDebugEventService
-    // *******************************
-
-    @Override
-    public <T> EventCategoryBuilder<T> buildEvent(Class<T> evClass) {
-        return new EventCategoryBuilder<T>(evClass);
-    }
-
-    private void flushLocalToGlobal(int eventId, LocalEventHistory le) {
-        DebugEventHistory de = allEvents.get(eventId);
-        if (de.einfo.enabled) {
-            List<Event> transferEvents = new ArrayList<Event>();
-            // drain local buffer to Collection
-            int size = le.drainTo(transferEvents);
-            // if global buffer doesn't have enough space, clear
-            // some space
-            int requiredSpace = size
-                                - de.circularEventBuffer.remainingCapacity();
-            if (requiredSpace > 0) {
-                for (int i = 0; i < requiredSpace; i++) {
-                    de.circularEventBuffer.removeFirst();
-                }
-            }
-            de.circularEventBuffer.addAll(transferEvents);
-        } else {
-            le.enabled = false;
-            this.threadlocalCurrentEvents.get().remove(eventId);
-        }
-    }
-
-    private void newEvent(int eventId, boolean flushNow, Object eventData) {
-        if (eventId < 0) {
-            throw new IllegalStateException("Invalid eventId");
-        }
-
-        Map<Integer, LocalEventHistory> thishist = this.threadlocalEvents.get();
-        if (!thishist.containsKey(eventId)) {
-            // seeing this event for the first time in this thread - create
-            // local
-            // store by consulting global store
-            if (allEvents.containsKey(eventId)) {
-                DebugEventHistory de = allEvents.get(eventId);
-                boolean enabled = de.einfo.enabled;
-                int localCapacity = de.einfo.bufferCapacity * PCT_LOCAL_CAP
-                                    / 100;
-                if (localCapacity < 10) localCapacity = MIN_LOCAL_CAPACITY;
-                thishist.put(eventId, new LocalEventHistory(enabled,
-                                                            localCapacity));
-                if (enabled) {
-                    Set<Integer> thisset = this.threadlocalCurrentEvents.get();
-                    thisset.add(eventId);
-                }
-            } else {
-                log.error("updateEvent seen locally for event {} but no global"
-                                  + "storage exists for it yet .. not updating",
-                          eventId);
-                return;
-            }
-        }
-
-        // update local store if enabled locally for updating
-        LocalEventHistory le = thishist.get(eventId);
-        if (le.enabled) {
-            try {
-                le.add(new Event(System.currentTimeMillis(),
-                                 Thread.currentThread().getId(),
-                                 Thread.currentThread().getName(),
-                                 eventData,
-                                 /*
-                                  * the eventInstanceId is started in reverse
-                                  * order so BigDB gets the values in ascending
-                                  * order Initialization in startUp()
-                                  */
-                                 eventInstanceId.decrementAndGet()));
-
-                if (le.isFull() || flushNow) {
-                    flushLocalToGlobal(eventId, le);
-                }
-            } catch (IllegalStateException ise) {
-                log.debug("Exception while adding event locally: "
-                          + ise.getMessage());
-            }
-        }
-    }
-
-    @Override
-    public void flushEvents() {
-        Map<Integer, LocalEventHistory> thishist = this.threadlocalEvents.get();
-        Set<Integer> thisset = this.threadlocalCurrentEvents.get();
-
-        for (int eventId : thisset) {
-            if (thishist.containsKey(eventId)) {
-                LocalEventHistory le = thishist.get(eventId);
-                if (!le.isEmpty()) {
-                    flushLocalToGlobal(eventId, le);
-                }
-            }
-        }
-
-        // sync thread local currently enabled set of eventIds with global set.
-        Sets.SetView<Integer> sv = Sets.difference(currentEvents, thisset);
-        for (int eventId : sv) {
-            if (thishist.containsKey(eventId)) {
-                thishist.get(eventId).enabled = true;
-                thisset.add(eventId);
-            }
-        }
-
-    }
-
-    @Override
-    public boolean containsModuleEventName(String moduleName,
-                                           String eventName) {
-        if (!moduleEvents.containsKey(moduleName)) return false;
-        if (moduleEvents.get(moduleName).containsKey(eventName))
-                                                                return true;
-        return false;
-    }
-
-    @Override
-    public boolean containsModuleName(String moduleName) {
-        return moduleEvents.containsKey(moduleName);
-    }
-
-    @Override
-    public List<EventInfoResource> getAllEventHistory() {
-        List<EventInfoResource> moduleEventList = new ArrayList<EventInfoResource>();
-        for (Map<String, Integer> modev : moduleEvents.values()) {
-            for (int eventId : modev.values()) {
-                if (allEvents.containsKey(eventId)) {
-                    DebugEventHistory de = allEvents.get(eventId);
-
-                    List<EventResource> eventData = new ArrayList<EventResource>();
-                    // take snapshot and iterate
-                    Iterator<Event> iter = de.circularEventBuffer.descendingIterator();
-                    while (iter.hasNext()) {
-                        Event e = iter.next();
-                        eventData.add(e.getFormattedEvent(de.einfo.eventClass,
-                                                          de.einfo.moduleEventName));
-                    }
-                    moduleEventList.add(new EventInfoResource(de.einfo,
-                                                              eventData));
-                }
-            }
-        }
-        traceLogDebugHistory(moduleEventList);
-        return moduleEventList;
-    }
-
-    @Override
-    public List<EventInfoResource> getModuleEventHistory(String moduleName) {
-        if (!moduleEvents.containsKey(moduleName))
-                                                  return Collections.emptyList();
-        List<EventInfoResource> moduleEventList = new ArrayList<EventInfoResource>();
-        for (int eventId : moduleEvents.get(moduleName).values()) {
-            if (allEvents.containsKey(eventId)) {
-                DebugEventHistory de = allEvents.get(eventId);
-
-                List<EventResource> eventData = new ArrayList<EventResource>();
-                // take snapshot and iterate
-                Iterator<Event> iter = de.circularEventBuffer.descendingIterator();
-                while (iter.hasNext()) {
-                    Event e = iter.next();
-                    eventData.add(e.getFormattedEvent(de.einfo.eventClass,
-                                                      de.einfo.moduleEventName));
-                }
-                moduleEventList.add(new EventInfoResource(de.einfo,
-                                                          eventData));
-            }
-        }
-        traceLogDebugHistory(moduleEventList);
-        return moduleEventList;
-    }
-
-    @Override
-    public EventInfoResource getSingleEventHistory(String moduleName,
-                                                   String eventName,
-                                                   int numOfEvents) {
-        if (!moduleEvents.containsKey(moduleName)) return null;
-        Integer eventId = moduleEvents.get(moduleName).get(eventName);
-        if (eventId == null) return null;
-
-        if (!allEvents.containsKey(eventId)) return null;
-
-        DebugEventHistory de = allEvents.get(eventId);
-        if (numOfEvents == 0) numOfEvents = de.einfo.bufferCapacity;
-
-        de.einfo.numOfEvents = numOfEvents;
-        int num = 1;
-        List<EventResource> eventData = new ArrayList<EventResource>();
-        // take snapshot and iterate
-        Iterator<Event> iter = de.circularEventBuffer.descendingIterator();
-        while (iter.hasNext()) {
-            Event e = iter.next();
-            if (num > numOfEvents) break;
-            eventData.add(e.getFormattedEvent(de.einfo.eventClass,
-                                              de.einfo.moduleEventName));
-            num++;
-        }
-        EventInfoResource ret = new EventInfoResource(de.einfo, eventData);
-        traceLogDebugHistory(Collections.singletonList(ret));
-        return ret;
-    }
-
-    @Override
-    public void resetAllEvents() {
-        for (Map<String, Integer> eventMap : moduleEvents.values()) {
-            for (Integer evId : eventMap.values()) {
-                allEvents.get(evId).circularEventBuffer.clear();
-            }
-        }
-    }
-
-    @Override
-    public void resetAllModuleEvents(String moduleName) {
-        if (!moduleEvents.containsKey(moduleName)) return;
-        Map<String, Integer> modEvents = moduleEvents.get(moduleName);
-        for (Integer evId : modEvents.values()) {
-            allEvents.get(evId).circularEventBuffer.clear();
-        }
-    }
-
-    @Override
-    public void resetSingleEvent(String moduleName, String eventName) {
-        if (!moduleEvents.containsKey(moduleName)) return;
-        Integer eventId = moduleEvents.get(moduleName).get(eventName);
-        if (eventId == null) return;
-
-        if (allEvents.containsKey(eventId)) {
-            allEvents.get(eventId).circularEventBuffer.clear();
-        }
-    }
-
-    @Override
-    public void setAck(int eventId, long eventInstanceId, boolean ack) {
-        if (allEvents.containsKey(eventId)) {
-            for (Event e : allEvents.get(eventId).circularEventBuffer) {
-                if (e.getEventInstanceId() == eventInstanceId) {
-                    e.setAcked(ack);
-                }
-            }
-        }
-    }
-
-    @Override
-    public List<String> getModuleList() {
-        List<String> el = new ArrayList<String>();
-        el.addAll(moduleEvents.keySet());
-        return el;
-    }
-
-    @Override
-    public List<String> getModuleEventList(String moduleName) {
-        if (!moduleEvents.containsKey(moduleName))
-                                                  return Collections.emptyList();
-        List<String> el = new ArrayList<String>();
-        el.addAll(moduleEvents.get(moduleName).keySet());
-        return el;
-    }
-
-
-    private void traceLogDebugHistory(List<EventInfoResource> l) {
-        if (!log.isTraceEnabled()) {
-            return;
-        }
-        for (EventInfoResource eir: l) {
-            for (EventResource der: eir.getEvents()) {
-                log.trace("{}", der);
-            }
-        }
-    }
-
-    private class ShutdownListenenerDelegate implements IShutdownListener {
-        @Override
-        public void floodlightIsShuttingDown() {
-            for (EventInfoResource eir: getAllEventHistory()) {
-                for (EventResource der: eir.getEvents()) {
-                    log.info("{}", der);
-                }
-            }
-        }
-    }
-
-    // *******************************
-    // IFloodlightModule
-    // *******************************
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IDebugEventService.class);
-        return l;
-    }
-
-    @Override
-    public Map<Class<? extends IFloodlightService>, IFloodlightService>
-            getServiceImpls() {
-        Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
-        m.put(IDebugEventService.class, this);
-        return m;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleDependencies() {
-        ArrayList<Class<? extends IFloodlightService>> deps = new ArrayList<Class<? extends IFloodlightService>>();
-        deps.add(IShutdownService.class);
-        return deps;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context) {
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        IShutdownService shutdownService =
-                context.getServiceImpl(IShutdownService.class);
-        shutdownService.registerShutdownListener(new ShutdownListenenerDelegate());
-        DebugEventAppender.setDebugEventServiceImpl(this);
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/Event.java b/src/main/java/net/floodlightcontroller/debugevent/Event.java
index 1eb76a1a80b0b1227e1867d27f2bb07849358ae7..3e0ac6db32eba864cb27c335553ade8a1bf5cfc6 100644
--- a/src/main/java/net/floodlightcontroller/debugevent/Event.java
+++ b/src/main/java/net/floodlightcontroller/debugevent/Event.java
@@ -11,10 +11,8 @@ import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.packet.IPv4;
 
-import org.projectfloodlight.openflow.protocol.OFFlowMod;
-import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
-import org.projectfloodlight.openflow.protocol.OFFlowModify;
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.util.HexString;
 
 public class Event {
     long timestamp;
@@ -112,8 +110,8 @@ public class Event {
                         if (flags == 0) {
                             builder.append("None");
                         }
-                        else { //towirevalue
-                            if ((flags & OFFlowModFlags.SEND_FLOW_REM.) != 0) {
+                        else {
+                            if ((flags & OFFlowMod.OFPFF_SEND_FLOW_REM) != 0) {
                                 builder.append("SEND_FLOW_REM ");
                             }
                             if ((flags & OFFlowMod.OFPFF_CHECK_OVERLAP) != 0) {
diff --git a/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java b/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java
new file mode 100644
index 0000000000000000000000000000000000000000..d54e9f632af539f53ecdd9e4b2b4477cba8d79d5
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java
@@ -0,0 +1,189 @@
+package net.floodlightcontroller.debugevent;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.debugevent.DebugEvent.EventInfo;
+
+public interface IDebugEventService extends IFloodlightService {
+
+    /**
+     * Different event types. Events that are meant to be logged on demand
+     * need to be separately enabled/disabled.
+     */
+    public enum EventType {
+        ALWAYS_LOG,
+        LOG_ON_DEMAND
+    }
+
+    /**
+     * Describes the type of field obtained from reflection
+     */
+    enum EventFieldType {
+        DPID, IPv4, MAC, STRING, OBJECT, PRIMITIVE, LIST_IPV4,
+        LIST_ATTACHMENT_POINT, LIST_OBJECT, SREF_LIST_OBJECT, SREF_OBJECT,
+        FLOW_MOD_FLAGS
+    }
+
+    /**
+     * EventColumn is the only annotation given to the fields of the event
+     * when updating an event.
+     */
+    @Target(ElementType.FIELD)
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface EventColumn {
+        String name() default "param";
+        EventFieldType description() default EventFieldType.PRIMITIVE;
+    }
+
+    /**
+     * Debug Event Qualifiers
+     */
+    public static final String EV_MDATA_WARN = "warn";
+    public static final String EV_MDATA_ERROR = "error";
+
+    /**
+     *  A limit on the maximum number of events that can be created
+     */
+    public static final int MAX_EVENTS = 2000;
+
+    /**
+     * Public class for information returned in response to rest API calls.
+     */
+    public class DebugEventInfo {
+        EventInfo eventInfo;
+        List<Map<String,String>> events;
+
+        public DebugEventInfo(EventInfo eventInfo,
+                              List<Map<String, String>> eventHistory) {
+            this.eventInfo = eventInfo;
+            this.events = eventHistory;
+        }
+
+        public EventInfo getEventInfo() {
+            return eventInfo;
+        }
+
+        public List<Map<String,String>> getEvents() {
+            return events;
+        }
+    }
+
+    /**
+    * exception thrown when MAX_EVENTS have been registered
+    */
+    public class MaxEventsRegistered extends Exception {
+        private static final long serialVersionUID = 2609587082227510262L;
+    }
+
+    /**
+     * Register an event for debugging.
+     *
+     * @param moduleName       module registering event eg. linkdiscovery, virtualrouting.
+     * @param eventName        name given to event.
+     * @param eventDescription A descriptive string describing the event.
+     * @param eventType        EventType for this event. On-demand events have to
+     *                         be explicitly enabled using other methods in this API
+     * @param eventClass       A user defined class that annotates the fields
+     *                         with @EventColumn. This class specifies the
+     *                         fields/columns for this event.
+     * @param bufferCapacity   Number of events to store for this event in a circular
+     *                         buffer. Older events will be discarded once the
+     *                         buffer is full.
+     * @param metaData         variable arguments that qualify an event
+     *                         eg. EV_MDATA_WARN, EV_MDATA_ERROR etc. See Debug Event Qualifiers
+     * @return                 IEventUpdater with update methods that can be used to
+     *                         update an event of the given eventClass
+     * @throws MaxEventsRegistered
+     */
+    public <T> IEventUpdater<T> registerEvent(String moduleName, String eventName,
+                                              String eventDescription,
+                                              EventType eventType,
+                                              Class<T> eventClass,
+                                              int bufferCapacity,
+                                              String... metaData)
+                                                      throws MaxEventsRegistered;
+
+    /**
+     * Update the global event stores with values from the thread local stores. This
+     * method is not typically intended for use by any module. It's typical usage is from
+     * floodlight core for events that happen in the packet processing pipeline.
+     * For other rare events, flushEvents should be called.
+     */
+    public void flushEvents();
+
+    /**
+     * Determine if eventName is a registered event for a given moduleName
+     */
+    public boolean containsModuleEventName(String moduleName, String eventName);
+
+    /**
+     * Determine if any events have been registered for module of name moduleName
+     */
+    public boolean containsModuleName(String moduleName);
+
+    /**
+     * Get event history for all events. This call can be expensive as it
+     * formats the event histories for all events.
+     *
+     * @return  a list of all event histories or an empty list if no events have
+     *          been registered
+     */
+    public List<DebugEventInfo> getAllEventHistory();
+
+    /**
+     * Get event history for all events registered for a given moduleName
+     *
+     * @return  a list of all event histories for all events registered for the
+     *          the module or an empty list if there are no events for this module
+     */
+    public List<DebugEventInfo> getModuleEventHistory(String moduleName);
+
+    /**
+     * Get event history for a single event
+     *
+     * @param  moduleName  registered module name
+     * @param  eventName   registered event name for moduleName
+     * @param  last        last X events
+     * @return DebugEventInfo for that event, or null if the moduleEventName
+     *         does not correspond to a registered event.
+     */
+    public DebugEventInfo getSingleEventHistory(String moduleName, String eventName, int last);
+
+    /**
+     * Wipe out all event history for all registered events
+     */
+    public void resetAllEvents();
+
+    /**
+     * Wipe out all event history for all events registered for a specific module
+     *
+     * @param moduleName  registered module name
+     */
+    public void resetAllModuleEvents(String moduleName);
+
+    /**
+     * Wipe out event history for a single event
+     * @param  moduleName  registered module name
+     * @param  eventName   registered event name for moduleName
+     */
+    public void resetSingleEvent(String moduleName, String eventName);
+
+    /**
+     * Retrieve a list of moduleNames registered for debug events or an empty
+     * list if no events have been registered in the system
+     */
+    public List<String> getModuleList();
+
+    /**
+     * Returns a list of all events registered for a specific moduleName
+     * or a empty list
+     */
+    public List<String> getModuleEventList(String moduleName);
+
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/IEventCategory.java b/src/main/java/net/floodlightcontroller/debugevent/IEventCategory.java
deleted file mode 100644
index 00cea123269b5aadef0d5438889ffaf00b24c2fb..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/IEventCategory.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package net.floodlightcontroller.debugevent;
-
-/**
- * EventCategory is used to log events for pre-registered events.
- */
-public interface IEventCategory<T> {
-
-    /**
-     * Logs the instance of the event thread-locally. Flushing to the global
-     * circular buffer for this event is delayed resulting in better
-     * performance. This method should typically be used by those events that
-     * happen in the packet processing pipeline
-     *
-     * @param event
-     *            an instance of the user-defined event of type T
-     */
-    public void newEventNoFlush(T event);
-
-    /**
-     * Logs the instance of the event thread-locally and immediated flushes to
-     * the global circular buffer for this event. This method should typically
-     * be used by those events that happen outside the packet processing
-     * pipeline
-     *
-     * @param event
-     *            an instance of the user-defined event of type T
-     */
-    public void newEventWithFlush(T event);
-
-}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java b/src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java
deleted file mode 100644
index 7f0676a556f37be26f259dfd883e8191c932b5a6..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package net.floodlightcontroller.debugevent;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-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.debugevent.DebugEventResource.EventInfoResource;
-import net.floodlightcontroller.debugevent.DebugEventService.EventCategoryBuilder;
-
-public class MockDebugEventService implements IFloodlightModule, IDebugEventService {
-
-    @Override
-    public <T> EventCategoryBuilder<T> buildEvent(Class<T> evClass) {
-        DebugEventService des = new DebugEventService();
-        return des.buildEvent(evClass);
-    }
-
-    @Override
-    public void flushEvents() {
-
-    }
-
-    @Override
-    public boolean containsModuleEventName(String moduleName,
-                                           String eventName) {
-        return false;
-    }
-
-    @Override
-    public boolean containsModuleName(String moduleName) {
-        return false;
-    }
-
-    @Override
-    public List<EventInfoResource> getAllEventHistory() {
-        return Collections.emptyList();
-    }
-
-    @Override
-    public List<EventInfoResource> getModuleEventHistory(String moduleName) {
-        return Collections.emptyList();
-    }
-
-    @Override
-    public EventInfoResource getSingleEventHistory(String moduleName,
-                                                   String eventName,
-                                                   int numOfEvents) {
-        return null;
-    }
-
-    @Override
-    public void resetAllEvents() {
-
-    }
-
-    @Override
-    public void resetAllModuleEvents(String moduleName) {
-
-    }
-
-    @Override
-    public void resetSingleEvent(String moduleName, String eventName) {
-
-    }
-
-    @Override
-    public List<String> getModuleList() {
-        return Collections.emptyList();
-    }
-
-    @Override
-    public List<String> getModuleEventList(String moduleName) {
-        return Collections.emptyList();
-    }
-
-    @Override
-    public void setAck(int eventId, long eventInstanceId, boolean ack) {
-
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> services =
-                new ArrayList<Class<? extends IFloodlightService>>(1);
-        services.add(IDebugEventService.class);
-        return services;
-    }
-
-    @Override
-    public Map<Class<? extends IFloodlightService>, IFloodlightService>
-            getServiceImpls() {
-        Map<Class<? extends IFloodlightService>, IFloodlightService> m =
-                new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
-        m.put(IDebugEventService.class, this);
-        return m;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleDependencies() {
-        return null;
-    }
-
-    @Override
-    public
-            void
-            init(FloodlightModuleContext context)
-                                                 throws FloodlightModuleException {
-
-    }
-
-    @Override
-    public
-            void
-            startUp(FloodlightModuleContext context)
-                                                    throws FloodlightModuleException {
-
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java b/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java
index 4d5ba9be6d5d5ef7f31a4316cb92d2303a62502f..4593b7bac9d8f4b25f9a3c1e5c4693bfd1a0fca0 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java
@@ -19,10 +19,6 @@ package net.floodlightcontroller.devicemanager;
 
 import java.util.Date;
 
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.VlanVid;
-
 
 /**
  * Represents an independent device on the network.  A device consists of a 
@@ -41,7 +37,7 @@ public interface IDevice {
      * Get the MAC address of the device as a Long value.
      * @return the MAC address for the device
      */
-    public MacAddress getMACAddress();
+    public long getMACAddress();
 
     /**
      * Get the MAC address of the device as a String value.
@@ -54,13 +50,13 @@ public interface IDevice {
      * entities, then the value -1 will be returned.
      * @return an array containing all unique VLAN IDs for the device.
      */
-    public VlanVid[] getVlanId();
+    public Short[] getVlanId();
     
     /**
      * Get all unique IPv4 addresses associated with the device.
      * @return an array containing the unique IPv4 addresses for the device.
      */
-    public IPv4Address[] getIPv4Addresses();
+    public Integer[] getIPv4Addresses();
     
     /**
      * Get all unique attachment points associated with the device.  This will
@@ -89,7 +85,7 @@ public interface IDevice {
      * @param swp the switch port to query
      * @return an array containing the unique VLAN IDs
      */
-    public VlanVid[] getSwitchPortVlanIds(SwitchPort swp);
+    public Short[] getSwitchPortVlanIds(SwitchPort swp);
     
     /**
      * Get the most recent timestamp for this device
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java
index 40d729f6894149d9a1e3142c618bc606c0753a4b..eb3801344f73d68ab0c35e6db556c09edfa1ba68 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java
@@ -22,12 +22,6 @@ import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.Set;
 
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.VlanVid;
-import org.projectfloodlight.openflow.types.OFPort;
-
 import net.floodlightcontroller.core.FloodlightContextStore;
 import net.floodlightcontroller.core.module.IFloodlightService;
 
@@ -101,9 +95,9 @@ public interface IDeviceService extends IFloodlightService {
      * @throws IllegalArgumentException if not all key fields of the
      * current {@link IEntityClassifierService} are specified.
      */
-    public IDevice findDevice(MacAddress macAddress, VlanVid vlan,
-                              IPv4Address ipv4Address, DatapathId switchDPID,
-                              OFPort switchPort)
+    public IDevice findDevice(long macAddress, Short vlan,
+                              Integer ipv4Address, Long switchDPID,
+                              Integer switchPort)
                               throws IllegalArgumentException;
     
     /**
@@ -128,8 +122,8 @@ public interface IDeviceService extends IFloodlightService {
      * source's {@link IEntityClass} are specified.
      */
     public IDevice findClassDevice(IEntityClass entityClass,
-                                   MacAddress macAddress, VlanVid vlan,
-                                   IPv4Address ipv4Address)
+                                   long macAddress, Short vlan,
+                                   Integer ipv4Address)
                                    throws IllegalArgumentException;
 
     /**
@@ -168,11 +162,11 @@ public interface IDeviceService extends IFloodlightService {
      * @see IDeviceService#queryClassDevices(IEntityClass, Long, 
      * Short, Integer, Long, Integer)
      */
-    public Iterator<? extends IDevice> queryDevices(MacAddress macAddress,
-                                                    VlanVid vlan,
-                                                    IPv4Address ipv4Address, 
-                                                    DatapathId switchDPID,
-                                                    OFPort switchPort);
+    public Iterator<? extends IDevice> queryDevices(Long macAddress,
+                                                    Short vlan,
+                                                    Integer ipv4Address, 
+                                                    Long switchDPID,
+                                                    Integer switchPort);
 
     /**
      * Find devices that match the provided query.  Only the index for
@@ -193,11 +187,11 @@ public interface IDeviceService extends IFloodlightService {
      * Short, Integer, Long, Integer)
      */
     public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass,
-                                                         MacAddress macAddress,
-                                                         VlanVid vlan,
-                                                         IPv4Address ipv4Address, 
-                                                         DatapathId switchDPID,
-                                                         OFPort switchPort);
+                                                         Long macAddress,
+                                                         Short vlan,
+                                                         Integer ipv4Address, 
+                                                         Long switchDPID,
+                                                         Integer switchPort);
     
     /**
      * Adds a listener to listen for IDeviceManagerServices notifications
@@ -213,9 +207,9 @@ public interface IDeviceService extends IFloodlightService {
      * @param sw
      * @param port
      */
-    public void addSuppressAPs(DatapathId swId, OFPort port);
+    public void addSuppressAPs(long swId, short port);
 
-    public void removeSuppressAPs(DatapathId swId, OFPort port);
+    public void removeSuppressAPs(long swId, short port);
 
     public Set<SwitchPort> getSuppressAPs();
 
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java b/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java
index d057f9c4a353f0501631f6cf7725fd00d4be5b4e..9fe62d9507c0d2e575bebaa8bdcc86b8c15676a4 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java
@@ -17,8 +17,7 @@
 
 package net.floodlightcontroller.devicemanager;
 
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
+import org.openflow.util.HexString;
 
 import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
 
@@ -56,8 +55,8 @@ public class SwitchPort {
         }
     }
 
-    private final DatapathId switchDPID;
-    private final OFPort port;
+    private final long switchDPID;
+    private final int port;
     private final ErrorStatus errorStatus;
 
     /**
@@ -66,7 +65,7 @@ public class SwitchPort {
      * @param port the port
      * @param errorStatus any error status for the switch port
      */
-    public SwitchPort(DatapathId switchDPID, OFPort port, ErrorStatus errorStatus) {
+    public SwitchPort(long switchDPID, int port, ErrorStatus errorStatus) {
         super();
         this.switchDPID = switchDPID;
         this.port = port;
@@ -78,7 +77,7 @@ public class SwitchPort {
      * @param switchDPID the dpid
      * @param port the port
      */
-    public SwitchPort(DatapathId switchDPID, OFPort port) {
+    public SwitchPort(long switchDPID, int port) {
         super();
         this.switchDPID = switchDPID;
         this.port = port;
@@ -90,11 +89,11 @@ public class SwitchPort {
     // ***************
 
     @JsonSerialize(using=DPIDSerializer.class)
-    public DatapathId getSwitchDPID() {
+    public long getSwitchDPID() {
         return switchDPID;
     }
 
-    public OFPort getPort() {
+    public int getPort() {
         return port;
     }
 
@@ -114,8 +113,8 @@ public class SwitchPort {
                         + ((errorStatus == null)
                                 ? 0
                                 : errorStatus.hashCode());
-        result = prime * result + port.getPortNumber();
-        result = prime * result + (int) (switchDPID.getLong() ^ (switchDPID.getLong() >>> 32));
+        result = prime * result + port;
+        result = prime * result + (int) (switchDPID ^ (switchDPID >>> 32));
         return result;
     }
 
@@ -133,7 +132,7 @@ public class SwitchPort {
 
     @Override
     public String toString() {
-        return "SwitchPort [switchDPID=" + switchDPID.toString() +
+        return "SwitchPort [switchDPID=" + HexString.toHexString(switchDPID) +
                ", port=" + port + ", errorStatus=" + errorStatus + "]";
     }
 
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java
index 46c2408faef824cb4ccf74c9dd69515037f70f3a..a08a3a5d2cb723582cf422b5ca988a22ac61e3f2 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java
@@ -21,16 +21,11 @@
 
 package net.floodlightcontroller.devicemanager.internal;
 
-import java.util.Date;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
-
 public class AttachmentPoint {
-    DatapathId  sw;
-    OFPort port;
-    Date  activeSince;
-    Date  lastSeen;
+    long  sw;
+    short port;
+    long  activeSince;
+    long  lastSeen;
 
     // Timeout for moving attachment points from OF/broadcast
     // domain to another.
@@ -39,15 +34,15 @@ public class AttachmentPoint {
     public static final long OPENFLOW_TO_EXTERNAL_TIMEOUT = 30000; // 30 seconds
     public static final long CONSISTENT_TIMEOUT = 30000;           // 30 seconds
 
-    public AttachmentPoint(DatapathId sw, OFPort port, Date activeSince,
-                           Date lastSeen) {
+    public AttachmentPoint(long sw, short port, long activeSince,
+                           long lastSeen) {
         this.sw = sw;
         this.port = port;
         this.activeSince = activeSince;
         this.lastSeen = lastSeen;
     }
 
-    public AttachmentPoint(DatapathId sw, OFPort port, Date lastSeen) {
+    public AttachmentPoint(long sw, short port, long lastSeen) {
         this.sw = sw;
         this.port = port;
         this.lastSeen = lastSeen;
@@ -61,31 +56,31 @@ public class AttachmentPoint {
         this.lastSeen = ap.lastSeen;
     }
 
-    public DatapathId getSw() {
+    public long getSw() {
         return sw;
     }
-    public void setSw(DatapathId sw) {
+    public void setSw(long sw) {
         this.sw = sw;
     }
-    public OFPort getPort() {
+    public short getPort() {
         return port;
     }
-    public void setPort(OFPort port) {
+    public void setPort(short port) {
         this.port = port;
     }
-    public Date getActiveSince() {
+    public long getActiveSince() {
         return activeSince;
     }
-    public void setActiveSince(Date activeSince) {
+    public void setActiveSince(long activeSince) {
         this.activeSince = activeSince;
     }
-    public Date getLastSeen() {
+    public long getLastSeen() {
         return lastSeen;
     }
-    public void setLastSeen(Date lastSeen) {
-        if (this.lastSeen.getTime() + INACTIVITY_INTERVAL < lastSeen.getTime())
+    public void setLastSeen(long lastSeen) {
+        if (this.lastSeen + INACTIVITY_INTERVAL < lastSeen)
             this.activeSince = lastSeen;
-        if (this.lastSeen.before(lastSeen))
+        if (this.lastSeen < lastSeen)
             this.lastSeen = lastSeen;
     }
 
@@ -96,8 +91,8 @@ public class AttachmentPoint {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + port.getPortNumber();
-        result = prime * result + (int) (sw.getLong() ^ (sw.getLong() >>> 32));
+        result = prime * result + port;
+        result = prime * result + (int) (sw ^ (sw >>> 32));
         return result;
     }
 
@@ -123,7 +118,7 @@ public class AttachmentPoint {
     @Override
     public String toString() {
         return "AttachmentPoint [sw=" + sw + ", port=" + port
-               + ", activeSince=" + activeSince + ", lastSeen=" + lastSeen.toString()
+               + ", activeSince=" + activeSince + ", lastSeen=" + lastSeen
                + "]";
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
index 07e5b77bfbacf879ce6b749fe7cbe811d1c90f85..ef0ba346809496090c83e273be35c5576699369c 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
@@ -30,11 +30,7 @@ import java.util.Map;
 import java.util.TreeSet;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.VlanVid;
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -65,7 +61,7 @@ public class Device implements IDevice {
 
     protected final String macAddressString;
     // the vlan Ids from the entities of this device
-    protected final VlanVid[] vlanIds;
+    protected final Short[] vlanIds;
     protected volatile String dhcpClientName;
 
     /**
@@ -107,7 +103,7 @@ public class Device implements IDevice {
 
         if (entity.getSwitchDPID() != null &&
                 entity.getSwitchPort() != null){
-            DatapathId sw = entity.getSwitchDPID();
+            long sw = entity.getSwitchDPID();
             short port = entity.getSwitchPort().shortValue();
 
             if (deviceManager.isValidAttachmentPoint(sw, port)) {
@@ -213,29 +209,30 @@ public class Device implements IDevice {
                     new ArrayList<AttachmentPoint>(device.attachmentPoints);
         }
 
-        this.macAddressString = this.entities[0].getMacAddress().toString();
+        this.macAddressString =
+                HexString.toHexString(this.entities[0].getMacAddress(), 6);
 
         this.entityClass = device.entityClass;
         vlanIds = computeVlandIds();
     }
 
-    private VlanVid[] computeVlandIds() {
+    private Short[]  computeVlandIds() {
         if (entities.length == 1) {
             if (entities[0].getVlan() != null) {
-                return new VlanVid[]{ entities[0].getVlan() };
+                return new Short[]{ entities[0].getVlan() };
             } else {
-                return new VlanVid[] { VlanVid.ofVlan(-1) };
+                return new Short[] { Short.valueOf((short)-1) };
             }
         }
 
-        TreeSet<VlanVid> vals = new TreeSet<VlanVid>();
+        TreeSet<Short> vals = new TreeSet<Short>();
         for (Entity e : entities) {
             if (e.getVlan() == null)
-                vals.add(VlanVid.ofVlan(-1));
+                vals.add((short)-1);
             else
                 vals.add(e.getVlan());
         }
-        return vals.toArray(new VlanVid[vals.size()]);
+        return vals.toArray(new Short[vals.size()]);
     }
 
     /**
@@ -296,7 +293,7 @@ public class Device implements IDevice {
         if (apList == null) return false;
 
         for(AttachmentPoint ap: apList) {
-            if (ap.getLastSeen().getTime() + AttachmentPoint.INACTIVITY_INTERVAL <
+            if (ap.getLastSeen() + AttachmentPoint.INACTIVITY_INTERVAL <
                     System.currentTimeMillis())
                 expiredAPs.add(ap);
         }
@@ -335,8 +332,8 @@ public class Device implements IDevice {
             if (trueAP == null) continue;
             boolean c = (topology.isConsistent(trueAP.getSw(), trueAP.getPort(),
                                               ap.getSw(), ap.getPort()));
-            boolean active = (ap.getActiveSince().after(trueAP.getActiveSince()));
-            boolean last = ap.getLastSeen().getTime() > timeThreshold;
+            boolean active = (ap.getActiveSince() > trueAP.getActiveSince());
+            boolean last = ap.getLastSeen() > timeThreshold;
             if (!c && active && last) {
                 dupAPs.add(ap);
             }
@@ -388,7 +385,7 @@ public class Device implements IDevice {
      * @param lastSeen
      * @return
      */
-    protected boolean updateAttachmentPoint(DatapathId sw, OFPort port, Date lastSeen){
+    protected boolean updateAttachmentPoint(long sw, short port, long lastSeen){
         ITopologyService topology = deviceManager.topology;
         List<AttachmentPoint> oldAPList;
         List<AttachmentPoint> apList;
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java
index d9a7a4532284bc30bc74bd2f8017ecca854bee89..2cbea66e5577495461171661f479c4f26335f11f 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java
@@ -20,12 +20,6 @@ package net.floodlightcontroller.devicemanager.internal;
 import java.util.Arrays;
 import java.util.Iterator;
 
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.VlanVid;
-
 import net.floodlightcontroller.devicemanager.IEntityClass;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.util.FilterIterator;
@@ -36,11 +30,11 @@ import net.floodlightcontroller.util.FilterIterator;
 public class DeviceIterator extends FilterIterator<Device> {
     private IEntityClass[] entityClasses;
     
-    private MacAddress macAddress;
-    private VlanVid vlan;
-    private IPv4Address ipv4Address; 
-    private DatapathId switchDPID;
-    private OFPort switchPort;
+    private Long macAddress;
+    private Short vlan;
+    private Integer ipv4Address; 
+    private Long switchDPID;
+    private Integer switchPort;
     
     /**
      * Construct a new device iterator over the key fields
@@ -54,11 +48,11 @@ public class DeviceIterator extends FilterIterator<Device> {
      */
     public DeviceIterator(Iterator<Device> subIterator, 
                           IEntityClass[] entityClasses,
-                          MacAddress macAddress,
-                          VlanVid vlan, 
-                          IPv4Address ipv4Address, 
-                          DatapathId switchDPID,
-                          OFPort switchPort) {
+                          Long macAddress,
+                          Short vlan, 
+                          Integer ipv4Address, 
+                          Long switchDPID,
+                          Integer switchPort) {
         super(subIterator);
         this.entityClasses = entityClasses;
         this.subIterator = subIterator;
@@ -86,7 +80,7 @@ public class DeviceIterator extends FilterIterator<Device> {
             if (!match) return false;                
         }
         if (macAddress != null) {
-            if (macAddress.getLong() != value.getMACAddress())
+            if (macAddress.longValue() != value.getMACAddress())
                 return false;
         }
         if (vlan != null) {
@@ -106,11 +100,11 @@ public class DeviceIterator extends FilterIterator<Device> {
             match = false;
             for (SwitchPort sp : sps) {
                 if (switchDPID != null) {
-                    if (switchDPID.getLong() != sp.getSwitchDPID().getLong())
+                    if (switchDPID.longValue() != sp.getSwitchDPID())
                         return false;
                 }
                 if (switchPort != null) {
-                    if (switchPort.getPortNumber() != sp.getPort().getPortNumber())
+                    if (switchPort.intValue() != sp.getPort())
                         return false;
                 }
                 match = true;
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
index 7d34fc3f6d789dfdd9bb1c3ecd42369ab85a1244..e4f67420bed7489558a389dd6714c14b57451766 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
@@ -47,7 +47,7 @@ import net.floodlightcontroller.core.IHAListener;
 import net.floodlightcontroller.core.IInfoProvider;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.HARole;
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -96,15 +96,11 @@ import net.floodlightcontroller.util.MultiIterator;
 import static net.floodlightcontroller.devicemanager.internal.
 DeviceManagerImpl.DeviceUpdate.Change.*;
 
-import org.projectfloodlight.openflow.protocol.OFMatchWithSwDpid;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.VlanVid;
-import org.projectfloodlight.openflow.protocol.OFType;
+import org.openflow.protocol.OFMatchWithSwDpid;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFType;
 import org.sdnplatform.sync.IClosableIterator;
 import org.sdnplatform.sync.IStoreClient;
 import org.sdnplatform.sync.ISyncService;
@@ -364,33 +360,33 @@ IFlowReconcileListener, IInfoProvider {
         public int compare(AttachmentPoint oldAP, AttachmentPoint newAP) {
             //First compare based on L2 domain ID;
 
-            DatapathId oldSw = oldAP.getSw();
-            OFPort oldPort = oldAP.getPort();
-            DatapathId oldDomain = topology.getL2DomainId(oldSw);
+            long oldSw = oldAP.getSw();
+            short oldPort = oldAP.getPort();
+            long oldDomain = topology.getL2DomainId(oldSw);
             boolean oldBD = topology.isBroadcastDomainPort(oldSw, oldPort);
 
-            DatapathId newSw = newAP.getSw();
-            OFPort newPort = newAP.getPort();
-            DatapathId newDomain = topology.getL2DomainId(newSw);
+            long newSw = newAP.getSw();
+            short newPort = newAP.getPort();
+            long newDomain = topology.getL2DomainId(newSw);
             boolean newBD = topology.isBroadcastDomainPort(newSw, newPort);
 
-            if (oldDomain.getLong() < newDomain.getLong()) return -1;
-            else if (oldDomain.getLong() > newDomain.getLong()) return 1;
+            if (oldDomain < newDomain) return -1;
+            else if (oldDomain > newDomain) return 1;
 
 
-            // Give preference to LOCAL always
-            if (oldPort != OFPort.LOCAL &&
-                    newPort == OFPort.LOCAL) {
+            // Give preference to OFPP_LOCAL always
+            if (oldPort != OFPort.OFPP_LOCAL.getValue() &&
+                    newPort == OFPort.OFPP_LOCAL.getValue()) {
                 return -1;
-            } else if (oldPort == OFPort.LOCAL &&
-                    newPort != OFPort.LOCAL) {
+            } else if (oldPort == OFPort.OFPP_LOCAL.getValue() &&
+                    newPort != OFPort.OFPP_LOCAL.getValue()) {
                 return 1;
             }
 
             // We expect that the last seen of the new AP is higher than
             // old AP, if it is not, just reverse and send the negative
             // of the result.
-            if (oldAP.getActiveSince().after(newAP.getActiveSince()))
+            if (oldAP.getActiveSince() > newAP.getActiveSince())
                 return -compare(newAP, oldAP);
 
             long activeOffset = 0;
@@ -411,8 +407,8 @@ IFlowReconcileListener, IInfoProvider {
             }
 
 
-            if ((newAP.getActiveSince().getTime() > oldAP.getLastSeen().getTime() + activeOffset) ||
-                    (newAP.getLastSeen().getTime() > oldAP.getLastSeen().getTime() +
+            if ((newAP.getActiveSince() > oldAP.getLastSeen() + activeOffset) ||
+                    (newAP.getLastSeen() > oldAP.getLastSeen() +
                             AttachmentPoint.INACTIVITY_INTERVAL)) {
                 return -1;
             }
@@ -457,13 +453,13 @@ IFlowReconcileListener, IInfoProvider {
     }
 
     @Override
-    public IDevice findDevice(MacAddress macAddress, VlanVid vlan,
-                              IPv4Address ipv4Address, DatapathId switchDPID,
-                              OFPort switchPort)
+    public IDevice findDevice(long macAddress, Short vlan,
+                              Integer ipv4Address, Long switchDPID,
+                              Integer switchPort)
                               throws IllegalArgumentException {
-        if (vlan != null && vlan.getVlan() <= 0)
+        if (vlan != null && vlan.shortValue() <= 0)
             vlan = null;
-        if (ipv4Address != null && ipv4Address.getInt() == 0)
+        if (ipv4Address != null && ipv4Address == 0)
             ipv4Address = null;
         Entity e = new Entity(macAddress, vlan, ipv4Address, switchDPID,
                               switchPort, null);
@@ -475,12 +471,12 @@ IFlowReconcileListener, IInfoProvider {
     }
 
     @Override
-    public IDevice findClassDevice(IEntityClass entityClass, MacAddress macAddress,
-                                  VlanVid vlan, IPv4Address ipv4Address)
+    public IDevice findClassDevice(IEntityClass entityClass, long macAddress,
+                                  Short vlan, Integer ipv4Address)
                                   throws IllegalArgumentException {
-        if (vlan != null && vlan.getVlan() <= 0)
+        if (vlan != null && vlan.shortValue() <= 0)
             vlan = null;
-        if (ipv4Address != null && ipv4Address.getInt() == 0)
+        if (ipv4Address != null && ipv4Address == 0)
             ipv4Address = null;
         Entity e = new Entity(macAddress, vlan, ipv4Address,
                               null, null, null);
@@ -510,11 +506,11 @@ IFlowReconcileListener, IInfoProvider {
     }
 
     @Override
-    public Iterator<? extends IDevice> queryDevices(MacAddress macAddress,
-                                                    VlanVid vlan,
-                                                    IPv4Address ipv4Address,
-                                                    DatapathId switchDPID,
-                                                    OFPort switchPort) {
+    public Iterator<? extends IDevice> queryDevices(Long macAddress,
+                                                    Short vlan,
+                                                    Integer ipv4Address,
+                                                    Long switchDPID,
+                                                    Integer switchPort) {
         DeviceIndex index = null;
         if (secondaryIndexMap.size() > 0) {
             EnumSet<DeviceField> keys =
@@ -529,7 +525,7 @@ IFlowReconcileListener, IInfoProvider {
             deviceIterator = deviceMap.values().iterator();
         } else {
             // index lookup
-            Entity entity = new Entity(macAddress,
+            Entity entity = new Entity((macAddress == null ? 0 : macAddress),
                                        vlan,
                                        ipv4Address,
                                        switchDPID,
@@ -552,11 +548,11 @@ IFlowReconcileListener, IInfoProvider {
 
     @Override
     public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass,
-                                                         MacAddress macAddress,
-                                                         VlanVid vlan,
-                                                         IPv4Address ipv4Address,
-                                                         DatapathId switchDPID,
-                                                         OFPort switchPort) {
+                                                         Long macAddress,
+                                                         Short vlan,
+                                                         Integer ipv4Address,
+                                                         Long switchDPID,
+                                                         Integer switchPort) {
         ArrayList<Iterator<Device>> iterators =
                 new ArrayList<Iterator<Device>>();
         ClassState classState = getClassState(entityClass);
@@ -585,7 +581,7 @@ IFlowReconcileListener, IInfoProvider {
         } else {
             // index lookup
             Entity entity =
-                    new Entity(macAddress,
+                    new Entity((macAddress == null ? 0 : macAddress),
                                vlan,
                                ipv4Address,
                                switchDPID,
@@ -599,11 +595,11 @@ IFlowReconcileListener, IInfoProvider {
         return new MultiIterator<Device>(iterators.iterator());
     }
 
-    protected Iterator<Device> getDeviceIteratorForQuery(MacAddress macAddress,
-                                                        VlanVid vlan,
-                                                        IPv4Address ipv4Address,
-                                                        DatapathId switchDPID,
-                                                        OFPort switchPort) {
+    protected Iterator<Device> getDeviceIteratorForQuery(Long macAddress,
+                                                        Short vlan,
+                                                        Integer ipv4Address,
+                                                        Long switchDPID,
+                                                        Integer switchPort) {
         DeviceIndex index = null;
         if (secondaryIndexMap.size() > 0) {
             EnumSet<DeviceField> keys =
@@ -618,7 +614,7 @@ IFlowReconcileListener, IInfoProvider {
             deviceIterator = deviceMap.values().iterator();
         } else {
             // index lookup
-            Entity entity = new Entity(macAddress,
+            Entity entity = new Entity((macAddress == null ? 0 : macAddress),
                                 vlan,
                                 ipv4Address,
                                 switchDPID,
@@ -646,12 +642,12 @@ IFlowReconcileListener, IInfoProvider {
     }
 
     @Override
-    public void addSuppressAPs(DatapathId swId, OFPort port) {
+    public void addSuppressAPs(long swId, short port) {
         suppressAPs.add(new SwitchPort(swId, port));
     }
 
     @Override
-    public void removeSuppressAPs(DatapathId swId, OFPort port) {
+    public void removeSuppressAPs(long swId, short port) {
         suppressAPs.remove(new SwitchPort(swId, port));
     }
 
@@ -718,14 +714,14 @@ IFlowReconcileListener, IInfoProvider {
         }
 
         private void generateDeviceEvent(IDevice device, String reason) {
-            List<IPv4Address> ipv4Addresses =
-                new ArrayList<IPv4Address>(Arrays.asList(device.getIPv4Addresses()));
+            List<Integer> ipv4Addresses =
+                new ArrayList<Integer>(Arrays.asList(device.getIPv4Addresses()));
             List<SwitchPort> oldAps =
                 new ArrayList<SwitchPort>(Arrays.asList(device.getOldAP()));
             List<SwitchPort> currentAps =
                     new ArrayList<SwitchPort>(Arrays.asList(device.getAttachmentPoints()));
-            List<VlanVid> vlanIds =
-                    new ArrayList<VlanVid>(Arrays.asList(device.getVlanId()));
+            List<Short> vlanIds =
+                    new ArrayList<Short>(Arrays.asList(device.getVlanId()));
 
             evDevice.updateEventNoFlush(
                     new DeviceEvent(device.getMACAddress(),
@@ -775,7 +771,7 @@ IFlowReconcileListener, IInfoProvider {
                            FloodlightContext cntx) {
         switch (msg.getType()) {
             case PACKET_IN:
-                cntIncoming.increment();
+                cntIncoming.updateCounterNoFlush();
                 return this.processPacketInMessage(sw,
                                                    (OFPacketIn) msg, cntx);
             default:
@@ -807,19 +803,19 @@ IFlowReconcileListener, IInfoProvider {
     }
 
     protected Command reconcileFlow(OFMatchReconcile ofm) {
-        cntReconcileRequest.increment();
+        cntReconcileRequest.updateCounterNoFlush();
         // Extract source entity information
         Entity srcEntity =
                 getEntityFromFlowMod(ofm.ofmWithSwDpid, true);
         if (srcEntity == null) {
-            cntReconcileNoSource.increment();
+            cntReconcileNoSource.updateCounterNoFlush();
             return Command.STOP;
        }
 
         // Find the device by source entity
         Device srcDevice = findDeviceByEntity(srcEntity);
         if (srcDevice == null)  {
-            cntReconcileNoSource.increment();
+            cntReconcileNoSource.updateCounterNoFlush();
             return Command.STOP;
         }
         // Store the source device in the context
@@ -834,9 +830,9 @@ IFlowReconcileListener, IInfoProvider {
             if (dstDevice != null)
                 fcStore.put(ofm.cntx, CONTEXT_DST_DEVICE, dstDevice);
             else
-                cntReconcileNoDest.increment();
+                cntReconcileNoDest.updateCounterNoFlush();
         } else {
-            cntReconcileNoDest.increment();
+            cntReconcileNoDest.updateCounterNoFlush();
         }
         if (logger.isTraceEnabled()) {
             logger.trace("Reconciling flow: match={}, srcEntity={}, srcDev={}, "
@@ -1193,7 +1189,7 @@ IFlowReconcileListener, IInfoProvider {
         Entity srcEntity =
                 getSourceEntityFromPacket(eth, sw.getId(), pi.getInPort());
         if (srcEntity == null) {
-            cntInvalidSource.increment();
+            cntInvalidSource.updateCounterNoFlush();
             return Command.STOP;
         }
 
@@ -1208,7 +1204,7 @@ IFlowReconcileListener, IInfoProvider {
         // Learn/lookup device information
         Device srcDevice = learnDeviceByEntity(srcEntity);
         if (srcDevice == null) {
-            cntNoSource.increment();
+            cntNoSource.updateCounterNoFlush();
             return Command.STOP;
         }
 
@@ -1218,7 +1214,7 @@ IFlowReconcileListener, IInfoProvider {
         // Find the device matching the destination from the entity
         // classes of the source.
         if (eth.getDestinationMAC().toLong() == 0) {
-            cntInvalidDest.increment();
+            cntInvalidDest.updateCounterNoFlush();
             return Command.STOP;
         }
         Entity dstEntity = getDestEntityFromPacket(eth);
@@ -1229,9 +1225,9 @@ IFlowReconcileListener, IInfoProvider {
             if (dstDevice != null)
                 fcStore.put(cntx, CONTEXT_DST_DEVICE, dstDevice);
             else
-                cntNoDest.increment();
+                cntNoDest.updateCounterNoFlush();
         } else {
-            cntNoDest.increment();
+            cntNoDest.updateCounterNoFlush();
         }
 
        if (logger.isTraceEnabled()) {
@@ -1266,7 +1262,7 @@ IFlowReconcileListener, IInfoProvider {
             DHCPOption dhcpOption = dhcp.getOption(
                     DHCPOptionCode.OptionCode_Hostname);
             if (dhcpOption != null) {
-                cntDhcpClientNameSnooped.increment();
+                cntDhcpClientNameSnooped.updateCounterNoFlush();
                 srcDevice.dhcpClientName = new String(dhcpOption.getData());
             }
         }
@@ -1318,22 +1314,23 @@ IFlowReconcileListener, IInfoProvider {
      * @return the entity from the packet
      */
     protected Entity getSourceEntityFromPacket(Ethernet eth,
-                                             DatapathId swdpid,
-                                             OFPort port) {
-        MacAddress dlAddr = MacAddress.of(eth.getSourceMACAddress());
-        
+                                             long swdpid,
+                                             int port) {
+        byte[] dlAddrArr = eth.getSourceMACAddress();
+        long dlAddr = Ethernet.toLong(dlAddrArr);
+
         // Ignore broadcast/multicast source
-        if (dlAddr.isBroadcast() || dlAddr.isMulticast())
+        if ((dlAddrArr[0] & 0x1) != 0)
             return null;
         // Ignore 0 source mac
-        if (dlAddr.getLong() == 0)
+        if (dlAddr == 0)
             return null;
 
-        VlanVid vlan = VlanVid.ofVlan(eth.getVlanID());
-        IPv4Address nwSrc = getSrcNwAddr(eth, dlAddr);
+        short vlan = eth.getVlanID();
+        int nwSrc = getSrcNwAddr(eth, dlAddr);
         return new Entity(dlAddr,
-                          vlan,
-                          nwSrc,
+                          ((vlan >= 0) ? vlan : null),
+                          ((nwSrc != 0) ? nwSrc : null),
                           swdpid,
                           port,
                           new Date());
@@ -1345,8 +1342,8 @@ IFlowReconcileListener, IInfoProvider {
      * address in ARP data.
      */
     protected void learnDeviceFromArpResponseData(Ethernet eth,
-                                            DatapathId swdpid,
-                                            OFPort port) {
+                                            long swdpid,
+                                            int port) {
 
         if (!(eth.getPayload() instanceof ARP)) return;
         ARP arp = (ARP) eth.getPayload();
@@ -1615,8 +1612,8 @@ IFlowReconcileListener, IInfoProvider {
                 // attachment point port. Otherwise ignore.
                 if (entity.hasSwitchPort() &&
                         !topology.isAttachmentPointPort(entity.getSwitchDPID(),
-                                                 entity.getSwitchPort())) {
-                    cntDeviceOnInternalPortNotLearned.increment();
+                                                 entity.getSwitchPort().shortValue())) {
+                    cntDeviceOnInternalPortNotLearned.updateCounterNoFlush();
                     if (logger.isDebugEnabled()) {
                         logger.debug("Not learning new device on internal"
                                      + " link: {}", entity);
@@ -1627,7 +1624,7 @@ IFlowReconcileListener, IInfoProvider {
                 // Before we create the new device also check if
                 // the entity is allowed (e.g., for spoofing protection)
                 if (!isEntityAllowed(entity, entityClass)) {
-                    cntPacketNotAllowed.increment();
+                    cntPacketNotAllowed.updateCounterNoFlush();
                     if (logger.isDebugEnabled()) {
                         logger.debug("PacketIn is not allowed {} {}",
                                     entityClass.getName(), entity);
@@ -1655,7 +1652,7 @@ IFlowReconcileListener, IInfoProvider {
                 // We need to count and log here. If we log earlier we could
                 // hit a concurrent modification and restart the dev creation
                 // and potentially count the device twice.
-                cntNewDevice.increment();
+                cntNewDevice.updateCounterNoFlush();
                 if (logger.isDebugEnabled()) {
                     logger.debug("New device created: {} deviceKey={}, entity={}",
                                  new Object[]{device, deviceKey, entity});
@@ -1669,7 +1666,7 @@ IFlowReconcileListener, IInfoProvider {
             }
             // if it gets here, we have a pre-existing Device for this Entity
             if (!isEntityAllowed(entity, device.getEntityClass())) {
-                cntPacketNotAllowed.increment();
+                cntPacketNotAllowed.updateCounterNoFlush();
                 if (logger.isDebugEnabled()) {
                     logger.info("PacketIn is not allowed {} {}",
                                 device.getEntityClass().getName(), entity);
@@ -1681,8 +1678,8 @@ IFlowReconcileListener, IInfoProvider {
             // the chain.
             if (entity.hasSwitchPort() &&
                     !topology.isAttachmentPointPort(entity.getSwitchDPID(),
-                                                 entity.getSwitchPort())) {
-                cntPacketOnInternalPortForKnownDevice.increment();
+                                                 entity.getSwitchPort().shortValue())) {
+                cntPacketOnInternalPortForKnownDevice.updateCounterNoFlush();
                 break;
             }
             int entityindex = -1;
@@ -1726,9 +1723,9 @@ IFlowReconcileListener, IInfoProvider {
 
                 // We need to count here after all the possible "continue"
                 // statements in this branch
-                cntNewEntity.increment();
+                cntNewEntity.updateCounterNoFlush();
                 if (changedFields.size() > 0) {
-                    cntDeviceChanged.increment();
+                    cntDeviceChanged.updateCounterNoFlush();
                     deviceUpdates =
                     updateUpdates(deviceUpdates,
                                   new DeviceUpdate(newDevice, CHANGE,
@@ -1741,8 +1738,8 @@ IFlowReconcileListener, IInfoProvider {
             if (entity.hasSwitchPort()) {
                 boolean moved =
                         device.updateAttachmentPoint(entity.getSwitchDPID(),
-                                entity.getSwitchPort(),
-                                entity.getLastSeenTimestamp());
+                                entity.getSwitchPort().shortValue(),
+                                entity.getLastSeenTimestamp().getTime());
                 // TODO: use update mechanism instead of sending the
                 // notification directly
                 if (moved) {
@@ -1989,7 +1986,7 @@ IFlowReconcileListener, IInfoProvider {
      * Clean up expired entities/devices
      */
     protected void cleanupEntities () {
-        cntCleanupEntitiesRuns.increment();
+        cntCleanupEntitiesRuns.updateCounterWithFlush();
 
         Calendar c = Calendar.getInstance();
         c.add(Calendar.MILLISECOND, -ENTITY_TIMEOUT);
@@ -2022,7 +2019,7 @@ IFlowReconcileListener, IInfoProvider {
                     break;
                 }
 
-                cntEntityRemovedTimeout.increment();
+                cntEntityRemovedTimeout.updateCounterWithFlush();
                 for (Entity e : toRemove) {
                     removeEntity(e, d.getEntityClass(), d.getDeviceKey(), toKeep);
                 }
@@ -2058,7 +2055,7 @@ IFlowReconcileListener, IInfoProvider {
                     if (update != null) {
                         // need to count after all possibly continue stmts in
                         // this branch
-                        cntDeviceChanged.increment();
+                        cntDeviceChanged.updateCounterWithFlush();
                         deviceUpdates.add(update);
                     }
                 } else {
@@ -2070,7 +2067,7 @@ IFlowReconcileListener, IInfoProvider {
                         d = deviceMap.get(d.getDeviceKey());
                         if (null != d)
                             continue;
-                        cntDeviceDeleted.increment();
+                        cntDeviceDeleted.updateCounterWithFlush();
                     }
                     deviceUpdates.add(update);
                 }
@@ -2128,11 +2125,11 @@ IFlowReconcileListener, IInfoProvider {
         }
     }
 
-    private EnumSet<DeviceField> getEntityKeys(MacAddress macAddress,
-                                               VlanVid vlan,
-                                               IPv4Address ipv4Address,
-                                               DatapathId switchDPID,
-                                               OFPort switchPort) {
+    private EnumSet<DeviceField> getEntityKeys(Long macAddress,
+                                               Short vlan,
+                                               Integer ipv4Address,
+                                               Long switchDPID,
+                                               Integer switchPort) {
         // FIXME: vlan==null is a valid search. Need to handle this
         // case correctly. Note that the code will still work correctly.
         // But we might do a full device search instead of using an index.
@@ -2186,8 +2183,8 @@ IFlowReconcileListener, IInfoProvider {
         for (Entity entity : entities) {
             if (entity.switchDPID != null && entity.switchPort != null) {
                 AttachmentPoint aP =
-                        new AttachmentPoint(entity.switchDPID,
-                                    entity.switchPort, new Date(0));
+                        new AttachmentPoint(entity.switchDPID.longValue(),
+                                    entity.switchPort.shortValue(), 0);
                 newPossibleAPs.add(aP);
             }
         }
@@ -2244,7 +2241,7 @@ IFlowReconcileListener, IInfoProvider {
      * @param updates the updates to process.
      */
     protected void sendDeviceMovedNotification(Device d) {
-        cntDeviceMoved.increment();
+        cntDeviceMoved.updateCounterNoFlush();
         deviceSyncManager.storeDevice(d);
         List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
         if (listeners != null) {
@@ -2303,7 +2300,7 @@ IFlowReconcileListener, IInfoProvider {
             return false;
         }
 
-        cntDeviceReclassifyDelete.increment();
+        cntDeviceReclassifyDelete.updateCounterNoFlush();
         LinkedList<DeviceUpdate> deviceUpdates =
                 new LinkedList<DeviceUpdate>();
         // delete this device and then re-learn all the entities
@@ -2388,7 +2385,7 @@ IFlowReconcileListener, IInfoProvider {
                 writeUpdatedDeviceToStorage(d);
                 lastWriteTimes.put(d.getDeviceKey(), now);
             } else {
-                cntDeviceStoreThrottled.increment();
+                cntDeviceStoreThrottled.updateCounterWithFlush();
             }
         }
 
@@ -2409,12 +2406,12 @@ IFlowReconcileListener, IInfoProvider {
                 // TODO: should probably do versioned delete. OTOH, even
                 // if we accidentally delete, we'll write it again after
                 // the next entity ....
-                cntDeviceRemovedFromStore.increment();
+                cntDeviceRemovedFromStore.updateCounterWithFlush();
                 storeClient.delete(DeviceSyncRepresentation.computeKey(d));
             } catch(ObsoleteVersionException e) {
                 // FIXME
             } catch (SyncException e) {
-                cntSyncException.increment();
+                cntSyncException.updateCounterWithFlush();
                 logger.error("Could not remove device " + d + " from store", e);
             }
         }
@@ -2426,14 +2423,14 @@ IFlowReconcileListener, IInfoProvider {
          */
         private void removeDevice(Versioned<DeviceSyncRepresentation> dev) {
             try {
-                cntDeviceRemovedFromStore.increment();
+                cntDeviceRemovedFromStore.updateCounterWithFlush();
                 storeClient.delete(dev.getValue().getKey(),
                                    dev.getVersion());
             } catch(ObsoleteVersionException e) {
                 // Key was locally modified by another thread.
                 // Do not delete and ignore.
             } catch(SyncException e) {
-                cntSyncException.increment();
+                cntSyncException.updateCounterWithFlush();
                 logger.error("Failed to remove device entry for " +
                             dev.toString() + " from store.", e);
             }
@@ -2447,13 +2444,13 @@ IFlowReconcileListener, IInfoProvider {
             if (logger.isDebugEnabled()) {
                 logger.debug("Transitioning to MASTER role");
             }
-            cntTransitionToMaster.increment();
+            cntTransitionToMaster.updateCounterWithFlush();
             IClosableIterator<Map.Entry<String,Versioned<DeviceSyncRepresentation>>>
                     iter = null;
             try {
                 iter = storeClient.entries();
             } catch (SyncException e) {
-                cntSyncException.increment();
+                cntSyncException.updateCounterWithFlush();
                 logger.error("Failed to read devices from sync store", e);
                 return;
             }
@@ -2465,7 +2462,7 @@ IFlowReconcileListener, IInfoProvider {
                             versionedDevice.getValue();
                     if (storedDevice == null)
                         continue;
-                    cntDevicesFromStore.increment();
+                    cntDevicesFromStore.updateCounterWithFlush();
                     for(SyncEntity se: storedDevice.getEntities()) {
                         learnDeviceByEntity(se.asEntity());
                     }
@@ -2485,7 +2482,7 @@ IFlowReconcileListener, IInfoProvider {
          */
         private void writeUpdatedDeviceToStorage(Device device) {
             try {
-                cntDeviceStrored.increment();
+                cntDeviceStrored.updateCounterWithFlush();
                 // FIXME: use a versioned put
                 DeviceSyncRepresentation storeDevice =
                         new DeviceSyncRepresentation(device);
@@ -2494,7 +2491,7 @@ IFlowReconcileListener, IInfoProvider {
                 // FIXME: what's the right behavior here. Can the store client
                 // even throw this error?
             } catch (SyncException e) {
-                cntSyncException.increment();
+                cntSyncException.updateCounterWithFlush();
                 logger.error("Could not write device " + device +
                           " to sync store:", e);
             }
@@ -2518,7 +2515,7 @@ IFlowReconcileListener, IInfoProvider {
         private void consolidateStore() {
             if (!isMaster)
                 return;
-            cntConsolidateStoreRuns.increment();
+            cntConsolidateStoreRuns.updateCounterWithFlush();
             if (logger.isDebugEnabled()) {
                 logger.debug("Running consolidateStore.");
             }
@@ -2527,7 +2524,7 @@ IFlowReconcileListener, IInfoProvider {
             try {
                 iter = storeClient.entries();
             } catch (SyncException e) {
-                cntSyncException.increment();
+                cntSyncException.updateCounterWithFlush();
                 logger.error("Failed to read devices from sync store", e);
                 return;
             }
@@ -2564,7 +2561,7 @@ IFlowReconcileListener, IInfoProvider {
                                          + "corresponding live device",
                                          storedDevice.getKey());
                         }
-                        cntConsolidateStoreDevicesRemoved.increment();
+                        cntConsolidateStoreDevicesRemoved.updateCounterWithFlush();
                         removeDevice(versionedDevice);
                     }
                 }
@@ -2599,24 +2596,24 @@ IFlowReconcileListener, IInfoProvider {
      */
     private class DeviceEvent {
         @EventColumn(name = "MAC", description = EventFieldType.MAC)
-        private final MacAddress macAddress;
-        @EventColumn(name = "IPs", description = EventFieldType.IPv4)
-        private final List<IPv4Address> ipv4Addresses;
+        private final long macAddress;
+        @EventColumn(name = "IPs", description = EventFieldType.LIST_IPV4)
+        private final List<Integer> ipv4Addresses;
         @EventColumn(name = "Old Attachment Points",
-                     description = EventFieldType.COLLECTION_ATTACHMENT_POINT)
+                     description = EventFieldType.LIST_ATTACHMENT_POINT)
         private final List<SwitchPort> oldAttachmentPoints;
         @EventColumn(name = "Current Attachment Points",
-                     description = EventFieldType.COLLECTION_ATTACHMENT_POINT)
+                     description = EventFieldType.LIST_ATTACHMENT_POINT)
         private final List<SwitchPort> currentAttachmentPoints;
-        @EventColumn(name = "VLAN IDs", description = EventFieldType.COLLECTION_OBJECT)
-        private final List<VlanVid> vlanIds;
+        @EventColumn(name = "VLAN IDs", description = EventFieldType.LIST_OBJECT)
+        private final List<Short> vlanIds;
         @EventColumn(name = "Reason", description = EventFieldType.STRING)
         private final String reason;
 
-        public DeviceEvent(MacAddress macAddress, List<IPv4Address> ipv4Addresses,
+        public DeviceEvent(long macAddress, List<Integer> ipv4Addresses,
                 List<SwitchPort> oldAttachmentPoints,
                 List<SwitchPort> currentAttachmentPoints,
-                List<VlanVid> vlanIds, String reason) {
+                List<Short> vlanIds, String reason) {
             super();
             this.macAddress = macAddress;
             this.ipv4Addresses = ipv4Addresses;
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java
index b1c395d4c9664553550685125f686bdf87508283..42bfb01321cfc704d9578672630893bff31d4e0e 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java
@@ -6,14 +6,9 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.EnumSet;
 import java.util.List;
+import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField;
 
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.VlanVid;
 
-import net.floodlightcontroller.devicemanager.IDeviceService.DeviceField;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -21,15 +16,15 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class DeviceSyncRepresentation {
     public static class SyncEntity implements Comparable<SyncEntity> {
         @JsonProperty
-        public MacAddress macAddress;
+        public long macAddress;
         @JsonProperty
-        public IPv4Address ipv4Address;
+        public Integer ipv4Address;
         @JsonProperty
-        public VlanVid vlan;
+        public Short vlan;
         @JsonProperty
-        public DatapathId switchDPID;
+        public Long switchDPID;
         @JsonProperty
-        public OFPort switchPort;
+        public Integer switchPort;
         @JsonProperty
         public Date lastSeenTimestamp;
         @JsonProperty
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
index 39a8d79cd7c67b8e08522943bc97055b1d45745d..db8d8e9fb3ff92256e0e9db55751e9345e6765fa 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
@@ -22,15 +22,11 @@ import java.util.Date;
 import net.floodlightcontroller.core.web.serializers.IPv4Serializer;
 import net.floodlightcontroller.core.web.serializers.MACSerializer;
 import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
+import net.floodlightcontroller.packet.IPv4;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.VlanVid;
+import org.openflow.util.HexString;
 
 /**
  * An entity on the network is a visible trace of a device that corresponds
@@ -56,30 +52,30 @@ public class Entity implements Comparable<Entity> {
     /**
      * The MAC address associated with this entity
      */
-    protected MacAddress macAddress;
+    protected long macAddress;
     
     /**
      * The IP address associated with this entity, or null if no IP learned
      * from the network observation associated with this entity
      */
-    protected IPv4Address ipv4Address;
+    protected Integer ipv4Address;
     
     /**
      * The VLAN tag on this entity, or null if untagged
      */
-    protected VlanVid vlan;
+    protected Short vlan;
     
     /**
      * The DPID of the switch for the ingress point for this entity,
      * or null if not present
      */
-    protected DatapathId switchDPID;
+    protected Long switchDPID;
     
     /**
      * The port number of the switch for the ingress point for this entity,
      * or null if not present
      */
-    protected OFPort switchPort;
+    protected Integer switchPort;
     
     /**
      * The last time we observed this entity on the network
@@ -112,8 +108,8 @@ public class Entity implements Comparable<Entity> {
      * @param switchPort
      * @param lastSeenTimestamp
      */
-    public Entity(MacAddress macAddress, VlanVid vlan, 
-                  IPv4Address ipv4Address, DatapathId switchDPID, OFPort switchPort, 
+    public Entity(long macAddress, Short vlan, 
+                  Integer ipv4Address, Long switchDPID, Integer switchPort, 
                   Date lastSeenTimestamp) {
         this.macAddress = macAddress;
         this.ipv4Address = ipv4Address;
@@ -129,25 +125,25 @@ public class Entity implements Comparable<Entity> {
     // ***************
 
     @JsonSerialize(using=MACSerializer.class)
-    public MacAddress getMacAddress() {
+    public long getMacAddress() {
         return macAddress;
     }
 
     @JsonSerialize(using=IPv4Serializer.class)
-    public IPv4Address getIpv4Address() {
+    public Integer getIpv4Address() {
         return ipv4Address;
     }
 
-    public VlanVid getVlan() {
+    public Short getVlan() {
         return vlan;
     }
 
     @JsonSerialize(using=DPIDSerializer.class)
-    public DatapathId getSwitchDPID() {
+    public Long getSwitchDPID() {
         return switchDPID;
     }
 
-    public OFPort getSwitchPort() {
+    public Integer getSwitchPort() {
         return switchPort;
     }
     
@@ -189,7 +185,7 @@ public class Entity implements Comparable<Entity> {
         hashCode = 1;
         hashCode = prime * hashCode
                  + ((ipv4Address == null) ? 0 : ipv4Address.hashCode());
-        hashCode = prime * hashCode + (int) (macAddress.getLong() ^ (macAddress.getLong() >>> 32));
+        hashCode = prime * hashCode + (int) (macAddress ^ (macAddress >>> 32));
         hashCode = prime * hashCode
                  + ((switchDPID == null) ? 0 : switchDPID.hashCode());
         hashCode = prime * hashCode
@@ -227,15 +223,16 @@ public class Entity implements Comparable<Entity> {
     public String toString() {
         StringBuilder builder = new StringBuilder();
         builder.append("Entity [macAddress=");
-        builder.append(macAddress.toString());
+        builder.append(HexString.toHexString(macAddress, 6));
         builder.append(", ipv4Address=");
-        builder.append(ipv4Address.toString());
+        builder.append(IPv4.fromIPv4Address(ipv4Address==null ?
+                       0 : ipv4Address.intValue()));
         builder.append(", vlan=");
-        builder.append(vlan.getVlan());
+        builder.append(vlan);
         builder.append(", switchDPID=");
-        builder.append(switchDPID.toString());
+        builder.append(switchDPID);
         builder.append(", switchPort=");
-        builder.append(switchPort.getPortNumber());
+        builder.append(switchPort);
         builder.append(", lastSeenTimestamp=");
         builder.append(lastSeenTimestamp == null? "null" : lastSeenTimestamp.getTime());
         builder.append(", activeSince=");
@@ -246,8 +243,8 @@ public class Entity implements Comparable<Entity> {
 
     @Override
     public int compareTo(Entity o) {
-        if (macAddress.getLong() < o.macAddress.getLong()) return -1;
-        if (macAddress.getLong() > o.macAddress.getLong()) return 1;
+        if (macAddress < o.macAddress) return -1;
+        if (macAddress > o.macAddress) return 1;
 
         int r;
         if (switchDPID == null)
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java
index a1e7160b2b4987ffa2d87a07b3d6367a191ba43c..13a78a49accfa001c51fb3260325179abc362a46 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/IndexedEntity.java
@@ -89,8 +89,8 @@ public class IndexedEntity {
             switch (f) {
                 case MAC:
                     hashCode = prime * hashCode
-                        + (int) (entity.macAddress.getLong() ^ 
-                                (entity.macAddress.getLong() >>> 32));
+                        + (int) (entity.macAddress ^ 
+                                (entity.macAddress >>> 32));
                     break;
                 case IPV4:
                     hashCode = prime * hashCode
diff --git a/src/main/java/net/floodlightcontroller/firewall/Firewall.java b/src/main/java/net/floodlightcontroller/firewall/Firewall.java
index 6b6b5578f06dbe18416fc0eb166a7245dd076f4f..21dc8aed6ca937f3123e9a00971ee8b0fc13fd80 100644
--- a/src/main/java/net/floodlightcontroller/firewall/Firewall.java
+++ b/src/main/java/net/floodlightcontroller/firewall/Firewall.java
@@ -24,16 +24,9 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.EthType;
-import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
-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.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFType;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IOFMessageListener;
@@ -42,11 +35,11 @@ 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.IFloodlightProviderService;
 import net.floodlightcontroller.devicemanager.IDeviceService;
 
 import java.util.ArrayList;
-
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.restserver.IRestApiService;
@@ -191,7 +184,7 @@ public class Firewall implements IFirewallService, IOFMessageListener,
                 try {
                     r.ruleid = Integer
                             .parseInt((String) row.get(COLUMN_RULEID));
-                    r.dpid = DatapathId.of((String) row.get(COLUMN_DPID));
+                    r.dpid = Long.parseLong((String) row.get(COLUMN_DPID));
 
                     for (String key : row.keySet()) {
                         if (row.get(key) == null)
@@ -203,58 +196,58 @@ public class Firewall implements IFirewallService, IOFMessageListener,
                         } 
                         
                         else if (key.equals(COLUMN_IN_PORT)) {
-                            r.in_port = OFPort.of(Integer.parseInt((String) row
-                                    .get(COLUMN_IN_PORT)));
+                            r.in_port = Short.parseShort((String) row
+                                    .get(COLUMN_IN_PORT));
                         } 
                         
                         else if (key.equals(COLUMN_DL_SRC)) {
-                            r.dl_src = MacAddress.of(Long.parseLong((String) row
-                                    .get(COLUMN_DL_SRC)));
+                            r.dl_src = Long.parseLong((String) row
+                                    .get(COLUMN_DL_SRC));
                         } 
                         
                         else if (key.equals(COLUMN_DL_DST)) {
-                            r.dl_dst = MacAddress.of(Long.parseLong((String) row
-                                    .get(COLUMN_DL_DST)));
+                            r.dl_dst = Long.parseLong((String) row
+                                    .get(COLUMN_DL_DST));
                         } 
                         
                         else if (key.equals(COLUMN_DL_TYPE)) {
-                            r.dl_type = EthType.of(Integer.parseInt((String) row
-                                    .get(COLUMN_DL_TYPE)));
+                            r.dl_type = Short.parseShort((String) row
+                                    .get(COLUMN_DL_TYPE));
                         } 
                         
                         else if (key.equals(COLUMN_NW_SRC_PREFIX)) {
-                            r.nw_src_prefix_and_mask = IPv4AddressWithMask.of(Integer.parseInt((String) row
-                                    .get(COLUMN_NW_SRC_PREFIX)), r.nw_src_prefix_and_mask.getMask().getInt());
+                            r.nw_src_prefix = Integer.parseInt((String) row
+                                    .get(COLUMN_NW_SRC_PREFIX));
                         } 
                         
                         else if (key.equals(COLUMN_NW_SRC_MASKBITS)) {
-                            r.nw_src_prefix_and_mask = IPv4AddressWithMask.of(r.nw_src_prefix_and_mask.getValue().getInt(), Integer.parseInt((String) row
-                                    .get(COLUMN_NW_SRC_MASKBITS)));
+                            r.nw_src_maskbits = Integer.parseInt((String) row
+                                    .get(COLUMN_NW_SRC_MASKBITS));
                         } 
                         
                         else if (key.equals(COLUMN_NW_DST_PREFIX)) {
-                            r.nw_dst_prefix_and_mask = IPv4AddressWithMask.of(Integer.parseInt((String) row
-                                    .get(COLUMN_NW_DST_PREFIX)), r.nw_dst_prefix_and_mask.getMask().getInt());
+                            r.nw_dst_prefix = Integer.parseInt((String) row
+                                    .get(COLUMN_NW_DST_PREFIX));
                         } 
                         
                         else if (key.equals(COLUMN_NW_DST_MASKBITS)) {
-                            r.nw_dst_prefix_and_mask = IPv4AddressWithMask.of(r.nw_dst_prefix_and_mask.getValue().getInt(), Integer.parseInt((String) row
-                                    .get(COLUMN_NW_DST_MASKBITS)));
+                            r.nw_dst_maskbits = Integer.parseInt((String) row
+                                    .get(COLUMN_NW_DST_MASKBITS));
                         } 
                         
                         else if (key.equals(COLUMN_NW_PROTO)) {
-                            r.nw_proto = IpProtocol.of(Short.parseShort((String) row
-                                    .get(COLUMN_NW_PROTO)));
+                            r.nw_proto = Short.parseShort((String) row
+                                    .get(COLUMN_NW_PROTO));
                         } 
                         
                         else if (key.equals(COLUMN_TP_SRC)) {
-                            r.tp_src = TransportPort.of(Integer.parseInt((String) row
-                                    .get(COLUMN_TP_SRC)));
+                            r.tp_src = Short.parseShort((String) row
+                                    .get(COLUMN_TP_SRC));
                         } 
                         
                         else if (key.equals(COLUMN_TP_DST)) {
-                            r.tp_dst = TransportPort.of(Integer.parseInt((String) row
-                                    .get(COLUMN_TP_DST)));
+                            r.tp_dst = Short.parseShort((String) row
+                                    .get(COLUMN_TP_DST));
                         } 
                         
                         else if (key.equals(COLUMN_WILDCARD_DPID)) {
@@ -459,18 +452,18 @@ public class Firewall implements IFirewallService, IOFMessageListener,
         // add rule to database
         Map<String, Object> entry = new HashMap<String, Object>();
         entry.put(COLUMN_RULEID, Integer.toString(rule.ruleid));
-        entry.put(COLUMN_DPID, Long.toString(rule.dpid.getLong()));
-        entry.put(COLUMN_IN_PORT, Integer.toString(rule.in_port.getPortNumber()));
-        entry.put(COLUMN_DL_SRC, Long.toString(rule.dl_src.getLong()));
-        entry.put(COLUMN_DL_DST, Long.toString(rule.dl_dst.getLong()));
-        entry.put(COLUMN_DL_TYPE, Integer.toString(rule.dl_type.getValue()));
-        entry.put(COLUMN_NW_SRC_PREFIX, Integer.toString(rule.nw_src_prefix_and_mask.getValue().getInt()));
-        entry.put(COLUMN_NW_SRC_MASKBITS, Integer.toString(rule.nw_src_prefix_and_mask.getMask().getInt()));
-        entry.put(COLUMN_NW_DST_PREFIX, Integer.toString(rule.nw_dst_prefix_and_mask.getValue().getInt()));
-        entry.put(COLUMN_NW_DST_MASKBITS, Integer.toString(rule.nw_dst_prefix_and_mask.getMask().getInt()));
-        entry.put(COLUMN_NW_PROTO, Short.toString(rule.nw_proto.getIpProtocolNumber()));
-        entry.put(COLUMN_TP_SRC, Integer.toString(rule.tp_src.getPort()));
-        entry.put(COLUMN_TP_DST, Integer.toString(rule.tp_dst.getPort()));
+        entry.put(COLUMN_DPID, Long.toString(rule.dpid));
+        entry.put(COLUMN_IN_PORT, Short.toString(rule.in_port));
+        entry.put(COLUMN_DL_SRC, Long.toString(rule.dl_src));
+        entry.put(COLUMN_DL_DST, Long.toString(rule.dl_dst));
+        entry.put(COLUMN_DL_TYPE, Short.toString(rule.dl_type));
+        entry.put(COLUMN_NW_SRC_PREFIX, Integer.toString(rule.nw_src_prefix));
+        entry.put(COLUMN_NW_SRC_MASKBITS, Integer.toString(rule.nw_src_maskbits));
+        entry.put(COLUMN_NW_DST_PREFIX, Integer.toString(rule.nw_dst_prefix));
+        entry.put(COLUMN_NW_DST_MASKBITS, Integer.toString(rule.nw_dst_maskbits));
+        entry.put(COLUMN_NW_PROTO, Short.toString(rule.nw_proto));
+        entry.put(COLUMN_TP_SRC, Integer.toString(rule.tp_src));
+        entry.put(COLUMN_TP_DST, Integer.toString(rule.tp_dst));
         entry.put(COLUMN_WILDCARD_DPID,
                 Boolean.toString(rule.wildcard_dpid));
         entry.put(COLUMN_WILDCARD_IN_PORT,
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
index bee8fddef5942d16806c3cef144ded5a01dcfd3b..f457ce8d9e85510f91fdefe2bb2f3ac84276eec4 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
@@ -18,15 +18,7 @@
 package net.floodlightcontroller.firewall;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-
-import org.projectfloodlight.openflow.protocol.match.MatchField;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.EthType;
-import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
-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.openflow.protocol.OFMatch;
 
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
@@ -38,18 +30,18 @@ import net.floodlightcontroller.packet.UDP;
 public class FirewallRule implements Comparable<FirewallRule> {
     public int ruleid;
 
-    public DatapathId dpid; 
-    public OFPort in_port; 
-    public MacAddress dl_src; 
-    public MacAddress dl_dst; 
-    public EthType dl_type; 
-    public IPv4AddressWithMask nw_src_prefix_and_mask; 
-    //public int nw_src_maskbits;
-    public IPv4AddressWithMask nw_dst_prefix_and_mask;
-    //public int nw_dst_maskbits;
-    public IpProtocol nw_proto;
-    public TransportPort tp_src;
-    public TransportPort tp_dst;
+    public long dpid; 
+    public short in_port; 
+    public long dl_src; 
+    public long dl_dst; 
+    public short dl_type; 
+    public int nw_src_prefix; 
+    public int nw_src_maskbits;
+    public int nw_dst_prefix;
+    public int nw_dst_maskbits;
+    public short nw_proto;
+    public short tp_src;
+    public short tp_dst;
 
     public boolean wildcard_dpid;
     public boolean wildcard_in_port; 
@@ -75,18 +67,18 @@ public class FirewallRule implements Comparable<FirewallRule> {
     }
 
     public FirewallRule() {
-        this.in_port = OFPort.ZERO; 
-        this.dl_src = MacAddress.NONE;
-        this.nw_src_prefix_and_mask = IPv4AddressWithMask.NONE;
-        //this.nw_src_maskbits = 0; 
-        this.dl_dst = MacAddress.NONE;
-        this.nw_proto = IpProtocol.NONE;
-        this.tp_src = TransportPort.NONE;
-        this.tp_dst = TransportPort.NONE;
-        this.dl_dst = MacAddress.NONE;
-        this.nw_dst_prefix_and_mask = IPv4AddressWithMask.NONE;
-        //this.nw_dst_maskbits = 0; 
-        this.dpid = DatapathId.NONE;
+        this.in_port = 0; 
+        this.dl_src = 0;
+        this.nw_src_prefix = 0;
+        this.nw_src_maskbits = 0; 
+        this.dl_dst = 0;
+        this.nw_proto = 0;
+        this.tp_src = 0;
+        this.tp_dst = 0;
+        this.dl_dst = 0;
+        this.nw_dst_prefix = 0;
+        this.nw_dst_maskbits = 0; 
+        this.dpid = -1;
         this.wildcard_dpid = true; 
         this.wildcard_in_port = true; 
         this.wildcard_dl_src = true; 
@@ -96,7 +88,7 @@ public class FirewallRule implements Comparable<FirewallRule> {
         this.wildcard_nw_dst = true; 
         this.wildcard_nw_proto = true; 
         this.wildcard_tp_src = true; 
-        this.wildcard_tp_dst = true;
+        this.wildcard_tp_dst = true; 
         this.priority = 0; 
         this.action = FirewallAction.ALLOW; 
         this.ruleid = 0; 
@@ -140,23 +132,23 @@ public class FirewallRule implements Comparable<FirewallRule> {
     public boolean isSameAs(FirewallRule r) {
         if (this.action != r.action
                 || this.wildcard_dl_type != r.wildcard_dl_type
-                || (this.wildcard_dl_type == false && !this.dl_type.equals(r.dl_type))
+                || (this.wildcard_dl_type == false && this.dl_type != r.dl_type)
                 || this.wildcard_tp_src != r.wildcard_tp_src
-                || (this.wildcard_tp_src == false && !this.tp_src.equals(r.tp_src))
+                || (this.wildcard_tp_src == false && this.tp_src != r.tp_src)
                 || this.wildcard_tp_dst != r.wildcard_tp_dst
-                || (this.wildcard_tp_dst == false && !this.tp_dst.equals(r.tp_dst))
+                || (this.wildcard_tp_dst == false &&this.tp_dst != r.tp_dst)
                 || this.wildcard_dpid != r.wildcard_dpid
-                || (this.wildcard_dpid == false && !this.dpid.equals(r.dpid))
+                || (this.wildcard_dpid == false && this.dpid != r.dpid)
                 || this.wildcard_in_port != r.wildcard_in_port
-                || (this.wildcard_in_port == false && !this.in_port.equals(r.in_port))
+                || (this.wildcard_in_port == false && this.in_port != r.in_port)
                 || this.wildcard_nw_src != r.wildcard_nw_src
-                || (this.wildcard_nw_src == false && !this.nw_src_prefix_and_mask.equals(r.nw_src_prefix_and_mask))
+                || (this.wildcard_nw_src == false && (this.nw_src_prefix != r.nw_src_prefix || this.nw_src_maskbits != r.nw_src_maskbits))
                 || this.wildcard_dl_src != r.wildcard_dl_src
-                || (this.wildcard_dl_src == false && !this.dl_src.equals(r.dl_src))
+                || (this.wildcard_dl_src == false && this.dl_src != r.dl_src)
                 || this.wildcard_nw_proto != r.wildcard_nw_proto
-                || (this.wildcard_nw_proto == false && !this.nw_proto.equals(r.nw_proto))
+                || (this.wildcard_nw_proto == false && this.nw_proto != r.nw_proto)
                 || this.wildcard_nw_dst != r.wildcard_nw_dst
-                || (this.wildcard_nw_dst == false && !this.nw_dst_prefix_and_mask.equals(r.nw_dst_prefix_and_mask))
+                || (this.wildcard_nw_dst == false && (this.nw_dst_prefix != r.nw_dst_prefix || this.nw_dst_maskbits != r.nw_dst_maskbits))
                 || this.wildcard_dl_dst != r.wildcard_dl_dst                
                 || (this.wildcard_dl_dst == false && this.dl_dst != r.dl_dst)) {
             return false;
@@ -179,7 +171,7 @@ public class FirewallRule implements Comparable<FirewallRule> {
      *            method to derive wildcards for the decision to be taken
      * @return true if the rule matches the given packet-in, false otherwise
      */
-    public boolean matchesFlow(DatapathId switchDpid, OFPort inPort, Ethernet packet,
+    public boolean matchesFlow(long switchDpid, short inPort, Ethernet packet,
             WildcardsPair wildcards) {
         IPacket pkt = packet.getPayload();
 
@@ -195,39 +187,35 @@ public class FirewallRule implements Comparable<FirewallRule> {
         short pkt_tp_dst = 0;
 
         // switchID matches?
-        if (wildcard_dpid == false && !dpid.equals(switchDpid))
+        if (wildcard_dpid == false && dpid != switchDpid)
             return false;
 
         // in_port matches?
-        if (wildcard_in_port == false && !in_port.equals(inPort))
+        if (wildcard_in_port == false && in_port != inPort)
             return false;
         if (action == FirewallRule.FirewallAction.DENY) {
-            //wildcards.drop &= ~OFMatch.OFPFW_IN_PORT;
-            wildcards.drop.setExact(MatchField.IN_PORT, this.in_port);
+            wildcards.drop &= ~OFMatch.OFPFW_IN_PORT;
         } else {
-            //wildcards.allow &= ~OFMatch.OFPFW_IN_PORT;
-            wildcards.allow.setExact(MatchField.IN_PORT, this.in_port);
+            wildcards.allow &= ~OFMatch.OFPFW_IN_PORT;
         }
 
         // mac address (src and dst) match?
-        if (wildcard_dl_src == false && !dl_src.equals(packet.getSourceMAC()))
+        if (wildcard_dl_src == false
+                && dl_src != packet.getSourceMAC().toLong())
             return false;
         if (action == FirewallRule.FirewallAction.DENY) {
-            //wildcards.drop &= ~OFMatch.OFPFW_DL_SRC;
-            wildcards.drop.setExact(MatchField.ETH_SRC, this.dl_src);
+            wildcards.drop &= ~OFMatch.OFPFW_DL_SRC;
         } else {
-            //wildcards.allow &= ~OFMatch.OFPFW_DL_SRC;
-            wildcards.allow.setExact(MatchField.ETH_SRC, this.dl_src);
+            wildcards.allow &= ~OFMatch.OFPFW_DL_SRC;
         }
 
-        if (wildcard_dl_dst == false && !dl_dst.equals(packet.getDestinationMAC()))
+        if (wildcard_dl_dst == false
+                && dl_dst != packet.getDestinationMAC().toLong())
             return false;
         if (action == FirewallRule.FirewallAction.DENY) {
-            //wildcards.drop &= ~OFMatch.OFPFW_DL_DST;
-            wildcards.drop.setExact(MatchField.ETH_DST, this.dl_dst);
+            wildcards.drop &= ~OFMatch.OFPFW_DL_DST;
         } else {
-            //wildcards.allow &= ~OFMatch.OFPFW_DL_DST;
-            wildcards.allow.setExact(MatchField.ETH_DST, this.dl_dst);
+            wildcards.allow &= ~OFMatch.OFPFW_DL_DST;
         }
 
         // dl_type check: ARP, IP
@@ -235,128 +223,103 @@ public class FirewallRule implements Comparable<FirewallRule> {
         // if this is not an ARP rule but the pkt is ARP,
         // return false match - no need to continue protocol specific check
         if (wildcard_dl_type == false) {
-            if (dl_type.equals(EthType.ARP)) {
-                if (packet.getEtherType() != EthType.ARP.getValue())
+            if (dl_type == Ethernet.TYPE_ARP) {
+                if (packet.getEtherType() != Ethernet.TYPE_ARP)
                     return false;
                 else {
                     if (action == FirewallRule.FirewallAction.DENY) {
-                        //wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
-                        wildcards.drop.setExact(MatchField.ETH_TYPE, this.dl_type);
+                        wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
                     } else {
-                        //wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
-                        wildcards.allow.setExact(MatchField.ETH_TYPE, this.dl_type);
+                        wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
                     }
                 }
-            } else if (dl_type.equals(EthType.IPv4)) {
-                if (packet.getEtherType() != EthType.IPv4.getValue())
+            } else if (dl_type == Ethernet.TYPE_IPv4) {
+                if (packet.getEtherType() != Ethernet.TYPE_IPv4)
                     return false;
                 else {
                     if (action == FirewallRule.FirewallAction.DENY) {
-                        //wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
-                        wildcards.drop.setExact(MatchField.IP_PROTO, this.nw_proto);
+                        wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
                     } else {
-                        //wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
-                        wildcards.allow.setExact(MatchField.IP_PROTO, this.nw_proto);
+                        wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
                     }
                     // IP packets, proceed with ip address check
                     pkt_ip = (IPv4) pkt;
 
                     // IP addresses (src and dst) match?
-                    if (wildcard_nw_src == false && this.matchIPAddress(nw_src_prefix_and_mask.getValue().getInt(), nw_src_prefix_and_mask.getMask().getInt(), pkt_ip.getSourceAddress()) == false)
+                    if (wildcard_nw_src == false
+                            && this.matchIPAddress(nw_src_prefix,
+                                    nw_src_maskbits, pkt_ip.getSourceAddress()) == false)
                         return false;
                     if (action == FirewallRule.FirewallAction.DENY) {
-                        //wildcards.drop &= ~OFMatch.OFPFW_NW_SRC_ALL;
-                        //wildcards.drop |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT);
-                    	wildcards.drop.setMasked(MatchField.IPV4_SRC, nw_src_prefix_and_mask);
+                        wildcards.drop &= ~OFMatch.OFPFW_NW_SRC_ALL;
+                        wildcards.drop |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT);
                     } else {
-                        //wildcards.allow &= ~OFMatch.OFPFW_NW_SRC_ALL;
-                        //wildcards.allow |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT);
-                    	wildcards.allow.setMasked(MatchField.IPV4_SRC, nw_src_prefix_and_mask);
+                        wildcards.allow &= ~OFMatch.OFPFW_NW_SRC_ALL;
+                        wildcards.allow |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT);
                     }
 
-                    if (wildcard_nw_dst == false && this.matchIPAddress(nw_dst_prefix_and_mask.getValue().getInt(), nw_dst_prefix_and_mask.getMask().getInt(), pkt_ip.getDestinationAddress()) == false)
+                    if (wildcard_nw_dst == false
+                            && this.matchIPAddress(nw_dst_prefix,
+                                    nw_dst_maskbits,
+                                    pkt_ip.getDestinationAddress()) == false)
                         return false;
                     if (action == FirewallRule.FirewallAction.DENY) {
-                        //wildcards.drop &= ~OFMatch.OFPFW_NW_DST_ALL;
-                        //wildcards.drop |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT);
-                    	wildcards.drop.setMasked(MatchField.IPV4_DST, nw_dst_prefix_and_mask);
+                        wildcards.drop &= ~OFMatch.OFPFW_NW_DST_ALL;
+                        wildcards.drop |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT);
                     } else {
-                        //wildcards.allow &= ~OFMatch.OFPFW_NW_DST_ALL;
-                        //wildcards.allow |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT);
-                    	wildcards.allow.setMasked(MatchField.IPV4_DST, nw_dst_prefix_and_mask);
+                        wildcards.allow &= ~OFMatch.OFPFW_NW_DST_ALL;
+                        wildcards.allow |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT);
                     }
 
                     // nw_proto check
                     if (wildcard_nw_proto == false) {
-                        if (nw_proto.equals(IpProtocol.TCP)) {
-                            if ((short) pkt_ip.getProtocol() != IpProtocol.TCP.getIpProtocolNumber())
+                        if (nw_proto == IPv4.PROTOCOL_TCP) {
+                            if (pkt_ip.getProtocol() != IPv4.PROTOCOL_TCP)
                                 return false;
                             else {
                                 pkt_tcp = (TCP) pkt_ip.getPayload();
                                 pkt_tp_src = pkt_tcp.getSourcePort();
                                 pkt_tp_dst = pkt_tcp.getDestinationPort();
                             }
-                        } else if (nw_proto.equals(IpProtocol.UDP)) {
-                            if ((short) pkt_ip.getProtocol() != IpProtocol.UDP.getIpProtocolNumber())
+                        } else if (nw_proto == IPv4.PROTOCOL_UDP) {
+                            if (pkt_ip.getProtocol() != IPv4.PROTOCOL_UDP)
                                 return false;
                             else {
                                 pkt_udp = (UDP) pkt_ip.getPayload();
                                 pkt_tp_src = pkt_udp.getSourcePort();
                                 pkt_tp_dst = pkt_udp.getDestinationPort();
                             }
-                        } else if (nw_proto.equals(IpProtocol.ICMP)) {
-                            if ((short) pkt_ip.getProtocol() != IpProtocol.ICMP.getIpProtocolNumber())
+                        } else if (nw_proto == IPv4.PROTOCOL_ICMP) {
+                            if (pkt_ip.getProtocol() != IPv4.PROTOCOL_ICMP)
                                 return false;
                             else {
                                 // nothing more needed for ICMP
                             }
                         }
                         if (action == FirewallRule.FirewallAction.DENY) {
-                            //wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
-                            wildcards.drop.setExact(MatchField.IP_PROTO, this.nw_proto);
+                            wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
                         } else {
-                            //wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
-                            wildcards.allow.setExact(MatchField.IP_PROTO, this.nw_proto);
+                            wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
                         }
 
                         // TCP/UDP source and destination ports match?
                         if (pkt_tcp != null || pkt_udp != null) {
                             // does the source port match?
-                            if (tp_src.getPort() != 0 && tp_src.getPort() != pkt_tp_src)
+                            if (tp_src != 0 && tp_src != pkt_tp_src)
                                 return false;
                             if (action == FirewallRule.FirewallAction.DENY) {
-                                //wildcards.drop &= ~OFMatch.OFPFW_TP_SRC;
-                                if (pkt_tcp != null) {
-                                	wildcards.drop.setExact(MatchField.TCP_SRC, this.tp_src);
-                                } else {
-                                	wildcards.drop.setExact(MatchField.UDP_SRC, this.tp_src);   
-                                }
+                                wildcards.drop &= ~OFMatch.OFPFW_TP_SRC;
                             } else {
-                                //wildcards.allow &= ~OFMatch.OFPFW_TP_SRC;
-                                if (pkt_tcp != null) {
-                                	wildcards.allow.setExact(MatchField.TCP_SRC, this.tp_src);
-                                } else {
-                                	wildcards.allow.setExact(MatchField.UDP_SRC, this.tp_src);   
-                                }
+                                wildcards.allow &= ~OFMatch.OFPFW_TP_SRC;
                             }
 
                             // does the destination port match?
-                            if (tp_dst.getPort() != 0 && tp_dst.getPort() != pkt_tp_dst)
+                            if (tp_dst != 0 && tp_dst != pkt_tp_dst)
                                 return false;
                             if (action == FirewallRule.FirewallAction.DENY) {
-                                //wildcards.drop &= ~OFMatch.OFPFW_TP_DST;
-                                if (pkt_tcp != null) {
-                                	wildcards.drop.setExact(MatchField.TCP_DST, this.tp_dst);
-                                } else {
-                                	wildcards.drop.setExact(MatchField.UDP_DST, this.tp_dst);   
-                                }
+                                wildcards.drop &= ~OFMatch.OFPFW_TP_DST;
                             } else {
-                                //wildcards.allow &= ~OFMatch.OFPFW_TP_DST;
-                            	if (pkt_tcp != null) {
-                                	wildcards.allow.setExact(MatchField.TCP_DST, this.tp_dst);
-                                } else {
-                                	wildcards.allow.setExact(MatchField.UDP_DST, this.tp_dst);   
-                                }
+                                wildcards.allow &= ~OFMatch.OFPFW_TP_DST;
                             }
                         }
                     }
@@ -368,11 +331,9 @@ public class FirewallRule implements Comparable<FirewallRule> {
             }
         }
         if (action == FirewallRule.FirewallAction.DENY) {
-            //wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
-        	wildcards.drop.setExact(MatchField.ETH_TYPE, this.dl_type);
+            wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
         } else {
-            //wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
-        	wildcards.allow.setExact(MatchField.ETH_TYPE, this.dl_type);
+            wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
         }
 
         // all applicable checks passed
@@ -421,18 +382,18 @@ public class FirewallRule implements Comparable<FirewallRule> {
     public int hashCode() {
         final int prime = 2521;
         int result = super.hashCode();
-        result = prime * result + (int) dpid.getLong();
-        result = prime * result + in_port.getPortNumber();
-        result = prime * result + (int) dl_src.getLong();
-        result = prime * result + (int) dl_dst.getLong();
-        result = prime * result + dl_type.getValue();
-        result = prime * result + nw_src_prefix_and_mask.getValue().getInt();
-        result = prime * result + nw_src_prefix_and_mask.getMask().getInt();
-        result = prime * result + nw_dst_prefix_and_mask.getValue().getInt();
-        result = prime * result + nw_dst_prefix_and_mask.getMask().getInt();
-        result = prime * result + nw_proto.getIpProtocolNumber();
-        result = prime * result + tp_src.getPort();
-        result = prime * result + tp_dst.getPort();
+        result = prime * result + (int) dpid;
+        result = prime * result + in_port;
+        result = prime * result + (int) dl_src;
+        result = prime * result + (int) dl_dst;
+        result = prime * result + dl_type;
+        result = prime * result + nw_src_prefix;
+        result = prime * result + nw_src_maskbits;
+        result = prime * result + nw_dst_prefix;
+        result = prime * result + nw_dst_maskbits;
+        result = prime * result + nw_proto;
+        result = prime * result + tp_src;
+        result = prime * result + tp_dst;
         result = prime * result + action.ordinal();
         result = prime * result + priority;
         result = prime * result + (new Boolean(wildcard_dpid)).hashCode();
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java
index 42cb2727f79e3403d0b1ddd0d777468a07092627..3180968d1dd1786ef183933bc8584a5b896b123d 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java
@@ -19,10 +19,14 @@ package net.floodlightcontroller.firewall;
 
 import java.io.IOException;
 
+import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.util.MACAddress;
+
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
+import org.openflow.util.HexString;
 
 /**
  * Serialize a FirewallRule object
@@ -38,18 +42,18 @@ public class FirewallRuleSerializer extends JsonSerializer<FirewallRule> {
         jGen.writeStartObject();
         
         jGen.writeNumberField("ruleid", rule.ruleid);
-        jGen.writeStringField("dpid", rule.dpid.toString());
-        jGen.writeNumberField("in_port", rule.in_port.getPortNumber());
-        jGen.writeStringField("dl_src", rule.dl_src.toString());
-        jGen.writeStringField("dl_dst", rule.dl_dst.toString());
-        jGen.writeNumberField("dl_type", rule.dl_type.getValue());
-        jGen.writeStringField("nw_src_prefix", rule.nw_src_prefix_and_mask.getValue().toString());
-        jGen.writeNumberField("nw_src_maskbits", rule.nw_src_prefix_and_mask.getMask().asCidrMaskLength());
-        jGen.writeStringField("nw_dst_prefix", rule.nw_dst_prefix_and_mask.getValue().toString());
-        jGen.writeNumberField("nw_dst_maskbits", rule.nw_dst_prefix_and_mask.getMask().asCidrMaskLength());
-        jGen.writeNumberField("nw_proto", rule.nw_proto.getIpProtocolNumber());
-        jGen.writeNumberField("tp_src", rule.tp_src.getPort());
-        jGen.writeNumberField("tp_dst", rule.tp_dst.getPort());
+        jGen.writeStringField("dpid", HexString.toHexString(rule.dpid));
+        jGen.writeNumberField("in_port", rule.in_port);
+        jGen.writeStringField("dl_src",String.valueOf(MACAddress.valueOf(rule.dl_src)));
+        jGen.writeStringField("dl_dst", String.valueOf(MACAddress.valueOf(rule.dl_dst)));
+        jGen.writeNumberField("dl_type", rule.dl_type);
+        jGen.writeStringField("nw_src_prefix", IPv4.fromIPv4Address(rule.nw_src_prefix));
+        jGen.writeNumberField("nw_src_maskbits", rule.nw_src_maskbits);
+        jGen.writeStringField("nw_dst_prefix", IPv4.fromIPv4Address(rule.nw_dst_prefix));
+        jGen.writeNumberField("nw_dst_maskbits", rule.nw_dst_maskbits);
+        jGen.writeNumberField("nw_proto", rule.nw_proto);
+        jGen.writeNumberField("tp_src", rule.tp_src);
+        jGen.writeNumberField("tp_dst", rule.tp_dst);
         jGen.writeBooleanField("wildcard_dpid", rule.wildcard_dpid);
         jGen.writeBooleanField("wildcard_in_port", rule.wildcard_in_port);
         jGen.writeBooleanField("wildcard_dl_src", rule.wildcard_dl_src);
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
index 27e40d3ffecebecc8b268125ee0441cf7ea8348c..7af219cc63f70879eda9cdd5ab7971b1a3111cea 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
@@ -25,14 +25,7 @@ import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.JsonToken;
 import com.fasterxml.jackson.databind.MappingJsonFactory;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.EthType;
-import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
-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.openflow.util.HexString;
 import org.restlet.resource.Delete;
 import org.restlet.resource.Post;
 import org.restlet.resource.Get;
@@ -40,6 +33,7 @@ import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
 
 public class FirewallRulesResource extends ServerResource {
@@ -172,13 +166,13 @@ public class FirewallRulesResource extends ServerResource {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("-1") == false) {
                     // user inputs hex format dpid
-                    rule.dpid = DatapathId.of(tmp);
+                    rule.dpid = HexString.toLong(tmp);
                     rule.wildcard_dpid = false;
                 }
             }
 
             else if (n == "src-inport") {
-                rule.in_port = OFPort.of(Integer.parseInt(jp.getText()));
+                rule.in_port = Short.parseShort(jp.getText());
                 rule.wildcard_in_port = false;
             }
 
@@ -186,7 +180,7 @@ public class FirewallRulesResource extends ServerResource {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("ANY") == false) {
                     rule.wildcard_dl_src = false;
-                    rule.dl_src = MacAddress.of(tmp);
+                    rule.dl_src = Ethernet.toLong(Ethernet.toMACAddress(tmp));
                 }
             }
 
@@ -194,7 +188,7 @@ public class FirewallRulesResource extends ServerResource {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("ANY") == false) {
                     rule.wildcard_dl_dst = false;
-                    rule.dl_dst = MacAddress.of(tmp);
+                    rule.dl_dst = Ethernet.toLong(Ethernet.toMACAddress(tmp));
                 }
             }
 
@@ -202,11 +196,11 @@ public class FirewallRulesResource extends ServerResource {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("ARP")) {
                     rule.wildcard_dl_type = false;
-                    rule.dl_type = EthType.ARP;
+                    rule.dl_type = Ethernet.TYPE_ARP;
                 }
                 if (tmp.equalsIgnoreCase("IPv4")) {
                     rule.wildcard_dl_type = false;
-                    rule.dl_type = EthType.IPv4;
+                    rule.dl_type = Ethernet.TYPE_IPv4;
                 }
             }
 
@@ -215,8 +209,10 @@ public class FirewallRulesResource extends ServerResource {
                 if (tmp.equalsIgnoreCase("ANY") == false) {
                     rule.wildcard_nw_src = false;
                     rule.wildcard_dl_type = false;
-                    rule.dl_type = EthType.IPv4;
-                    rule.nw_src_prefix_and_mask = IPv4AddressWithMask.of(tmp);
+                    rule.dl_type = Ethernet.TYPE_IPv4;
+                    int[] cidr = IPCIDRToPrefixBits(tmp);
+                    rule.nw_src_prefix = cidr[0];
+                    rule.nw_src_maskbits = cidr[1];
                 }
             }
 
@@ -225,8 +221,10 @@ public class FirewallRulesResource extends ServerResource {
                 if (tmp.equalsIgnoreCase("ANY") == false) {
                     rule.wildcard_nw_dst = false;
                     rule.wildcard_dl_type = false;
-                    rule.dl_type = EthType.IPv4;
-                    rule.nw_dst_prefix_and_mask = IPv4AddressWithMask.of(tmp);
+                    rule.dl_type = Ethernet.TYPE_IPv4;
+                    int[] cidr = IPCIDRToPrefixBits(tmp);
+                    rule.nw_dst_prefix = cidr[0];
+                    rule.nw_dst_maskbits = cidr[1];
                 }
             }
 
@@ -234,30 +232,30 @@ public class FirewallRulesResource extends ServerResource {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("TCP")) {
                     rule.wildcard_nw_proto = false;
-                    rule.nw_proto = IpProtocol.TCP;
+                    rule.nw_proto = IPv4.PROTOCOL_TCP;
                     rule.wildcard_dl_type = false;
-                    rule.dl_type = EthType.IPv4;
+                    rule.dl_type = Ethernet.TYPE_IPv4;
                 } else if (tmp.equalsIgnoreCase("UDP")) {
                     rule.wildcard_nw_proto = false;
-                    rule.nw_proto = IpProtocol.UDP;
+                    rule.nw_proto = IPv4.PROTOCOL_UDP;
                     rule.wildcard_dl_type = false;
-                    rule.dl_type = EthType.IPv4;
+                    rule.dl_type = Ethernet.TYPE_IPv4;
                 } else if (tmp.equalsIgnoreCase("ICMP")) {
                     rule.wildcard_nw_proto = false;
-                    rule.nw_proto = IpProtocol.ICMP;
+                    rule.nw_proto = IPv4.PROTOCOL_ICMP;
                     rule.wildcard_dl_type = false;
-                    rule.dl_type = EthType.IPv4;
+                    rule.dl_type = Ethernet.TYPE_IPv4;
                 }
             }
 
             else if (n == "tp-src") {
                 rule.wildcard_tp_src = false;
-                rule.tp_src = TransportPort.of(Integer.parseInt(jp.getText()));
+                rule.tp_src = Short.parseShort(jp.getText());
             }
 
             else if (n == "tp-dst") {
                 rule.wildcard_tp_dst = false;
-                rule.tp_dst = TransportPort.of(Integer.parseInt(jp.getText()));
+                rule.tp_dst = Short.parseShort(jp.getText());
             }
 
             else if (n == "priority") {
diff --git a/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java b/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java
index 114dc3eee332c005030152b69141873e1a7371b8..d2aa2e5ff458b4fdef9c00bb4544e9851df3fe5c 100644
--- a/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java
+++ b/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java
@@ -17,9 +17,9 @@
 
 package net.floodlightcontroller.firewall;
 
-import org.projectfloodlight.openflow.protocol.match.Match;
+import org.openflow.protocol.OFMatch;
 
 public class RuleWildcardsPair {
     public FirewallRule rule;
-    public Match.Builder wildcards;
+    public int wildcards = OFMatch.OFPFW_ALL;
 }
diff --git a/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java b/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java
index f6443c403e1de021319e84869b8f07f911e48f21..db4cf7441a11de5931a7b9b2db4205a9d66c54e6 100644
--- a/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java
+++ b/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java
@@ -17,12 +17,9 @@
 
 package net.floodlightcontroller.firewall;
 
-import org.projectfloodlight.openflow.protocol.match.Match;
-
+import org.openflow.protocol.OFMatch;
 
 public class WildcardsPair {
-    //public int allow = OFMatch.OFPFW_ALL;
-    //public int drop = OFMatch.OFPFW_ALL;
-    public Match.Builder allow;
-    public Match.Builder drop;
+    public int allow = OFMatch.OFPFW_ALL;
+    public int drop = OFMatch.OFPFW_ALL;
 }
diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
index 40fc77bcf04734639005148fc7c98a81ea555f9a..588e8bc3123336bf3fa7bab8a421e5ce17ff456c 100644
--- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
@@ -33,7 +33,6 @@ import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.core.annotations.LogMessageCategory;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
 import net.floodlightcontroller.core.annotations.LogMessageDocs;
-import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -41,30 +40,20 @@ import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.util.AppCookie;
 import net.floodlightcontroller.counter.ICounterStoreService;
 import net.floodlightcontroller.packet.Ethernet;
-import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.routing.ForwardingBase;
 import net.floodlightcontroller.routing.IRoutingDecision;
 import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.Route;
 import net.floodlightcontroller.topology.ITopologyService;
 
-import org.projectfloodlight.openflow.protocol.OFFlowMod;
-import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
-import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.protocol.match.MatchField;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.OFVlanVidMatch;
-import org.projectfloodlight.openflow.types.VlanVid;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFPort;
+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;
 
@@ -172,29 +161,24 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
     protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi,
                                  FloodlightContext cntx,
                                  boolean requestFlowRemovedNotifn) {
-        //OFMatch match = new OFMatch();
-        //match.loadFromPacket(pi.getData(), pi.getInPort());
-        //Match.Builder matchBuilder = sw.getOFFactory().buildMatch();
-        Match match = pi.getMatch();
+        OFMatch match = new OFMatch();
+        match.loadFromPacket(pi.getPacketData(), pi.getInPort());
+
         // Check if we have the location of the destination
         IDevice dstDevice =
                 IDeviceService.fcStore.
                     get(cntx, IDeviceService.CONTEXT_DST_DEVICE);
 
-        // DESTINATION DEVICE = KNOWN
         if (dstDevice != null) {
             IDevice srcDevice =
                     IDeviceService.fcStore.
                         get(cntx, IDeviceService.CONTEXT_SRC_DEVICE);
-            DatapathId srcIsland = topology.getL2DomainId(sw.getId());
+            Long srcIsland = topology.getL2DomainId(sw.getId());
 
-            // If we can't find the source device, that's no good
             if (srcDevice == null) {
                 log.debug("No device entry found for source device");
                 return;
             }
-            
-            // If the source isn't connected to an OF island we control, then that's not good either
             if (srcIsland == null) {
                 log.debug("No openflow island found for source {}/{}",
                           sw.getStringId(), pi.getInPort());
@@ -202,24 +186,24 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
             }
 
             // Validate that we have a destination known on the same island
-            // Validate that the source and destination are not on the same switch port
+            // Validate that the source and destination are not on the same switchport
             boolean on_same_island = false;
             boolean on_same_if = false;
             for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) {
-                DatapathId dstSwDpid = dstDap.getSwitchDPID();
-                DatapathId dstIsland = topology.getL2DomainId(dstSwDpid);
+                long dstSwDpid = dstDap.getSwitchDPID();
+                Long dstIsland = topology.getL2DomainId(dstSwDpid);
                 if ((dstIsland != null) && dstIsland.equals(srcIsland)) {
                     on_same_island = true;
-                    if ((sw.getId().equals(dstSwDpid)) &&
-                        (pi.getInPort().equals(dstDap.getPort()))) {
+                    if ((sw.getId() == dstSwDpid) &&
+                        (pi.getInPort() == dstDap.getPort())) {
                         on_same_if = true;
                     }
                     break;
                 }
             }
 
-            // If the two devices are not on the same L2 network, find out how to get to the destination via flooding
             if (!on_same_island) {
+                // Flood since we don't know the dst device
                 if (log.isTraceEnabled()) {
                     log.trace("No first hop island found for destination " +
                               "device {}, Action = flooding", dstDevice);
@@ -228,7 +212,6 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
                 return;
             }
 
-            // If the two devices are on the same switch port number, they should be able to communicate w/o further flows
             if (on_same_if) {
                 if (log.isTraceEnabled()) {
                     log.trace("Both source and destination are on the same " +
@@ -254,9 +237,9 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
 
                 // srcCluster and dstCluster here cannot be null as
                 // every switch will be at least in its own L2 domain.
-                DatapathId srcCluster =
+                Long srcCluster =
                         topology.getL2DomainId(srcDap.getSwitchDPID());
-                DatapathId dstCluster =
+                Long dstCluster =
                         topology.getL2DomainId(dstDap.getSwitchDPID());
 
                 int srcVsDest = srcCluster.compareTo(dstCluster);
@@ -264,9 +247,9 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
                     if (!srcDap.equals(dstDap)) {
                         Route route =
                                 routingEngine.getRoute(srcDap.getSwitchDPID(),
-                                                       srcDap.getPort(),
+                                                       (short)srcDap.getPort(),
                                                        dstDap.getSwitchDPID(),
-                                                       dstDap.getPort(), 0); //cookie = 0, i.e., default route
+                                                       (short)dstDap.getPort(), 0); //cookie = 0, i.e., default route
                         if (route != null) {
                             if (log.isTraceEnabled()) {
                                 log.trace("pushRoute match={} route={} " +
@@ -279,7 +262,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
                                     AppCookie.makeCookie(FORWARDING_APP_ID, 0);
 
                             // if there is prior routing decision use wildcard
-                            Match.Builder wildcard_hints;
+                            Integer wildcard_hints = null;
                             IRoutingDecision decision = null;
                             if (cntx != null) {
                                 decision = IRoutingDecision.rtStore
@@ -290,7 +273,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
                                 wildcard_hints = decision.getWildcards();
                             } else {
                             	// L2 only wildcard if there is no prior route decision
-                                /*wildcard_hints = ((Integer) sw
+                                wildcard_hints = ((Integer) sw
                                         .getAttribute(IOFSwitch.PROP_FASTWILDCARDS))
                                         .intValue()
                                         & ~OFMatch.OFPFW_IN_PORT
@@ -298,21 +281,12 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
                                         & ~OFMatch.OFPFW_DL_SRC
                                         & ~OFMatch.OFPFW_DL_DST
                                         & ~OFMatch.OFPFW_NW_SRC_MASK
-                                        & ~OFMatch.OFPFW_NW_DST_MASK;*/
-                            	//TODO @Ryan does the use of NO_MASK here automatically assume isFullyWildcarded is true?
-                            	// dummy values set to not trigger isFullyWildcarded
-                            	wildcard_hints = sw.getOFFactory().buildMatch();
-                                wildcard_hints.setExact(MatchField.IN_PORT, OFPort.of(1));
-                                wildcard_hints.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(1));
-                                wildcard_hints.setExact(MatchField.ETH_SRC, MacAddress.BROADCAST);
-                                wildcard_hints.setExact(MatchField.ETH_DST, MacAddress.BROADCAST);
-                                wildcard_hints.setExact(MatchField.IPV4_SRC, IPv4Address.FULL_MASK);
-                                wildcard_hints.setExact(MatchField.IPV4_DST, IPv4Address.FULL_MASK);
+                                        & ~OFMatch.OFPFW_NW_DST_MASK;
                             }
 
                             pushRoute(route, match, wildcard_hints, pi, sw.getId(), cookie,
                                       cntx, requestFlowRemovedNotifn, false,
-                                      OFFlowModCommand.ADD);
+                                      OFFlowMod.OFPFC_ADD);
                         }
                     }
                     iSrcDaps++;
@@ -323,9 +297,8 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
                     iDstDaps++;
                 }
             }
-        // END DESTINATION DEVICE = KNOWN
         } else {
-        	// DESTINATION DEVICE = UNKNOWN, thus flood to hopefully/eventually find out where the destination is
+            // Flood since we don't know the dst device
             doFlood(sw, pi, cntx);
         }
     }
@@ -412,7 +385,6 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
         Collection<Class<? extends IFloodlightService>> l =
                 new ArrayList<Class<? extends IFloodlightService>>();
         l.add(IFloodlightProviderService.class);
-        l.add(IOFSwitchService.class);
         l.add(IDeviceService.class);
         l.add(IRoutingService.class);
         l.add(ITopologyService.class);
@@ -440,7 +412,6 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
     public void init(FloodlightModuleContext context) throws FloodlightModuleException {
         super.init();
         this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-        this.switchService = context.getServiceImpl(IOFSwitchService.class);
         this.deviceManager = context.getServiceImpl(IDeviceService.class);
         this.routingEngine = context.getServiceImpl(IRoutingService.class);
         this.topology = context.getServiceImpl(ITopologyService.class);
diff --git a/src/main/java/net/floodlightcontroller/hub/Hub.java b/src/main/java/net/floodlightcontroller/hub/Hub.java
index e683fa917443d2c7abe24a3b331f13ecbce0fbfb..4a3549ba47224cc0b8a7821798f589d61fbabb52 100644
--- a/src/main/java/net/floodlightcontroller/hub/Hub.java
+++ b/src/main/java/net/floodlightcontroller/hub/Hub.java
@@ -17,6 +17,7 @@
 
 package net.floodlightcontroller.hub;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -26,20 +27,19 @@ import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.LogicalOFMessageCategory;
 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 org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
-import org.projectfloodlight.openflow.types.OFBufferId;
-import org.projectfloodlight.openflow.types.OFPort;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionOutput;
+import org.openflow.util.U16;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -64,24 +64,34 @@ public class Hub implements IFloodlightModule, IOFMessageListener {
         return Hub.class.getPackage().getName();
     }
 
-    //TODO @Ryan this is a good example (my first try) at using the builders. Might be good reference later.
     public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
         OFPacketIn pi = (OFPacketIn) msg;
-        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
-        pob.setBufferId(pi.getBufferId()).setInPort(pi.getInPort());
+        OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory()
+                .getMessage(OFType.PACKET_OUT);
+        po.setBufferId(pi.getBufferId())
+            .setInPort(pi.getInPort());
 
         // set actions
-        OFActionOutput.Builder actionBuilder = sw.getOFFactory().actions().buildOutput();
-            actionBuilder.setPort(OFPort.FLOOD);
-        pob.setActions(Collections.singletonList((OFAction) actionBuilder.build()));
-        // pob.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); @Ryan setting of lengths is taken care of now, I think
+        OFActionOutput action = new OFActionOutput()
+            .setPort(OFPort.OFPP_FLOOD.getValue());
+        po.setActions(Collections.singletonList((OFAction)action));
+        po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
 
         // set data if is is included in the packetin
-        if (pi.getBufferId() == OFBufferId.NO_BUFFER) {
-            byte[] packetData = pi.getData();
-            pob.setData(packetData);
+        if (pi.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
+            byte[] packetData = pi.getPacketData();
+            po.setLength(U16.t(OFPacketOut.MINIMUM_LENGTH
+                    + po.getActionsLength() + packetData.length));
+            po.setPacketData(packetData);
+        } else {
+            po.setLength(U16.t(OFPacketOut.MINIMUM_LENGTH
+                    + po.getActionsLength()));
+        }
+        try {
+            sw.write(po, cntx);
+        } catch (IOException e) {
+            log.error("Failure writing PacketOut", e);
         }
-        sw.write(pob.build(), LogicalOFMessageCategory.MAIN);
 
         return Command.CONTINUE;
     }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java
index 5025d8d6981d8c5002477a0c754de4932fb0232a..e4e109ca46fea5d8605109aea8f497c6300edcb6 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java
@@ -18,9 +18,7 @@ package net.floodlightcontroller.linkdiscovery;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
+import org.openflow.util.HexString;
 
 public interface ILinkDiscovery {
 
@@ -47,16 +45,16 @@ public interface ILinkDiscovery {
     }
 
     public class LDUpdate {
-        protected DatapathId src;
-        protected OFPort srcPort;
-        protected DatapathId dst;
-        protected OFPort dstPort;
+        protected long src;
+        protected short srcPort;
+        protected long dst;
+        protected short dstPort;
         protected SwitchType srcType;
         protected LinkType type;
         protected UpdateOperation operation;
 
-        public LDUpdate(DatapathId src, OFPort srcPort,
-        		DatapathId dst, OFPort dstPort,
+        public LDUpdate(long src, short srcPort,
+                      long dst, short dstPort,
                       ILinkDiscovery.LinkType type,
                       UpdateOperation operation) {
             this.src = src;
@@ -78,32 +76,32 @@ public interface ILinkDiscovery {
         }
 
         // For updtedSwitch(sw)
-        public LDUpdate(DatapathId switchId, SwitchType stype, UpdateOperation oper ){
+        public LDUpdate(long switchId, SwitchType stype, UpdateOperation oper ){
             this.operation = oper;
             this.src = switchId;
             this.srcType = stype;
         }
 
         // For port up or port down; and tunnel port added and removed.
-        public LDUpdate(DatapathId sw, OFPort port, UpdateOperation operation) {
+        public LDUpdate(long sw, short port, UpdateOperation operation) {
             this.src = sw;
             this.srcPort = port;
             this.operation = operation;
         }
 
-        public DatapathId getSrc() {
+        public long getSrc() {
             return src;
         }
 
-        public OFPort getSrcPort() {
+        public short getSrcPort() {
             return srcPort;
         }
 
-        public DatapathId getDst() {
+        public long getDst() {
             return dst;
         }
 
-        public OFPort getDstPort() {
+        public short getDstPort() {
             return dstPort;
         }
 
@@ -129,20 +127,20 @@ public interface ILinkDiscovery {
             case LINK_REMOVED:
             case LINK_UPDATED:
                 return "LDUpdate [operation=" + operation +
-                        ", src=" + src.toString()
-                        + ", srcPort=" + srcPort.toString()
-                        + ", dst=" + dst.toString()
-                        + ", dstPort=" + dstPort.toString()
+                        ", src=" + HexString.toHexString(src)
+                        + ", srcPort=" + srcPort
+                        + ", dst=" + HexString.toHexString(dst) 
+                        + ", dstPort=" + dstPort
                         + ", type=" + type + "]";
             case PORT_DOWN:
             case PORT_UP:
                 return "LDUpdate [operation=" + operation +
-                        ", src=" + src.toString()
-                        + ", srcPort=" + srcPort.toString() + "]";
+                        ", src=" + HexString.toHexString(src)
+                        + ", srcPort=" + srcPort + "]";
             case SWITCH_REMOVED:
             case SWITCH_UPDATED:
                 return "LDUpdate [operation=" + operation +
-                        ", src=" + src.toString() + "]";
+                        ", src=" + HexString.toHexString(src) + "]";
             default:
                 return "LDUpdate: Unknown update.";
             }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
index 2bb53727917ffba3b4138bf3d06a9e56b79db1f2..3773efd713b992755e093bd50dfdaf85317114a0 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
@@ -20,10 +20,7 @@ package net.floodlightcontroller.linkdiscovery;
 import java.util.Map;
 import java.util.Set;
 
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFPort;
+import org.openflow.protocol.OFPacketOut;
 
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.routing.Link;
@@ -35,7 +32,7 @@ public interface ILinkDiscoveryService extends IFloodlightService {
     /**
      * Returns if a given switchport is a tunnel endpoint or not
      */
-    public boolean isTunnelPort(DatapathId sw, OFPort port);
+    public boolean isTunnelPort(long sw, short port);
 
     /**
      * Retrieves a map of all known link connections between OpenFlow switches
@@ -62,7 +59,7 @@ public interface ILinkDiscoveryService extends IFloodlightService {
      * to switchport (sw, port). PacketOut does not contain actions.
      * PacketOut length includes the minimum length and data length.
      */
-    public OFPacketOut generateLLDPMessage(DatapathId sw, OFPort port,
+    public OFPacketOut generateLLDPMessage(long sw, short port,
                                            boolean isStandard,
                                            boolean isReverse);
 
@@ -70,7 +67,7 @@ public interface ILinkDiscoveryService extends IFloodlightService {
      * Returns an unmodifiable map from switch id to a set of all links with it
      * as an endpoint.
      */
-    public Map<DatapathId, Set<Link>> getSwitchLinks();
+    public Map<Long, Set<Link>> getSwitchLinks();
 
     /**
      * Adds a listener to listen for ILinkDiscoveryService messages
@@ -87,17 +84,17 @@ public interface ILinkDiscoveryService extends IFloodlightService {
      * Adds a switch port to suppress lldp set. LLDPs and BDDPs will not be sent
      * out, and if any are received on this port then they will be dropped.
      */
-    public void AddToSuppressLLDPs(DatapathId sw, OFPort port);
+    public void AddToSuppressLLDPs(long sw, short port);
 
     /**
      * Removes a switch port from suppress lldp set
      */
-    public void RemoveFromSuppressLLDPs(DatapathId sw, OFPort port);
+    public void RemoveFromSuppressLLDPs(long sw, short port);
 
     /**
      * Get the set of quarantined ports on a switch
      */
-    public Set<OFPort> getQuarantinedPorts(DatapathId sw);
+    public Set<Short> getQuarantinedPorts(long sw);
 
     /**
      * Get the status of auto port fast feature.
@@ -129,5 +126,5 @@ public interface ILinkDiscoveryService extends IFloodlightService {
      *        ALL MAC addresses to the ignore list. This will cause a drop of
      *        ALL packet ins.
      */
-    public void addMACToIgnoreList(MacAddress mac, int ignoreBits);
+    public void addMACToIgnoreList(long mac, int ignoreBits);
 }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java b/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java
index 6c2d7334e436cabe3f44eca1547d4f1425c3d440..0230b3bbd31f8cb47581ff83f6b79f4632386560 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java
@@ -15,17 +15,15 @@
 
 package net.floodlightcontroller.linkdiscovery;
 
-import java.util.Date;
-
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
 public class LinkInfo {
 
-    public LinkInfo(Date firstSeenTime,
-                    Date lastLldpReceivedTime,
-                    Date lastBddpReceivedTime) {
+    public LinkInfo(Long firstSeenTime,
+                    Long lastLldpReceivedTime,
+                    Long lastBddpReceivedTime) {
         super();
         this.firstSeenTime = firstSeenTime;
         this.lastLldpReceivedTime = lastLldpReceivedTime;
@@ -48,9 +46,9 @@ public class LinkInfo {
         this.lastBddpReceivedTime = fromLinkInfo.getMulticastValidTime();
     }
 
-    protected Date firstSeenTime;
-    protected Date lastLldpReceivedTime; /* Standard LLLDP received time */
-    protected Date lastBddpReceivedTime; /* Modified LLDP received time  */
+    protected Long firstSeenTime;
+    protected Long lastLldpReceivedTime; /* Standard LLLDP received time */
+    protected Long lastBddpReceivedTime; /* Modified LLDP received time  */
 
     /** The port states stored here are topology's last knowledge of
      * the state of the port. This mostly mirrors the state
@@ -62,27 +60,27 @@ public class LinkInfo {
      * requires the new state to be written to storage.
      */
 
-    public Date getFirstSeenTime() {
+    public Long getFirstSeenTime() {
         return firstSeenTime;
     }
 
-    public void setFirstSeenTime(Date firstSeenTime) {
+    public void setFirstSeenTime(Long firstSeenTime) {
         this.firstSeenTime = firstSeenTime;
     }
 
-    public Date getUnicastValidTime() {
+    public Long getUnicastValidTime() {
         return lastLldpReceivedTime;
     }
 
-    public void setUnicastValidTime(Date unicastValidTime) {
+    public void setUnicastValidTime(Long unicastValidTime) {
         this.lastLldpReceivedTime = unicastValidTime;
     }
 
-    public Date getMulticastValidTime() {
+    public Long getMulticastValidTime() {
         return lastBddpReceivedTime;
     }
 
-    public void setMulticastValidTime(Date multicastValidTime) {
+    public void setMulticastValidTime(Long multicastValidTime) {
         this.lastBddpReceivedTime = multicastValidTime;
     }
 
@@ -149,8 +147,8 @@ public class LinkInfo {
      */
     @Override
     public String toString() {
-        return "LinkInfo [unicastValidTime=" + ((lastLldpReceivedTime == null) ? "null" : lastLldpReceivedTime.getTime())
-                + ", multicastValidTime=" + ((lastBddpReceivedTime == null) ? "null" : lastBddpReceivedTime.getTime())
+        return "LinkInfo [unicastValidTime=" + ((lastLldpReceivedTime == null) ? "null" : lastLldpReceivedTime)
+                + ", multicastValidTime=" + ((lastBddpReceivedTime == null) ? "null" : lastBddpReceivedTime)
                 + "]";
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/packet/BSNPROBE.java b/src/main/java/net/floodlightcontroller/packet/BSNPROBE.java
index 63f710e58748881ca2aabe1360e559448253fec8..c9115eacb5c22c459cbaded572a64063125118c6 100644
--- a/src/main/java/net/floodlightcontroller/packet/BSNPROBE.java
+++ b/src/main/java/net/floodlightcontroller/packet/BSNPROBE.java
@@ -21,7 +21,7 @@ package net.floodlightcontroller.packet;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.util.HexString;
 
 /**
  * @author Shudong Zhou (shudong.zhou@bigswitch.com)
diff --git a/src/main/java/net/floodlightcontroller/packet/Ethernet.java b/src/main/java/net/floodlightcontroller/packet/Ethernet.java
index d29b0859c64daff72d9d503c5bb866a422c5b67a..60887b3158e27a3d714927aab4f57b7085242164 100644
--- a/src/main/java/net/floodlightcontroller/packet/Ethernet.java
+++ b/src/main/java/net/floodlightcontroller/packet/Ethernet.java
@@ -22,8 +22,8 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.util.HexString;
+import net.floodlightcontroller.util.MACAddress;
+import org.openflow.util.HexString;
 
 /**
  *
@@ -49,8 +49,8 @@ public class Ethernet extends BasePacket {
         etherTypeClassMap.put(TYPE_BSN, BSN.class);
     }
 
-    protected MacAddress destinationMACAddress;
-    protected MacAddress sourceMACAddress;
+    protected MACAddress destinationMACAddress;
+    protected MACAddress sourceMACAddress;
     protected byte priorityCode;
     protected short vlanID;
     protected short etherType;
@@ -68,13 +68,13 @@ public class Ethernet extends BasePacket {
      * @return the destination MAC as a byte array
      */
     public byte[] getDestinationMACAddress() {
-        return destinationMACAddress.getBytes();
+        return destinationMACAddress.toBytes();
     }
     
     /**
      * @return the destination MAC
      */
-    public MacAddress getDestinationMAC() {
+    public MACAddress getDestinationMAC() {
         return destinationMACAddress;
     }
 
@@ -82,7 +82,7 @@ public class Ethernet extends BasePacket {
      * @param destinationMACAddress the destination MAC to set
      */
     public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) {
-        this.destinationMACAddress = MacAddress.of(destinationMACAddress);
+        this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
         return this;
     }
 
@@ -90,7 +90,7 @@ public class Ethernet extends BasePacket {
      * @param destinationMACAddress the destination MAC to set
      */
     public Ethernet setDestinationMACAddress(String destinationMACAddress) {
-        this.destinationMACAddress = MacAddress.of(destinationMACAddress);
+        this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
         return this;
     }
 
@@ -98,13 +98,13 @@ public class Ethernet extends BasePacket {
      * @return the source MACAddress as a byte array
      */
     public byte[] getSourceMACAddress() {
-        return sourceMACAddress.getBytes();
+        return sourceMACAddress.toBytes();
     }
     
     /**
      * @return the source MACAddress
      */
-    public MacAddress getSourceMAC() {
+    public MACAddress getSourceMAC() {
         return sourceMACAddress;
     }
 
@@ -112,7 +112,7 @@ public class Ethernet extends BasePacket {
      * @param sourceMACAddress the source MAC to set
      */
     public Ethernet setSourceMACAddress(byte[] sourceMACAddress) {
-        this.sourceMACAddress = MacAddress.of(sourceMACAddress);
+        this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
         return this;
     }
 
@@ -120,7 +120,7 @@ public class Ethernet extends BasePacket {
      * @param sourceMACAddress the source MAC to set
      */
     public Ethernet setSourceMACAddress(String sourceMACAddress) {
-        this.sourceMACAddress = MacAddress.of(sourceMACAddress);
+        this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
         return this;
     }
 
@@ -173,7 +173,7 @@ public class Ethernet extends BasePacket {
      * @return True if the Ethernet frame is broadcast, false otherwise
      */
     public boolean isBroadcast() {
-        assert(destinationMACAddress.getLength() == 6);
+        assert(destinationMACAddress.length() == 6);
         return destinationMACAddress.isBroadcast();
     }
     
@@ -213,8 +213,8 @@ public class Ethernet extends BasePacket {
         }
         byte[] data = new byte[length];
         ByteBuffer bb = ByteBuffer.wrap(data);
-        bb.put(destinationMACAddress.getBytes());
-        bb.put(sourceMACAddress.getBytes());
+        bb.put(destinationMACAddress.toBytes());
+        bb.put(sourceMACAddress.toBytes());
         if (vlanID != VLAN_UNTAGGED) {
             bb.putShort((short) 0x8100);
             bb.putShort((short) ((priorityCode << 13) | (vlanID & 0x0fff)));
@@ -234,16 +234,16 @@ public class Ethernet extends BasePacket {
             return null;
         ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
         if (this.destinationMACAddress == null)
-            this.destinationMACAddress = MacAddress.of(new byte[6]);
-        byte[] dstAddr = new byte[MacAddress.NONE.getLength()];
+            this.destinationMACAddress = MACAddress.valueOf(new byte[6]);
+        byte[] dstAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
         bb.get(dstAddr);
-        this.destinationMACAddress = MacAddress.of(dstAddr);
+        this.destinationMACAddress = MACAddress.valueOf(dstAddr);
 
         if (this.sourceMACAddress == null)
-            this.sourceMACAddress = MacAddress.of(new byte[6]);
-        byte[] srcAddr = new byte[MacAddress.NONE.getLength()];
+            this.sourceMACAddress = MACAddress.valueOf(new byte[6]);
+        byte[] srcAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
         bb.get(srcAddr);
-        this.sourceMACAddress = MacAddress.of(srcAddr);
+        this.sourceMACAddress = MACAddress.valueOf(srcAddr);
 
         short etherType = bb.getShort();
         if (etherType == (short) 0x8100) {
@@ -322,7 +322,7 @@ public class Ethernet extends BasePacket {
      * @return The macAddress as a byte array 
      */
     public static byte[] toMACAddress(String macAddress) {
-        return MacAddress.of(macAddress).getBytes();
+        return MACAddress.valueOf(macAddress).toBytes();
     }
 
 
@@ -333,7 +333,7 @@ public class Ethernet extends BasePacket {
      * @return a long containing the mac address bytes
      */
     public static long toLong(byte[] macAddress) {
-        return MacAddress.of(macAddress).getLong();
+        return MACAddress.valueOf(macAddress).toLong();
     }
 
     /**
@@ -342,7 +342,7 @@ public class Ethernet extends BasePacket {
      * @return the bytes of the mac address
      */
     public static byte[] toByteArray(long macAddress) {
-        return MacAddress.of(macAddress).getBytes();
+        return MACAddress.valueOf(macAddress).toBytes();
     }
     
     /* (non-Javadoc)
diff --git a/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java b/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java
index 0198d16a45863b9c89ce9b51aec59ddc4a787532..cc70487eb8497e4330b59f679196450a57e5559d 100644
--- a/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java
+++ b/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java
@@ -18,7 +18,7 @@ package net.floodlightcontroller.perfmon;
 
 import java.util.List;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFMessage;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IOFMessageListener;
diff --git a/src/main/java/net/floodlightcontroller/perfmon/NullPktInProcessingTime.java b/src/main/java/net/floodlightcontroller/perfmon/NullPktInProcessingTime.java
index c10bc93a67a665d270e520fcee7d0b0965335b11..51641ccc7651f80c7aec121763a3b04a7273b7b8 100644
--- a/src/main/java/net/floodlightcontroller/perfmon/NullPktInProcessingTime.java
+++ b/src/main/java/net/floodlightcontroller/perfmon/NullPktInProcessingTime.java
@@ -22,7 +22,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFMessage;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IOFMessageListener;
diff --git a/src/main/java/net/floodlightcontroller/perfmon/PktInProcessingTime.java b/src/main/java/net/floodlightcontroller/perfmon/PktInProcessingTime.java
index 9e754469d917481db367d2afb67e014866b28c1e..366721120e332de7eb700ed383b521c7afb1a116 100644
--- a/src/main/java/net/floodlightcontroller/perfmon/PktInProcessingTime.java
+++ b/src/main/java/net/floodlightcontroller/perfmon/PktInProcessingTime.java
@@ -37,8 +37,8 @@ import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.restserver.IRestApiService;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFType;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java b/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java
index 28ca79f843a5f4984ab25eb012e95141c062c2bb..0c3703c97f9b3f8f07002203a0a7946c776cf0e7 100644
--- a/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java
+++ b/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java
@@ -20,48 +20,48 @@ import java.util.HashMap;
 
 import net.floodlightcontroller.routing.Link;
 
-import org.projectfloodlight.openflow.types.DatapathId;
+import org.openflow.util.HexString;
 
 public class BroadcastTree {
-    protected HashMap<DatapathId, Link> links;
-    protected HashMap<DatapathId, Integer> costs;
+    protected HashMap<Long, Link> links;
+    protected HashMap<Long, Integer> costs;
 
     public BroadcastTree() {
-        links = new HashMap<DatapathId, Link>();
-        costs = new HashMap<DatapathId, Integer>();
+        links = new HashMap<Long, Link>();
+        costs = new HashMap<Long, Integer>();
     }
 
-    public BroadcastTree(HashMap<DatapathId, Link> links, HashMap<DatapathId, Integer> costs) {
+    public BroadcastTree(HashMap<Long, Link> links, HashMap<Long, Integer> costs) {
         this.links = links;
         this.costs = costs;
     }
 
-    public Link getTreeLink(DatapathId node) {
+    public Link getTreeLink(long node) {
         return links.get(node);
     }
 
-    public int getCost(DatapathId node) {
+    public int getCost(long node) {
         if (costs.get(node) == null) return -1;
         return (costs.get(node));
     }
 
-    public HashMap<DatapathId, Link> getLinks() {
+    public HashMap<Long, Link> getLinks() {
         return links;
     }
 
-    public void addTreeLink(DatapathId myNode, Link link) {
+    public void addTreeLink(long myNode, Link link) {
         links.put(myNode, link);
     }
 
     public String toString() {
         StringBuffer sb = new StringBuffer();
-        for(DatapathId n: links.keySet()) {
-            sb.append("[" + n.toString() + ": cost=" + costs.get(n) + ", " + links.get(n) + "]");
+        for(long n: links.keySet()) {
+            sb.append("[" + HexString.toHexString(n) + ": cost=" + costs.get(n) + ", " + links.get(n) + "]");
         }
         return sb.toString();
     }
 
-    public HashMap<DatapathId, Integer> getCosts() {
+    public HashMap<Long, Integer> getCosts() {
         return costs;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
index a3b22551433ab428e38a03f11881e57006412084..2ef42197bd8a3a6a42c1b76df0682e37db5bf10e 100644
--- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
+++ b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
@@ -32,7 +32,6 @@ 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.internal.IOFSwitchService;
 import net.floodlightcontroller.core.util.AppCookie;
 import net.floodlightcontroller.counter.ICounterStoreService;
 import net.floodlightcontroller.devicemanager.IDeviceService;
@@ -47,26 +46,14 @@ import net.floodlightcontroller.topology.NodePortTuple;
 import net.floodlightcontroller.util.OFMessageDamper;
 import net.floodlightcontroller.util.TimedCache;
 
-import org.projectfloodlight.openflow.protocol.OFFlowMod;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.protocol.match.MatchField;
-import org.projectfloodlight.openflow.protocol.match.MatchFields;
-import org.projectfloodlight.openflow.protocol.OFFlowAdd;
-import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
-import org.projectfloodlight.openflow.protocol.OFFlowModify;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.protocol.OFPacketQueue;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.OFUint64;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFBufferId;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.U64;
+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;
 
@@ -96,7 +83,6 @@ public abstract class ForwardingBase
     protected IRoutingService routingEngine;
     protected ITopologyService topology;
     protected ICounterStoreService counterStore;
-    protected IOFSwitchService switchService;
 
     protected OFMessageDamper messageDamper;
 
@@ -120,9 +106,9 @@ public abstract class ForwardingBase
             new Comparator<SwitchPort>() {
                 @Override
                 public int compare(SwitchPort d1, SwitchPort d2) {
-                    DatapathId d1ClusterId =
+                    Long d1ClusterId =
                             topology.getL2DomainId(d1.getSwitchDPID());
-                    DatapathId d2ClusterId =
+                    Long d2ClusterId =
                             topology.getL2DomainId(d2.getSwitchDPID());
                     return d1ClusterId.compareTo(d2ClusterId);
                 }
@@ -218,35 +204,40 @@ public abstract class ForwardingBase
                         "flow modification to a switch",
             recommendation=LogMessageDoc.CHECK_SWITCH)
     })
-    public boolean pushRoute(Route route, Match match,
-                             Match.Builder wildcard_hints,
+    public boolean pushRoute(Route route, OFMatch match,
+                             Integer wildcard_hints,
                              OFPacketIn pi,
-                             DatapathId pinSwitch,
+                             long pinSwitch,
                              long cookie,
                              FloodlightContext cntx,
                              boolean reqeustFlowRemovedNotifn,
                              boolean doFlush,
-                             OFFlowModCommand flowModCommand) {
+                             short   flowModCommand) {
 
         boolean srcSwitchIncluded = false;
-        OFFlowAdd.Builder fmb = switchService.getSwitch(pinSwitch).getOFFactory().buildFlowAdd();
-        OFActionOutput.Builder actionOutputBuilder = switchService.getSwitch(pinSwitch).getOFFactory().actions().buildOutput();
-        actionOutputBuilder.setMaxLen((int) 0xffffffff);
+        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(actionOutputBuilder.build());
-
-        fmb.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
-        .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
-        .setBufferId(OFBufferId.NO_BUFFER)
-        .setCookie(U64.of(cookie))
-        .setMatch(match)
-        .setActions(actions);
+        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) {
+        for (int indx = switchPortList.size()-1; indx > 0; indx -= 2) {
             // indx and indx-1 will always have the same switch DPID.
-            DatapathId switchDPID = switchPortList.get(indx).getNodeId();
-            IOFSwitch sw = switchService.getSwitch(switchDPID);
+            long switchDPID = switchPortList.get(indx).getNodeId();
+            IOFSwitch sw = floodlightProvider.getSwitch(switchDPID);
             if (sw == null) {
                 if (log.isWarnEnabled()) {
                     log.warn("Unable to push route, switch at DPID {} " +
@@ -256,29 +247,26 @@ public abstract class ForwardingBase
             }
 
             // set the match.
-            fmb.setMatch(wildcard(match, sw, wildcard_hints));
+            fm.setMatch(wildcard(match, sw, wildcard_hints));
 
             // set buffer id if it is the source switch
-            // this only appears to set wildcards, which I think are not necessary
-            /*if (1 == indx) {
+            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.get(MatchField.ARP_OP).getOpcode() != Ethernet.TYPE_ARP)) {
-                    //with new flow cache design, we don't need the flow removal message from switch anymore
-                    //fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
-                    //
-                    match.setWildcards(fmb.getMatch().getWildcards());
+                        && (match.getDataLayerType() != Ethernet.TYPE_ARP)) {
+                    /**with new flow cache design, we don't need the flow removal message from switch anymore
+                    fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
+                    */
+                    match.setWildcards(fm.getMatch().getWildcards());
                 }
-            }*/
+            }
 
-            OFPort outPort = switchPortList.get(indx).getPortId();
-            OFPort inPort = switchPortList.get(indx-1).getPortId();
+            short outPort = switchPortList.get(indx).getPortId();
+            short inPort = switchPortList.get(indx-1).getPortId();
             // set input and output ports on the switch
-            Match m = fmb.getMatch();
-            m.
-            .setInputPort(inPort);
+            fm.getMatch().setInputPort(inPort);
             ((OFActionOutput)fm.getActions().get(0)).setPort(outPort);
 
             try {
@@ -298,7 +286,7 @@ public abstract class ForwardingBase
                 }
 
                 // Push the packet out the source switch
-                if (sw.getId().equals(pinSwitch)) {
+                if (sw.getId() == pinSwitch) {
                     // TODO: Instead of doing a packetOut here we could also
                     // send a flowMod with bufferId set....
                     pushPacket(sw, pi, false, outPort, cntx);
@@ -318,13 +306,13 @@ public abstract class ForwardingBase
         return srcSwitchIncluded;
     }
 
-    /*protected Match wildcard(Match match, IOFSwitch sw,
+    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
@@ -369,7 +357,7 @@ public abstract class ForwardingBase
      */
     protected void pushPacket(IOFSwitch sw, OFPacketIn pi,
                            boolean useBufferId,
-                           OFPort outport, FloodlightContext cntx) {
+                           short outport, FloodlightContext cntx) {
 
         if (pi == null) {
             return;
@@ -393,35 +381,37 @@ public abstract class ForwardingBase
                       new Object[] {sw, pi});
         }
 
-        //OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
-        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
+        OFPacketOut po =
+                (OFPacketOut) floodlightProvider.getOFMessageFactory()
+                                                .getMessage(OFType.PACKET_OUT);
 
         // set actions
         List<OFAction> actions = new ArrayList<OFAction>();
-        //actions.add(new OFActionOutput(outport, (short) 0xffff));
-        actions.add(sw.getOFFactory().actions().output(outport, (int) 0xffffffff));
+        actions.add(new OFActionOutput(outport, (short) 0xffff));
 
-        pob.setActions(actions);
-          //.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
-        //short poLength = (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
+        po.setActions(actions)
+          .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
+        short poLength =
+                (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
 
         if (useBufferId) {
-            pob.setBufferId(pi.getBufferId());
+            po.setBufferId(pi.getBufferId());
         } else {
-            pob.setBufferId(OFBufferId.NO_BUFFER);
+            po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
         }
 
-        if (pob.getBufferId() == OFBufferId.NO_BUFFER) {
-            //poLength += packetData.length;
-            pob.setData(pi.getData());
+        if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
+            byte[] packetData = pi.getPacketData();
+            poLength += packetData.length;
+            po.setPacketData(packetData);
         }
 
-        pob.setInPort(pi.getInPort());
-        //po.setLength(poLength);
+        po.setInPort(pi.getInPort());
+        po.setLength(poLength);
 
         try {
-            counterStore.updatePktOutFMCounterStoreLocal(sw, pob.build());
-            messageDamper.write(sw, pob.build(), cntx);
+            counterStore.updatePktOutFMCounterStoreLocal(sw, po);
+            messageDamper.write(sw, po, cntx);
         } catch (IOException e) {
             log.error("Failure writing packet out", e);
         }
@@ -439,43 +429,46 @@ public abstract class ForwardingBase
      */
     public void packetOutMultiPort(byte[] packetData,
                                    IOFSwitch sw,
-                                   OFPort inPort,
-                                   Set<OFPort> outPorts,
+                                   short inPort,
+                                   Set<Integer> outPorts,
                                    FloodlightContext cntx) {
         //setting actions
         List<OFAction> actions = new ArrayList<OFAction>();
 
-        Iterator<OFPort> j = outPorts.iterator();
+        Iterator<Integer> j = outPorts.iterator();
 
         while (j.hasNext())
         {
-            //actions.add(new OFActionOutput(j.next().shortValue(), (short) 0));
-            actions.add(sw.getOFFactory().actions().output(j.next(), 0));
+            actions.add(new OFActionOutput(j.next().shortValue(),
+                                           (short) 0));
         }
 
-        //OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
-        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
-        pob.setActions(actions);
-        //po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * outPorts.size()));
+        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
-        pob.setBufferId(OFBufferId.NO_BUFFER);
-        pob.setInPort(inPort);
+        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;
-        pob.setData(packetData);
-        //po.setLength(poLength);
+        short poLength = (short)(po.getActionsLength() +
+                OFPacketOut.MINIMUM_LENGTH);
+        poLength += packetData.length;
+        po.setPacketData(packetData);
+        po.setLength(poLength);
 
         try {
-            counterStore.updatePktOutFMCounterStoreLocal(sw, pob.build());
+            counterStore.updatePktOutFMCounterStoreLocal(sw, po);
             if (log.isTraceEnabled()) {
                 log.trace("write broadcast packet on switch-id={} " +
                         "interfaces={} packet-out={}",
-                        new Object[] {sw.getId(), outPorts, pob.build()});
+                        new Object[] {sw.getId(), outPorts, po});
             }
-            messageDamper.write(sw, pob.build(), cntx);
+            messageDamper.write(sw, po, cntx);
 
         } catch (IOException e) {
             log.error("Failure writing packet out", e);
@@ -489,10 +482,10 @@ public abstract class ForwardingBase
      */
     public void packetOutMultiPort(OFPacketIn pi,
                                    IOFSwitch sw,
-                                   OFPort inPort,
-                                   Set<OFPort> outPorts,
+                                   short inPort,
+                                   Set<Integer> outPorts,
                                    FloodlightContext cntx) {
-        packetOutMultiPort(pi.getData(), sw, inPort, outPorts, cntx);
+        packetOutMultiPort(pi.getPacketData(), sw, inPort, outPorts, cntx);
     }
 
     /**
@@ -502,8 +495,8 @@ public abstract class ForwardingBase
      */
     public void packetOutMultiPort(IPacket packet,
                                    IOFSwitch sw,
-                                   OFPort inPort,
-                                   Set<OFPort> outPorts,
+                                   short inPort,
+                                   Set<Integer> outPorts,
                                    FloodlightContext cntx) {
         packetOutMultiPort(packet.serialize(), sw, inPort, outPorts, cntx);
     }
@@ -522,8 +515,8 @@ public abstract class ForwardingBase
                 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
 
         Long broadcastHash;
-        broadcastHash = topology.getL2DomainId(sw.getId()).getLong() * prime1 +
-                        pi.getInPort().getPortNumber() * prime2 + eth.hashCode();
+        broadcastHash = topology.getL2DomainId(sw.getId()) * prime1 +
+                        pi.getInPort() * prime2 + eth.hashCode();
         if (broadcastCache.update(broadcastHash)) {
             sw.updateBroadcastCache(broadcastHash, pi.getInPort());
             return true;
@@ -542,7 +535,7 @@ public abstract class ForwardingBase
         Ethernet eth =
                 IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
 
-        long hash =  pi.getInPort().getPortNumber() * prime2 + eth.hashCode();
+        long hash =  pi.getInPort() * prime2 + eth.hashCode();
 
         // some FORWARD_OR_FLOOD packets are unicast with unknown destination mac
         return sw.updateBroadcastCache(hash, pi.getInPort());
@@ -556,43 +549,53 @@ public abstract class ForwardingBase
             recommendation=LogMessageDoc.CHECK_SWITCH)
     })
     public static boolean
-            blockHost(IOFSwitchService switchService,
-                      SwitchPort sw_tup, MacAddress host_mac,
+            blockHost(IFloodlightProviderService floodlightProvider,
+                      SwitchPort sw_tup, long host_mac,
                       short hardTimeout, long cookie) {
 
         if (sw_tup == null) {
             return false;
         }
 
-        IOFSwitch sw = switchService.getSwitch(sw_tup.getSwitchDPID());
+        IOFSwitch sw =
+                floodlightProvider.getSwitch(sw_tup.getSwitchDPID());
         if (sw == null) return false;
-        OFPort inputPort = sw_tup.getPort();
+        int inputPort = sw_tup.getPort();
         log.debug("blockHost sw={} port={} mac={}",
-                  new Object[] { sw, sw_tup.getPort(), host_mac.getLong() });
+                  new Object[] { sw, sw_tup.getPort(), Long.valueOf(host_mac) });
 
         // Create flow-mod based on packet-in and src-switch
-        OFFlowMod.Builder fmb = switchService.getSwitch(sw_tup.getSwitchDPID()).getOFFactory().buildFlowAdd();
-        Match.Builder mb = switchService.getSwitch(sw_tup.getSwitchDPID()).getOFFactory().buildMatch();
+        OFFlowMod fm =
+                (OFFlowMod) floodlightProvider.getOFMessageFactory()
+                                              .getMessage(OFType.FLOW_MOD);
+        OFMatch match = new OFMatch();
         List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to
                                                             // drop
-        mb.setExact(MatchField.IN_PORT, inputPort);
-        if (host_mac.getLong() != -1L) {
-            //match.setDataLayerSource(Ethernet.toByteArray(host_mac)).setWildcards(OFMatch.OFPFW_ALL & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_IN_PORT);
-            mb.setExact(MatchField.ETH_SRC, host_mac);
-        } /*else {
+        match.setInputPort((short)inputPort);
+        if (host_mac != -1L) {
+            match.setDataLayerSource(Ethernet.toByteArray(host_mac))
+                .setWildcards(OFMatch.OFPFW_ALL & ~OFMatch.OFPFW_DL_SRC
+                               & ~OFMatch.OFPFW_IN_PORT);
+        } else {
             match.setWildcards(OFMatch.OFPFW_ALL & ~OFMatch.OFPFW_IN_PORT);
-        }*/
-        fmb.setCookie(U64.of(cookie))
+        }
+        fm.setCookie(cookie)
           .setHardTimeout(hardTimeout)
           .setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
-          .setBufferId(OFBufferId.NO_BUFFER)
-          .setMatch(mb.build())
-          .setActions(actions);
-
-        log.debug("write drop flow-mod sw={} match={} flow-mod={}",
-		          new Object[] { sw, mb.build(), fmb.build() });
-		// TODO: can't use the message damper sine this method is static
-		sw.write(fmb.build(), null);
+          .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;
 
     }
diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java b/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
index 9c7a285970819db2cd48ebe92554ce7dc6d37fe3..ab09375486b9f61b2cfa98b83a5e9eeb483bd20b 100644
--- a/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
+++ b/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
@@ -19,8 +19,6 @@ package net.floodlightcontroller.routing;
 
 import java.util.List;
 
-import org.projectfloodlight.openflow.protocol.match.Match;
-
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.FloodlightContextStore;
 import net.floodlightcontroller.devicemanager.IDevice;
@@ -59,8 +57,8 @@ public interface IRoutingDecision {
     public void addDestinationDevice(IDevice d);
     public List<SwitchPort> getMulticastInterfaces();
     public void setMulticastInterfaces(List<SwitchPort> lspt);
-    public Match.Builder getWildcards();
-    public void setWildcards(Match.Builder wildcards);
+    public Integer getWildcards();
+    public void setWildcards(Integer wildcards);
     public short getHardTimeout();
     public void setHardTimeout(short hardTimeout);
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
index 6cff6f533a75e0a0b03cdab7a27c83fc61e00696..a3d77a83ba6309c02c6f99c19d2523eab2ecfa3b 100644
--- a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
+++ b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
@@ -19,9 +19,6 @@ package net.floodlightcontroller.routing;
 
 import java.util.ArrayList;
 
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
-
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.routing.Route;
 
@@ -36,7 +33,7 @@ public interface IRoutingService extends IFloodlightService {
      * @param dst Destination switch DPID.
      * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
      */
-    public Route getRoute(DatapathId src, DatapathId dst, long cookie);
+    public Route getRoute(long src, long dst, long cookie);
 
     /**
      * Provides a route between src and dst, with option to allow or
@@ -46,7 +43,7 @@ public interface IRoutingService extends IFloodlightService {
      * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
      * @param tunnelEnabled boolean option.
      */
-    public Route getRoute(DatapathId src, DatapathId dst, long cookie, boolean tunnelEnabled);
+    public Route getRoute(long src, long dst, long cookie, boolean tunnelEnabled);
 
     /**
      * Provides a route between srcPort on src and dstPort on dst.
@@ -56,8 +53,8 @@ public interface IRoutingService extends IFloodlightService {
      * @param dstPort dstPort on Destination switch.
      * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
      */
-    public Route getRoute(DatapathId srcId, OFPort srcPort,
-    		DatapathId dstId, OFPort dstPort, long cookie);
+    public Route getRoute(long srcId, short srcPort,
+                             long dstId, short dstPort, long cookie);
 
     /**
      * Provides a route between srcPort on src and dstPort on dst.
@@ -68,21 +65,21 @@ public interface IRoutingService extends IFloodlightService {
      * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
      * @param tunnelEnabled boolean option.
      */
-    public Route getRoute(DatapathId srcId, OFPort srcPort,
-    		DatapathId dstId, OFPort dstPort, long cookie,
+    public Route getRoute(long srcId, short srcPort,
+                             long dstId, short dstPort, long cookie,
                              boolean tunnelEnabled);
 
     /** return all routes, if available */
-    public ArrayList<Route> getRoutes(DatapathId longSrcDpid, DatapathId longDstDpid, boolean tunnelEnabled);
+    public ArrayList<Route> getRoutes(long longSrcDpid, long longDstDpid, boolean tunnelEnabled);
 
     /** Check if a route exists between src and dst, including tunnel links
      *  in the path.
      */
-    public boolean routeExists(DatapathId src, DatapathId dst);
+    public boolean routeExists(long src, long dst);
 
     /** Check if a route exists between src and dst, with option to have
      *  or not have tunnels as part of the path.
      */
-    public boolean routeExists(DatapathId src, DatapathId dst, boolean tunnelEnabled);
+    public boolean routeExists(long src, long dst, boolean tunnelEnabled);
 
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/Link.java b/src/main/java/net/floodlightcontroller/routing/Link.java
index a2f125f5a5b2cd73c9ce6bfaa65e4b56e87d6ff6..561ae04c09ba4b4d3849763da46796dff4c03f95 100755
--- a/src/main/java/net/floodlightcontroller/routing/Link.java
+++ b/src/main/java/net/floodlightcontroller/routing/Link.java
@@ -18,28 +18,34 @@
 package net.floodlightcontroller.routing;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
+import org.openflow.util.HexString;
 
 public class Link implements Comparable<Link> {
     @JsonProperty("src-switch")
-    private DatapathId src;
+    private long src;
     @JsonProperty("src-port")
-    private OFPort srcPort;
+    private short srcPort;
     @JsonProperty("dst-switch")
-    private DatapathId dst;
+    private long dst;
     @JsonProperty("dst-port")
-    private OFPort dstPort;
+    private short dstPort;
 
 
-    public Link(DatapathId srcId, OFPort srcPort, DatapathId dstId, OFPort dstPort) {
+    public Link(long srcId, short srcPort, long dstId, short dstPort) {
         this.src = srcId;
         this.srcPort = srcPort;
         this.dst = dstId;
         this.dstPort = dstPort;
     }
 
+    // Convenience method
+    public Link(long srcId, int srcPort, long dstId, int dstPort) {
+        this.src = srcId;
+        this.srcPort = (short) srcPort;
+        this.dst = dstId;
+        this.dstPort = (short) dstPort;
+    }
+
     /*
      * Do not use this constructor. Used primarily for JSON
      * Serialization/Deserialization
@@ -48,35 +54,35 @@ public class Link implements Comparable<Link> {
         super();
     }
 
-    public DatapathId getSrc() {
+    public long getSrc() {
         return src;
     }
 
-    public OFPort getSrcPort() {
+    public short getSrcPort() {
         return srcPort;
     }
 
-    public DatapathId getDst() {
+    public long getDst() {
         return dst;
     }
 
-    public OFPort getDstPort() {
+    public short getDstPort() {
         return dstPort;
     }
 
-    public void setSrc(DatapathId src) {
+    public void setSrc(long src) {
         this.src = src;
     }
 
-    public void setSrcPort(OFPort srcPort) {
+    public void setSrcPort(short srcPort) {
         this.srcPort = srcPort;
     }
 
-    public void setDst(DatapathId dst) {
+    public void setDst(long dst) {
         this.dst = dst;
     }
 
-    public void setDstPort(OFPort dstPort) {
+    public void setDstPort(short dstPort) {
         this.dstPort = dstPort;
     }
 
@@ -84,10 +90,10 @@ public class Link implements Comparable<Link> {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + (int) (dst.getLong() ^ (dst.getLong() >>> 32));
-        result = prime * result + dstPort.getPortNumber();
-        result = prime * result + (int) (src.getLong() ^ (src.getLong() >>> 32));
-        result = prime * result + srcPort.getPortNumber();
+        result = prime * result + (int) (dst ^ (dst >>> 32));
+        result = prime * result + dstPort;
+        result = prime * result + (int) (src ^ (src >>> 32));
+        result = prime * result + srcPort;
         return result;
     }
 
@@ -114,36 +120,35 @@ public class Link implements Comparable<Link> {
 
     @Override
     public String toString() {
-        return "Link [src=" + this.src.toString() 
+        return "Link [src=" + HexString.toHexString(this.src) 
                 + " outPort="
-                + srcPort.toString()
-                + ", dst=" + this.dst.toString()
+                + (srcPort & 0xffff)
+                + ", dst=" + HexString.toHexString(this.dst)
                 + ", inPort="
-                + dstPort.toString()
+                + (dstPort & 0xffff)
                 + "]";
     }
     
-    //TODO @Ryan there was some short 0xFFFF bitmasking here when ports were shorts. I don't get what that did other than just allow all bits of the short (16), so I just stringified the whole thing
     public String toKeyString() {
-    	return (this.src.toString() + "|" +
-    			this.srcPort.toString() + "|" +
-    			this.dst.toString() + "|" +
-    		    this.dstPort.toString());
+    	return (HexString.toHexString(this.src) + "|" +
+    			(this.srcPort & 0xffff) + "|" +
+    			HexString.toHexString(this.dst) + "|" +
+    		    (this.dstPort & 0xffff) );
     }
 
     @Override
     public int compareTo(Link a) {
         // compare link based on natural ordering - src id, src port, dst id, dst port
         if (this.getSrc() != a.getSrc())
-            return (int) (this.getSrc().getLong() - a.getSrc().getLong());
+            return (int) (this.getSrc() - a.getSrc());
         
         if (this.getSrcPort() != a.getSrcPort())
-            return (int) (this.getSrc().getLong() - a.getSrc().getLong());
+            return (int) (this.getSrc() - a.getSrc());
         
         if (this.getDst() != a.getDst())
-            return (int) (this.getDst().getLong() - a.getDst().getLong());
+            return (int) (this.getDst() - a.getDst());
         
-        return this.getDstPort().getPortNumber() - a.getDstPort().getPortNumber();
+        return this.getDstPort() - a.getDstPort();
     }
 }
 
diff --git a/src/main/java/net/floodlightcontroller/routing/Route.java b/src/main/java/net/floodlightcontroller/routing/Route.java
index f41a9aaf1e159249e4eb831da30cf80abe993ad5..da00d50b7b82a3d3498b1523543a8558abbd579a 100755
--- a/src/main/java/net/floodlightcontroller/routing/Route.java
+++ b/src/main/java/net/floodlightcontroller/routing/Route.java
@@ -20,8 +20,6 @@ package net.floodlightcontroller.routing;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.projectfloodlight.openflow.types.DatapathId;
-
 import net.floodlightcontroller.topology.NodePortTuple;
 
 /**
@@ -41,7 +39,7 @@ public class Route implements Comparable<Route> {
         this.routeCount = 0; // useful if multipath routing available
     }
 
-    public Route(DatapathId src, DatapathId dst) {
+    public Route(Long src, Long dst) {
         super();
         this.id = new RouteId(src, dst);
         this.switchPorts = new ArrayList<NodePortTuple>();
diff --git a/src/main/java/net/floodlightcontroller/routing/RouteId.java b/src/main/java/net/floodlightcontroller/routing/RouteId.java
index bd80f4d2c6727ab238ff18566896db16aae8223e..511db735969aa849d619783cdd88229d1922b27a 100755
--- a/src/main/java/net/floodlightcontroller/routing/RouteId.java
+++ b/src/main/java/net/floodlightcontroller/routing/RouteId.java
@@ -17,7 +17,7 @@
 
 package net.floodlightcontroller.routing;
 
-import org.projectfloodlight.openflow.types.DatapathId;
+import org.openflow.util.HexString;
 
 /**
  * Stores the endpoints of a route, in this case datapath ids
@@ -25,37 +25,37 @@ import org.projectfloodlight.openflow.types.DatapathId;
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
 public class RouteId implements Cloneable, Comparable<RouteId> {
-    protected DatapathId src;
-    protected DatapathId dst;
+    protected Long src;
+    protected Long dst;
     protected long cookie;
 
-    public RouteId(DatapathId src, DatapathId dst) {
+    public RouteId(Long src, Long dst) {
         super();
         this.src = src;
         this.dst = dst;
         this.cookie = 0;
     }
 
-    public RouteId(DatapathId src, DatapathId dst, long cookie) {
+    public RouteId(Long src, Long dst, long cookie) {
         super();
         this.src = src;
         this.dst = dst;
         this.cookie = cookie;
     }
 
-    public DatapathId getSrc() {
+    public Long getSrc() {
         return src;
     }
 
-    public void setSrc(DatapathId src) {
+    public void setSrc(Long src) {
         this.src = src;
     }
 
-    public DatapathId getDst() {
+    public Long getDst() {
         return dst;
     }
 
-    public void setDst(DatapathId dst) {
+    public void setDst(Long dst) {
         this.dst = dst;
     }
 
@@ -103,8 +103,8 @@ public class RouteId implements Cloneable, Comparable<RouteId> {
 
     @Override
     public String toString() {
-        return "RouteId [src=" + this.src.toString() + " dst="
-                + this.dst.toString() + "]";
+        return "RouteId [src=" + HexString.toHexString(this.src) + " dst="
+                + HexString.toHexString(this.dst) + "]";
     }
 
     @Override
diff --git a/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java b/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java
index 2d487f409ca01c9f7d0cbe859521be2b9dcd0a29..aa4b3dde823ab75a38671e53767294d1964012f3 100644
--- a/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java
+++ b/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java
@@ -20,10 +20,6 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
-
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.SwitchPort;
@@ -32,15 +28,15 @@ import net.floodlightcontroller.devicemanager.SwitchPort;
 public class RoutingDecision implements IRoutingDecision {
 
     protected RoutingAction action;
-    protected Match.Builder wildcards;
+    protected Integer wildcards;
     protected short hardTimeout;
     protected SwitchPort srcPort;
     protected IDevice srcDevice;
     protected List<IDevice> destDevices;
     protected List<SwitchPort> broadcastIntertfaces;
 
-    public RoutingDecision(DatapathId swDipd,
-                                  OFPort inPort,
+    public RoutingDecision(long swDipd,
+                                  short inPort,
                                   IDevice srcDevice,
                                   RoutingAction action) {
         this.srcPort = new SwitchPort(swDipd, inPort);
@@ -97,12 +93,12 @@ public class RoutingDecision implements IRoutingDecision {
     }
     
     @Override
-    public Match.Builder getWildcards() {
+    public Integer getWildcards() {
         return this.wildcards;
     }
     
     @Override
-    public void setWildcards(Match.Builder wildcards) {
+    public void setWildcards(Integer wildcards) {
         this.wildcards = wildcards;
     }
    
@@ -124,6 +120,6 @@ public class RoutingDecision implements IRoutingDecision {
     public String toString() {
         return "action " + action +
                " wildcard " +
-               ((wildcards == null) ? null : wildcards.toString());
+               ((wildcards == null) ? null : "0x"+Integer.toHexString(wildcards.intValue()));
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/Cluster.java b/src/main/java/net/floodlightcontroller/topology/Cluster.java
index 914740f10246698c95c7cf0085cb09465c79a709..e4ea23b8c97673f1d764b58211dd54f71f07b77c 100644
--- a/src/main/java/net/floodlightcontroller/topology/Cluster.java
+++ b/src/main/java/net/floodlightcontroller/topology/Cluster.java
@@ -23,37 +23,37 @@ import java.util.Set;
 
 import net.floodlightcontroller.routing.Link;
 
-import org.projectfloodlight.openflow.types.DatapathId;
+import org.openflow.util.HexString;
 
 public class Cluster {
-    protected DatapathId id; // the lowest id of the nodes
-    protected Map<DatapathId, Set<Link>> links; // set of links connected to a node.
+    protected long id; // the lowest id of the nodes
+    protected Map<Long, Set<Link>> links; // set of links connected to a node.
 
     public Cluster() {
-        id = DatapathId.NONE;
-        links = new HashMap<DatapathId, Set<Link>>();
+        id = Long.MAX_VALUE;
+        links = new HashMap<Long, Set<Link>>();
     }
 
-    public DatapathId getId() {
+    public long getId() {
         return id;
     }
 
-    public void setId(DatapathId id) {
+    public void setId(long id) {
         this.id = id;
     }
 
-    public Map<DatapathId, Set<Link>> getLinks() {
+    public Map<Long, Set<Link>> getLinks() {
         return links;
     }
 
-    public Set<DatapathId> getNodes() {
+    public Set<Long> getNodes() {
         return links.keySet();
     }
 
-    void add(DatapathId n) {
+    void add(long n) {
         if (links.containsKey(n) == false) {
             links.put(n, new HashSet<Link>());
-            if (n.getLong() < id.getLong()) id = n;
+            if (n < id) id = n;
         }
     }
 
@@ -67,7 +67,7 @@ public class Cluster {
 
     @Override 
     public int hashCode() {
-        return (int) (id.getLong() + id.getLong() >>>32);
+        return (int) (id + id >>>32);
     }
 
     @Override
@@ -84,6 +84,6 @@ public class Cluster {
     }
     
     public String toString() {
-        return "[Cluster id=" + id.toString() + ", " + links.keySet() + "]";
+        return "[Cluster id=" + HexString.toHexString(id) + ", " + links.keySet() + "]";
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java
index d6bd177550852501cded815cc2132abc9dc868b0..d518b80d21320095b9baaa3f5223768c414a414a 100644
--- a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java
+++ b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java
@@ -19,195 +19,192 @@ package net.floodlightcontroller.topology;
 import java.util.Date;
 import java.util.Set;
 
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
-
 import net.floodlightcontroller.core.module.IFloodlightService;
 
 public interface ITopologyService extends IFloodlightService  {
 
-	public void addListener(ITopologyListener listener);
-
-	public Date getLastUpdateTime();
-
-	/**
-	 * Query to determine if devices must be learned on a given switch port.
-	 */
-	public boolean isAttachmentPointPort(DatapathId switchid, OFPort port);
-	public boolean isAttachmentPointPort(DatapathId switchid, OFPort port,
-			boolean tunnelEnabled);
-
-	public DatapathId getOpenflowDomainId(DatapathId switchId);
-	public DatapathId getOpenflowDomainId(DatapathId switchId, boolean tunnelEnabled);
-
-	/**
-	 * Returns the identifier of the L2 domain of a given switch.
-	 * @param switchId The DPID of the switch in long form
-	 * @return The DPID of the switch that is the key for the cluster
-	 */
-	public DatapathId getL2DomainId(DatapathId switchId);
-	public DatapathId getL2DomainId(DatapathId switchId, boolean tunnelEnabled);
-
-	/**
-	 * Queries whether two switches are in the same cluster.
-	 * @param switch1
-	 * @param switch2
-	 * @return true if the switches are in the same cluster
-	 */
-	public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2);
-	public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2,
-			boolean tunnelEnabled);
-
-	public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID);
-	public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID,
-			boolean tunnelEnabled);
-
-	/**
-	 * Queries whether two switches are in the same island.
-	 * Currently, island and cluster are the same. In future,
-	 * islands could be different than clusters.
-	 * @param switch1
-	 * @param switch2
-	 * @return True of they are in the same island, false otherwise
-	 */
-	public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2);
-	public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2,
-			boolean tunnelEnabled);
-
-	public boolean isBroadcastDomainPort(DatapathId sw, OFPort port);
-	public boolean isBroadcastDomainPort(DatapathId sw, OFPort port,
-			boolean tunnelEnabled);
-
-
-	public boolean isAllowed(DatapathId sw, OFPort portId);
-	public boolean isAllowed(DatapathId sw, OFPort portId, boolean tunnelEnabled);
-
-	/**
-	 * Indicates if an attachment point on the new switch port is consistent
-	 * with the attachment point on the old switch port or not.
-	 */
-	public boolean isConsistent(DatapathId oldSw, OFPort oldPort,
-			DatapathId newSw, OFPort newPort);
-	public boolean isConsistent(DatapathId oldSw, OFPort oldPort,
-			DatapathId newSw, OFPort newPort,
-			boolean tunnelEnabled);
-
-	/**
-	 * Indicates if the two switch ports are connected to the same
-	 * broadcast domain or not.
-	 * @param s1
-	 * @param p1
-	 * @param s2
-	 * @param p2
-	 * @return
-	 */
-	public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1,
-			DatapathId s2, OFPort p2);
-	public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1,
-			DatapathId s2, OFPort p2,
-			boolean tunnelEnabled);
-
-	/**
-	 * Gets a list of ports on a given switch that are known to topology.
-	 * @param sw The switch DPID in long
-	 * @return The set of ports on this switch
-	 */
-	public Set<OFPort> getPortsWithLinks(DatapathId sw);
-	public Set<OFPort> getPortsWithLinks(DatapathId sw, boolean tunnelEnabled);
-
-	/** Get broadcast ports on a target switch for a given attachmentpoint
-	 * point port.
-	 */
-	public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort);
-
-	public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort,
-			boolean tunnelEnabled);
-
-	/**
-	 *
-	 */
-	public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId);
-	public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId,
-			boolean tunnelEnabled);
-
-
-	/** Get the proper outgoing switchport for a given pair of src-dst
-	 * switchports.
-	 */
-	public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort dstPort);
-
-
-	public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort dstPort,
-			boolean tunnelEnabled);
-
-
-	public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort dstPort);
-	public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort dstPort,
-			boolean tunnelEnabled);
-
-	/**
-	 * If the dst is not allowed by the higher-level topology,
-	 * this method provides the topologically equivalent broadcast port.
-	 * @param src
-	 * @param dst
-	 * @return the allowed broadcast port
-	 */
-	public NodePortTuple
-	getAllowedOutgoingBroadcastPort(DatapathId src,
-			OFPort srcPort,
-			DatapathId dst,
-			OFPort dstPort);
-
-	public NodePortTuple
-	getAllowedOutgoingBroadcastPort(DatapathId src,
-			OFPort srcPort,
-			DatapathId dst,
-			OFPort dstPort,
-			boolean tunnelEnabled);
-
-	/**
-	 * If the src broadcast domain port is not allowed for incoming
-	 * broadcast, this method provides the topologically equivalent
-	 * incoming broadcast-allowed
-	 * src port.
-	 * @param src
-	 * @param dst
-	 * @return the allowed broadcast port
-	 */
-	public NodePortTuple
-	getAllowedIncomingBroadcastPort(DatapathId src,
-			OFPort srcPort);
-
-	public NodePortTuple
-	getAllowedIncomingBroadcastPort(DatapathId src,
-			OFPort srcPort,
-			boolean tunnelEnabled);
-
-
-	/**
-	 * Gets the set of ports that belong to a broadcast domain.
-	 * @return The set of ports that belong to a broadcast domain.
-	 */
-	public Set<NodePortTuple> getBroadcastDomainPorts();
-	public Set<NodePortTuple> getTunnelPorts();
-
-
-	/**
-	 * Returns a set of blocked ports.  The set of blocked
-	 * ports is the union of all the blocked ports across all
-	 * instances.
-	 * @return
-	 */
-	public Set<NodePortTuple> getBlockedPorts();
-
-	/**
-	 * Returns the enabled, non quarantined ports of the given switch. Returns
-	 * an empty set if switch doesn't exists, doesn't have any enabled port, or
-	 * has only quarantined ports. Will never return null.
-	 */
-	public Set<OFPort> getPorts(DatapathId sw);
+    public void addListener(ITopologyListener listener);
+
+    public Date getLastUpdateTime();
+
+    /**
+     * Query to determine if devices must be learned on a given switch port.
+     */
+    public boolean isAttachmentPointPort(long switchid, short port);
+    public boolean isAttachmentPointPort(long switchid, short port,
+                                         boolean tunnelEnabled);
+
+    public long getOpenflowDomainId(long switchId);
+    public long getOpenflowDomainId(long switchId, boolean tunnelEnabled);
+
+    /**
+     * Returns the identifier of the L2 domain of a given switch.
+     * @param switchId The DPID of the switch in long form
+     * @return The DPID of the switch that is the key for the cluster
+     */
+    public long getL2DomainId(long switchId);
+    public long getL2DomainId(long switchId, boolean tunnelEnabled);
+
+    /**
+     * Queries whether two switches are in the same cluster.
+     * @param switch1
+     * @param switch2
+     * @return true if the switches are in the same cluster
+     */
+    public boolean inSameOpenflowDomain(long switch1, long switch2);
+    public boolean inSameOpenflowDomain(long switch1, long switch2,
+                                        boolean tunnelEnabled);
+
+    public Set<Long> getSwitchesInOpenflowDomain(long switchDPID);
+    public Set<Long> getSwitchesInOpenflowDomain(long switchDPID,
+                                                 boolean tunnelEnabled);
+
+    /**
+     * Queries whether two switches are in the same island.
+     * Currently, island and cluster are the same. In future,
+     * islands could be different than clusters.
+     * @param switch1
+     * @param switch2
+     * @return True of they are in the same island, false otherwise
+     */
+    public boolean inSameL2Domain(long switch1, long switch2);
+    public boolean inSameL2Domain(long switch1, long switch2,
+                                  boolean tunnelEnabled);
+
+    public boolean isBroadcastDomainPort(long sw, short port);
+    public boolean isBroadcastDomainPort(long sw, short port,
+                                         boolean tunnelEnabled);
+
+
+    public boolean isAllowed(long sw, short portId);
+    public boolean isAllowed(long sw, short portId, boolean tunnelEnabled);
+
+    /**
+     * Indicates if an attachment point on the new switch port is consistent
+     * with the attachment point on the old switch port or not.
+     */
+    public boolean isConsistent(long oldSw, short oldPort,
+                                long newSw, short newPort);
+    public boolean isConsistent(long oldSw, short oldPort,
+                                long newSw, short newPort,
+                                boolean tunnelEnabled);
+
+    /**
+     * Indicates if the two switch ports are connected to the same
+     * broadcast domain or not.
+     * @param s1
+     * @param p1
+     * @param s2
+     * @param p2
+     * @return
+     */
+    public boolean isInSameBroadcastDomain(long s1, short p1,
+                                           long s2, short p2);
+    public boolean isInSameBroadcastDomain(long s1, short p1,
+                                           long s2, short p2,
+                                           boolean tunnelEnabled);
+
+    /**
+     * Gets a list of ports on a given switch that are known to topology.
+     * @param sw The switch DPID in long
+     * @return The set of ports on this switch
+     */
+    public Set<Short> getPortsWithLinks(long sw);
+    public Set<Short> getPortsWithLinks(long sw, boolean tunnelEnabled);
+
+    /** Get broadcast ports on a target switch for a given attachmentpoint
+     * point port.
+     */
+    public Set<Short> getBroadcastPorts(long targetSw, long src, short srcPort);
+
+    public Set<Short> getBroadcastPorts(long targetSw, long src, short srcPort,
+                                        boolean tunnelEnabled);
+
+    /**
+     *
+     */
+    public boolean isIncomingBroadcastAllowed(long sw, short portId);
+    public boolean isIncomingBroadcastAllowed(long sw, short portId,
+                                              boolean tunnelEnabled);
+
+
+    /** Get the proper outgoing switchport for a given pair of src-dst
+     * switchports.
+     */
+    public NodePortTuple getOutgoingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort);
+
+
+    public NodePortTuple getOutgoingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort,
+                                               boolean tunnelEnabled);
+
+
+    public NodePortTuple getIncomingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort);
+    public NodePortTuple getIncomingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort,
+                                               boolean tunnelEnabled);
+
+    /**
+     * If the dst is not allowed by the higher-level topology,
+     * this method provides the topologically equivalent broadcast port.
+     * @param src
+     * @param dst
+     * @return the allowed broadcast port
+     */
+    public NodePortTuple
+    getAllowedOutgoingBroadcastPort(long src,
+                                    short srcPort,
+                                    long dst,
+                                    short dstPort);
+
+    public NodePortTuple
+    getAllowedOutgoingBroadcastPort(long src,
+                                    short srcPort,
+                                    long dst,
+                                    short dstPort,
+                                    boolean tunnelEnabled);
+
+    /**
+     * If the src broadcast domain port is not allowed for incoming
+     * broadcast, this method provides the topologically equivalent
+     * incoming broadcast-allowed
+     * src port.
+     * @param src
+     * @param dst
+     * @return the allowed broadcast port
+     */
+    public NodePortTuple
+    getAllowedIncomingBroadcastPort(long src,
+                                    short srcPort);
+
+    public NodePortTuple
+    getAllowedIncomingBroadcastPort(long src,
+                                    short srcPort,
+                                    boolean tunnelEnabled);
+
+
+    /**
+     * Gets the set of ports that belong to a broadcast domain.
+     * @return The set of ports that belong to a broadcast domain.
+     */
+    public Set<NodePortTuple> getBroadcastDomainPorts();
+    public Set<NodePortTuple> getTunnelPorts();
+
+
+    /**
+     * Returns a set of blocked ports.  The set of blocked
+     * ports is the union of all the blocked ports across all
+     * instances.
+     * @return
+     */
+    public Set<NodePortTuple> getBlockedPorts();
+
+    /**
+     * Returns the enabled, non quarantined ports of the given switch. Returns
+     * an empty set if switch doesn't exists, doesn't have any enabled port, or
+     * has only quarantined ports. Will never return null.
+     */
+    public Set<Short> getPorts(long sw);
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java b/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java
index f7b0a178ac397c9c2bc4bd9135c4053eb1882f96..8c5645143ac0edc54df86582d9b83273bd30ed56 100644
--- a/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java
+++ b/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java
@@ -21,10 +21,7 @@ import net.floodlightcontroller.core.web.serializers.UShortSerializer;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.util.HexString;
 
 /**
  * A NodePortTuple is similar to a SwitchPortTuple
@@ -34,46 +31,51 @@ import org.projectfloodlight.openflow.util.HexString;
  */
 
 public class NodePortTuple implements Comparable<NodePortTuple> {
-    protected DatapathId nodeId; // switch DPID
-    protected OFPort portId; // switch port id
+    protected long nodeId; // switch DPID
+    protected short portId; // switch port id
 
     /**
      * Creates a NodePortTuple
      * @param nodeId The DPID of the switch
      * @param portId The port of the switch
      */
-    public NodePortTuple(DatapathId nodeId, OFPort portId) {
+    public NodePortTuple(long nodeId, short portId) {
         this.nodeId = nodeId;
         this.portId = portId;
     }
 
+    public NodePortTuple(long nodeId, int portId) {
+        this.nodeId = nodeId;
+        this.portId = (short) portId;
+    }
+
     @JsonProperty("switch")
     @JsonSerialize(using=DPIDSerializer.class)
-    public DatapathId getNodeId() {
+    public long getNodeId() {
         return nodeId;
     }
-    public void setNodeId(DatapathId nodeId) {
+    public void setNodeId(long nodeId) {
         this.nodeId = nodeId;
     }
     @JsonProperty("port")
     @JsonSerialize(using=UShortSerializer.class)
-    public OFPort getPortId() {
+    public short getPortId() {
         return portId;
     }
-    public void setPortId(OFPort portId) {
+    public void setPortId(short portId) {
         this.portId = portId;
     }
     
     public String toString() {
-        return "[id=" + nodeId.toString() + ", port=" + portId.toString() + "]";
+        return "[id=" + HexString.toHexString(nodeId) + ", port=" + new Short(portId) + "]";
     }
 
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + (int) (nodeId.getLong() ^ (nodeId.getLong() >>> 32));
-        result = prime * result + portId.getPortNumber();
+        result = prime * result + (int) (nodeId ^ (nodeId >>> 32));
+        result = prime * result + portId;
         return result;
     }
 
@@ -100,7 +102,7 @@ public class NodePortTuple implements Comparable<NodePortTuple> {
      * @return
      */
     public String toKeyString() {
-        return (nodeId.toString()+ "|" + portId.toString());
+        return (HexString.toHexString(nodeId)+ "|" + (portId & 0xffff));
     }
 
     @Override
@@ -109,14 +111,14 @@ public class NodePortTuple implements Comparable<NodePortTuple> {
         final int EQUAL = 0;
         final int AFTER = 1;
 
-        if (this.getNodeId().getLong() < obj.getNodeId().getLong())
+        if (this.getNodeId() < obj.getNodeId())
             return BEFORE;
-        if (this.getNodeId().getLong() > obj.getNodeId().getLong())
+        if (this.getNodeId() > obj.getNodeId())
             return AFTER;
 
-        if (this.getPortId().getPortNumber() < obj.getPortId().getPortNumber())
+        if (this.getPortId() < obj.getPortId())
             return BEFORE;
-        if (this.getPortId().getPortNumber() > obj.getPortId().getPortNumber())
+        if (this.getPortId() > obj.getPortId())
             return AFTER;
 
         return EQUAL;
diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
index bc5d626783048f653c6c9ba63ac14f6a459709f0..a143d45e73e6bff892766999926487fb6fcb2f03 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
@@ -25,8 +25,7 @@ import java.util.Map;
 import java.util.PriorityQueue;
 import java.util.Set;
 
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -60,7 +59,7 @@ public class TopologyInstance {
 
     protected static Logger log = LoggerFactory.getLogger(TopologyInstance.class);
 
-    protected Map<DatapathId, Set<OFPort>> switchPorts; // Set of ports for each switch
+    protected Map<Long, Set<Short>> switchPorts; // Set of ports for each switch
     /** Set of switch ports that are marked as blocked.  A set of blocked
      * switch ports may be provided at the time of instantiation. In addition,
      * we may add additional ports to this set.
@@ -70,17 +69,17 @@ public class TopologyInstance {
     /** Set of links that are blocked. */
     protected Set<Link> blockedLinks;
 
-    protected Set<DatapathId> switches;
+    protected Set<Long> switches;
     protected Set<NodePortTuple> broadcastDomainPorts;
     protected Set<NodePortTuple> tunnelPorts;
 
     protected Set<Cluster> clusters;  // set of openflow domains
-    protected Map<DatapathId, Cluster> switchClusterMap; // switch to OF domain map
+    protected Map<Long, Cluster> switchClusterMap; // switch to OF domain map
 
     // States for routing
-    protected Map<DatapathId, BroadcastTree> destinationRootedTrees;
-    protected Map<DatapathId, Set<NodePortTuple>> clusterBroadcastNodePorts;
-    protected Map<DatapathId, BroadcastTree> clusterBroadcastTrees;
+    protected Map<Long, BroadcastTree> destinationRootedTrees;
+    protected Map<Long, Set<NodePortTuple>> clusterBroadcastNodePorts;
+    protected Map<Long, BroadcastTree> clusterBroadcastTrees;
 
     protected class PathCacheLoader extends CacheLoader<RouteId, Route> {
         TopologyInstance ti;
@@ -100,8 +99,8 @@ public class TopologyInstance {
     protected LoadingCache<RouteId, Route> pathcache;
 
     public TopologyInstance() {
-        this.switches = new HashSet<DatapathId>();
-        this.switchPorts = new HashMap<DatapathId, Set<OFPort>>();
+        this.switches = new HashSet<Long>();
+        this.switchPorts = new HashMap<Long, Set<Short>>();
         this.switchPortLinks = new HashMap<NodePortTuple, Set<Link>>();
         this.broadcastDomainPorts = new HashSet<NodePortTuple>();
         this.tunnelPorts = new HashSet<NodePortTuple>();
@@ -109,12 +108,12 @@ public class TopologyInstance {
         this.blockedLinks = new HashSet<Link>();
     }
 
-    public TopologyInstance(Map<DatapathId, Set<OFPort>> switchPorts,
+    public TopologyInstance(Map<Long, Set<Short>> switchPorts,
                             Map<NodePortTuple, Set<Link>> switchPortLinks,
                             Set<NodePortTuple> broadcastDomainPorts)
     {
-        this.switches = new HashSet<DatapathId>(switchPorts.keySet());
-        this.switchPorts = new HashMap<DatapathId, Set<OFPort>>(switchPorts);
+        this.switches = new HashSet<Long>(switchPorts.keySet());
+        this.switchPorts = new HashMap<Long, Set<Short>>(switchPorts);
         this.switchPortLinks = new HashMap<NodePortTuple,
                 Set<Link>>(switchPortLinks);
         this.broadcastDomainPorts = new HashSet<NodePortTuple>(broadcastDomainPorts);
@@ -123,19 +122,19 @@ public class TopologyInstance {
         this.blockedLinks = new HashSet<Link>();
 
         clusters = new HashSet<Cluster>();
-        switchClusterMap = new HashMap<DatapathId, Cluster>();
+        switchClusterMap = new HashMap<Long, Cluster>();
     }
-    public TopologyInstance(Map<DatapathId, Set<OFPort>> switchPorts,
+    public TopologyInstance(Map<Long, Set<Short>> switchPorts,
                             Set<NodePortTuple> blockedPorts,
                             Map<NodePortTuple, Set<Link>> switchPortLinks,
                             Set<NodePortTuple> broadcastDomainPorts,
                             Set<NodePortTuple> tunnelPorts){
 
         // copy these structures
-        this.switches = new HashSet<DatapathId>(switchPorts.keySet());
-        this.switchPorts = new HashMap<DatapathId, Set<OFPort>>();
-        for(DatapathId sw: switchPorts.keySet()) {
-            this.switchPorts.put(sw, new HashSet<OFPort>(switchPorts.get(sw)));
+        this.switches = new HashSet<Long>(switchPorts.keySet());
+        this.switchPorts = new HashMap<Long, Set<Short>>();
+        for(long sw: switchPorts.keySet()) {
+            this.switchPorts.put(sw, new HashSet<Short>(switchPorts.get(sw)));
         }
 
         this.blockedPorts = new HashSet<NodePortTuple>(blockedPorts);
@@ -149,10 +148,10 @@ public class TopologyInstance {
 
         blockedLinks = new HashSet<Link>();
         clusters = new HashSet<Cluster>();
-        switchClusterMap = new HashMap<DatapathId, Cluster>();
-        destinationRootedTrees = new HashMap<DatapathId, BroadcastTree>();
-        clusterBroadcastTrees = new HashMap<DatapathId, BroadcastTree>();
-        clusterBroadcastNodePorts = new HashMap<DatapathId, Set<NodePortTuple>>();
+        switchClusterMap = new HashMap<Long, Cluster>();
+        destinationRootedTrees = new HashMap<Long, BroadcastTree>();
+        clusterBroadcastTrees = new HashMap<Long, BroadcastTree>();
+        clusterBroadcastNodePorts = new HashMap<Long, Set<NodePortTuple>>();
 
         pathcache = CacheBuilder.newBuilder().concurrencyLevel(4)
                     .maximumSize(1000L)
@@ -205,9 +204,9 @@ public class TopologyInstance {
     }
 
     protected void addLinksToOpenflowDomains() {
-        for(DatapathId s: switches) {
+        for(long s: switches) {
             if (switchPorts.get(s) == null) continue;
-            for (OFPort p: switchPorts.get(s)) {
+            for (short p: switchPorts.get(s)) {
                 NodePortTuple np = new NodePortTuple(s, p);
                 if (switchPortLinks.get(np) == null) continue;
                 if (isBroadcastDomainPort(np)) continue;
@@ -243,17 +242,17 @@ public class TopologyInstance {
             explanation="The internal state of the topology module is corrupt",
             recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
     public void identifyOpenflowDomains() {
-        Map<DatapathId, ClusterDFS> dfsList = new HashMap<DatapathId, ClusterDFS>();
+        Map<Long, ClusterDFS> dfsList = new HashMap<Long, ClusterDFS>();
 
         if (switches == null) return;
 
-        for (DatapathId key: switches) {
+        for (Long key: switches) {
             ClusterDFS cdfs = new ClusterDFS();
             dfsList.put(key, cdfs);
         }
-        Set<DatapathId> currSet = new HashSet<DatapathId>();
+        Set<Long> currSet = new HashSet<Long>();
 
-        for (DatapathId sw: switches) {
+        for (Long sw: switches) {
             ClusterDFS cdfs = dfsList.get(sw);
             if (cdfs == null) {
                 log.error("No DFS object for switch {} found.", sw);
@@ -292,15 +291,15 @@ public class TopologyInstance {
      * @param currSet: Set of nodes in the current cluster in formation
      * @return long: DSF index to be used when a new node is visited
      */
-    private long dfsTraverse (long parentIndex, long currIndex, DatapathId currSw,
-                              Map<DatapathId, ClusterDFS> dfsList, Set <DatapathId> currSet) {
+    private long dfsTraverse (long parentIndex, long currIndex, long currSw,
+                              Map<Long, ClusterDFS> dfsList, Set <Long> currSet) {
 
         //Get the DFS object corresponding to the current switch
         ClusterDFS currDFS = dfsList.get(currSw);
         // Get all the links corresponding to this switch
 
-        Set<DatapathId> nodesInMyCluster = new HashSet<DatapathId>();
-        Set<DatapathId> myCurrSet = new HashSet<DatapathId>();
+        Set<Long> nodesInMyCluster = new HashSet<Long>();
+        Set<Long> myCurrSet = new HashSet<Long>();
 
         //Assign the DFS object with right values.
         currDFS.setVisited(true);
@@ -310,14 +309,14 @@ public class TopologyInstance {
 
         // Traverse the graph through every outgoing link.
         if (switchPorts.get(currSw) != null){
-            for(OFPort p: switchPorts.get(currSw)) {
+            for(Short p: switchPorts.get(currSw)) {
                 Set<Link> lset = switchPortLinks.get(new NodePortTuple(currSw, p));
                 if (lset == null) continue;
                 for(Link l:lset) {
-                	DatapathId dstSw = l.getDst();
+                    long dstSw = l.getDst();
 
                     // ignore incoming links.
-                    if (dstSw.equals(currSw)) continue;
+                    if (dstSw == currSw) continue;
 
                     // ignore if the destination is already added to
                     // another cluster
@@ -369,7 +368,7 @@ public class TopologyInstance {
             // create a new switch cluster and the switches in the current
             // set to the switch cluster.
             Cluster sc = new Cluster();
-            for(DatapathId sw: currSet){
+            for(long sw: currSet){
                 sc.add(sw);
                 switchClusterMap.put(sw, sc);
             }
@@ -426,8 +425,8 @@ public class TopologyInstance {
     }
 
     protected class NodeDist implements Comparable<NodeDist> {
-        private final DatapathId node;
-        public DatapathId getNode() {
+        private final Long node;
+        public Long getNode() {
             return node;
         }
 
@@ -436,7 +435,7 @@ public class TopologyInstance {
             return dist;
         }
 
-        public NodeDist(DatapathId node, int dist) {
+        public NodeDist(Long node, int dist) {
             this.node = node;
             this.dist = dist;
         }
@@ -444,7 +443,7 @@ public class TopologyInstance {
         @Override
         public int compareTo(NodeDist o) {
             if (o.dist == this.dist) {
-                return (int)(this.node.getLong() - o.node.getLong());
+                return (int)(this.node - o.node);
             }
             return this.dist - o.dist;
         }
@@ -479,34 +478,34 @@ public class TopologyInstance {
         }
     }
 
-    protected BroadcastTree dijkstra(Cluster c, DatapathId root,
+    protected BroadcastTree dijkstra(Cluster c, Long root,
                                      Map<Link, Integer> linkCost,
                                      boolean isDstRooted) {
-        HashMap<DatapathId, Link> nexthoplinks = new HashMap<DatapathId, Link>();
+        HashMap<Long, Link> nexthoplinks = new HashMap<Long, Link>();
         //HashMap<Long, Long> nexthopnodes = new HashMap<Long, Long>();
-        HashMap<DatapathId, Integer> cost = new HashMap<DatapathId, Integer>();
+        HashMap<Long, Integer> cost = new HashMap<Long, Integer>();
         int w;
 
-        for (DatapathId node: c.links.keySet()) {
+        for (Long node: c.links.keySet()) {
             nexthoplinks.put(node, null);
             //nexthopnodes.put(node, null);
             cost.put(node, MAX_PATH_WEIGHT);
         }
 
-        HashMap<DatapathId, Boolean> seen = new HashMap<DatapathId, Boolean>();
+        HashMap<Long, Boolean> seen = new HashMap<Long, Boolean>();
         PriorityQueue<NodeDist> nodeq = new PriorityQueue<NodeDist>();
         nodeq.add(new NodeDist(root, 0));
         cost.put(root, 0);
         while (nodeq.peek() != null) {
             NodeDist n = nodeq.poll();
-            DatapathId cnode = n.getNode();
+            Long cnode = n.getNode();
             int cdist = n.getDist();
             if (cdist >= MAX_PATH_WEIGHT) break;
             if (seen.containsKey(cnode)) continue;
             seen.put(cnode, true);
 
             for (Link link: c.links.get(cnode)) {
-            	DatapathId neighbor;
+                Long neighbor;
 
                 if (isDstRooted == true) neighbor = link.getSrc();
                 else neighbor = link.getDst();
@@ -555,7 +554,7 @@ public class TopologyInstance {
         }
 
         for(Cluster c: clusters) {
-            for (DatapathId node : c.links.keySet()) {
+            for (Long node : c.links.keySet()) {
                 BroadcastTree tree = dijkstra(c, node, linkCost, true);
                 destinationRootedTrees.put(node, tree);
             }
@@ -582,9 +581,9 @@ public class TopologyInstance {
             //log.info("Broadcast Tree {}", tree);
 
             Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
-            Map<DatapathId, Link> links = tree.getLinks();
+            Map<Long, Link> links = tree.getLinks();
             if (links == null) continue;
-            for(DatapathId nodeId: links.keySet()) {
+            for(long nodeId: links.keySet()) {
                 Link l = links.get(nodeId);
                 if (l == null) continue;
                 NodePortTuple npt1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
@@ -598,8 +597,8 @@ public class TopologyInstance {
 
     protected Route buildroute(RouteId id) {
         NodePortTuple npt;
-        DatapathId srcId = id.getSrc();
-        DatapathId dstId = id.getDst();
+        long srcId = id.getSrc();
+        long dstId = id.getDst();
 
         LinkedList<NodePortTuple> switchPorts =
                 new LinkedList<NodePortTuple>();
@@ -607,7 +606,7 @@ public class TopologyInstance {
         if (destinationRootedTrees == null) return null;
         if (destinationRootedTrees.get(dstId) == null) return null;
 
-        Map<DatapathId, Link> nexthoplinks =
+        Map<Long, Link> nexthoplinks =
                 destinationRootedTrees.get(dstId).getLinks();
 
         if (!switches.contains(srcId) || !switches.contains(dstId)) {
@@ -641,7 +640,7 @@ public class TopologyInstance {
         return result;
     }
 
-    protected int getCost(DatapathId srcId, DatapathId dstId) {
+    protected int getCost(long srcId, long dstId) {
         BroadcastTree bt = destinationRootedTrees.get(dstId);
         if (bt == null) return -1;
         return (bt.getCost(srcId));
@@ -656,7 +655,7 @@ public class TopologyInstance {
     }
 
     // IRoutingEngineService interfaces
-    protected boolean routeExists(DatapathId srcId, DatapathId dstId) {
+    protected boolean routeExists(long srcId, long dstId) {
         BroadcastTree bt = destinationRootedTrees.get(dstId);
         if (bt == null) return false;
         Link link = bt.getLinks().get(srcId);
@@ -664,19 +663,19 @@ public class TopologyInstance {
         return true;
     }
 
-    protected Route getRoute(ServiceChain sc, DatapathId srcId, OFPort srcPort,
-    		DatapathId dstId, OFPort dstPort, long cookie) {
+    protected Route getRoute(ServiceChain sc, long srcId, short srcPort,
+                             long dstId, short dstPort, long cookie) {
 
 
         // Return null the route source and desitnation are the
         // same switchports.
-        if (srcId.equals(dstId) && srcPort.equals(dstPort))
+        if (srcId == dstId && srcPort == dstPort)
             return null;
 
         List<NodePortTuple> nptList;
         NodePortTuple npt;
         Route r = getRoute(srcId, dstId, 0);
-        if (r == null && !srcId.equals(dstId)) return null;
+        if (r == null && srcId != dstId) return null;
 
         if (r != null) {
             nptList= new ArrayList<NodePortTuple>(r.getPath());
@@ -696,9 +695,9 @@ public class TopologyInstance {
     // NOTE: Return a null route if srcId equals dstId.  The null route
     // need not be stored in the cache.  Moreover, the LoadingCache will
     // throw an exception if null route is returned.
-    protected Route getRoute(DatapathId srcId, DatapathId dstId, long cookie) {
+    protected Route getRoute(long srcId, long dstId, long cookie) {
         // Return null route if srcId equals dstId
-        if (srcId.equals(dstId)) return null;
+        if (srcId == dstId) return null;
 
 
         RouteId id = new RouteId(srcId, dstId);
@@ -726,54 +725,54 @@ public class TopologyInstance {
     //  ITopologyService interface method helpers.
     //
 
-    protected boolean isInternalToOpenflowDomain(DatapathId switchid, OFPort port) {
+    protected boolean isInternalToOpenflowDomain(long switchid, short port) {
         return !isAttachmentPointPort(switchid, port);
     }
 
-    public boolean isAttachmentPointPort(DatapathId switchid, OFPort port) {
+    public boolean isAttachmentPointPort(long switchid, short port) {
         NodePortTuple npt = new NodePortTuple(switchid, port);
         if (switchPortLinks.containsKey(npt)) return false;
         return true;
     }
 
-    protected DatapathId getOpenflowDomainId(DatapathId switchId) {
+    protected long getOpenflowDomainId(long switchId) {
         Cluster c = switchClusterMap.get(switchId);
         if (c == null) return switchId;
         return c.getId();
     }
 
-    protected DatapathId getL2DomainId(DatapathId switchId) {
+    protected long getL2DomainId(long switchId) {
         return getOpenflowDomainId(switchId);
     }
 
-    protected Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchId) {
+    protected Set<Long> getSwitchesInOpenflowDomain(long switchId) {
         Cluster c = switchClusterMap.get(switchId);
         if (c == null) {
             // The switch is not known to topology as there
             // are no links connected to it.
-            Set<DatapathId> nodes = new HashSet<DatapathId>();
+            Set<Long> nodes = new HashSet<Long>();
             nodes.add(switchId);
             return nodes;
         }
         return (c.getNodes());
     }
 
-    protected boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2) {
+    protected boolean inSameOpenflowDomain(long switch1, long switch2) {
         Cluster c1 = switchClusterMap.get(switch1);
         Cluster c2 = switchClusterMap.get(switch2);
         if (c1 != null && c2 != null)
-            return (c1.getId().equals(c2.getId()));
-        return (switch1.equals(switch2));
+            return (c1.getId() == c2.getId());
+        return (switch1 == switch2);
     }
 
-    public boolean isAllowed(DatapathId sw, OFPort portId) {
+    public boolean isAllowed(long sw, short portId) {
         return true;
     }
 
     protected boolean
-    isIncomingBroadcastAllowedOnSwitchPort(DatapathId sw, OFPort portId) {
+    isIncomingBroadcastAllowedOnSwitchPort(long sw, short portId) {
         if (isInternalToOpenflowDomain(sw, portId)) {
-        	DatapathId clusterId = getOpenflowDomainId(sw);
+            long clusterId = getOpenflowDomainId(sw);
             NodePortTuple npt = new NodePortTuple(sw, portId);
             if (clusterBroadcastNodePorts.get(clusterId).contains(npt))
                 return true;
@@ -782,52 +781,52 @@ public class TopologyInstance {
         return true;
     }
 
-    public boolean isConsistent(DatapathId oldSw, OFPort oldPort, DatapathId newSw,
-                                OFPort newPort) {
+    public boolean isConsistent(long oldSw, short oldPort, long newSw,
+                                short newPort) {
         if (isInternalToOpenflowDomain(newSw, newPort)) return true;
-        return (oldSw.equals(newSw) && oldPort.equals(newPort));
+        return (oldSw == newSw && oldPort == newPort);
     }
 
     protected Set<NodePortTuple>
-    getBroadcastNodePortsInCluster(DatapathId sw) {
-    	DatapathId clusterId = getOpenflowDomainId(sw);
+    getBroadcastNodePortsInCluster(long sw) {
+        long clusterId = getOpenflowDomainId(sw);
         return clusterBroadcastNodePorts.get(clusterId);
     }
 
-    public boolean inSameBroadcastDomain(DatapathId s1, OFPort p1, DatapathId s2, OFPort p2) {
+    public boolean inSameBroadcastDomain(long s1, short p1, long s2, short p2) {
         return false;
     }
 
-    public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2) {
+    public boolean inSameL2Domain(long switch1, long switch2) {
         return inSameOpenflowDomain(switch1, switch2);
     }
 
-    public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
-    		DatapathId dst, OFPort dstPort) {
+    public NodePortTuple getOutgoingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort) {
         // Use this function to redirect traffic if needed.
         return new NodePortTuple(dst, dstPort);
     }
 
-    public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
-    		DatapathId dst, OFPort dstPort) {
+    public NodePortTuple getIncomingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort) {
         // Use this function to reinject traffic from a
         // different port if needed.
         return new NodePortTuple(src, srcPort);
     }
 
-    public Set<DatapathId> getSwitches() {
+    public Set<Long> getSwitches() {
         return switches;
     }
 
-    public Set<OFPort> getPortsWithLinks(DatapathId sw) {
+    public Set<Short> getPortsWithLinks(long sw) {
         return switchPorts.get(sw);
     }
 
-    public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort) {
-        Set<OFPort> result = new HashSet<OFPort>();
-        DatapathId clusterId = getOpenflowDomainId(targetSw);
+    public Set<Short> getBroadcastPorts(long targetSw, long src, short srcPort) {
+        Set<Short> result = new HashSet<Short>();
+        long clusterId = getOpenflowDomainId(targetSw);
         for(NodePortTuple npt: clusterBroadcastNodePorts.get(clusterId)) {
-            if (npt.getNodeId().equals(targetSw)) {
+            if (npt.getNodeId() == targetSw) {
                 result.add(npt.getPortId());
             }
         }
@@ -835,13 +834,15 @@ public class TopologyInstance {
     }
 
     public NodePortTuple
-    getAllowedOutgoingBroadcastPort(DatapathId src, OFPort srcPort, DatapathId dst,
-                                    OFPort dstPort) {
+    getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst,
+                                    short dstPort) {
+        // TODO Auto-generated method stub
         return null;
     }
 
     public NodePortTuple
-    getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort) {
+    getAllowedIncomingBroadcastPort(long src, short srcPort) {
+        // TODO Auto-generated method stub
         return null;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
index dce7d28b92a0928d211a245ad49f678a1af87685..25b91464a1dd7aa8213e4987a0d0bf77abc6d39a 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
@@ -33,15 +33,13 @@ import java.util.concurrent.TimeUnit;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.HAListenerTypeMarker;
-import net.floodlightcontroller.core.HARole;
 import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
 import net.floodlightcontroller.core.IHAListener;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.LogicalOFMessageCategory;
 import net.floodlightcontroller.core.annotations.LogMessageCategory;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
-import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -52,7 +50,7 @@ import net.floodlightcontroller.debugcounter.IDebugCounter;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
 import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
-import net.floodlightcontroller.debugcounter.MockDebugCounterService;
+import net.floodlightcontroller.debugcounter.NullDebugCounter;
 import net.floodlightcontroller.debugevent.IDebugEventService;
 import net.floodlightcontroller.debugevent.IEventUpdater;
 import net.floodlightcontroller.debugevent.NullDebugEvent;
@@ -72,16 +70,13 @@ import net.floodlightcontroller.routing.Route;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.topology.web.TopologyWebRoutable;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFBufferId;
-import org.projectfloodlight.openflow.types.OFPort;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPacketOut;
+import org.openflow.protocol.OFPort;
+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;
 
@@ -106,12 +101,12 @@ public class TopologyManager implements
     /**
      * Role of the controller.
      */
-    private HARole role;
+    private Role role;
 
     /**
      * Set of ports for each switch
      */
-    protected Map<DatapathId, Set<OFPort>> switchPorts;
+    protected Map<Long, Set<Short>> switchPorts;
 
     /**
      * Set of links organized by node port tuple
@@ -136,7 +131,6 @@ public class TopologyManager implements
     protected ILinkDiscoveryService linkDiscovery;
     protected IThreadPoolService threadPool;
     protected IFloodlightProviderService floodlightProvider;
-    protected IOFSwitchService switchService;
     protected IRestApiService restApi;
     protected IDebugCounterService debugCounters;
 
@@ -194,11 +188,11 @@ public class TopologyManager implements
     protected class TopologyEventInfo {
         private final int numOpenflowClustersWithTunnels;
         private final int numOpenflowClustersWithoutTunnels;
-        private final Map<DatapathId, List<NodePortTuple>> externalPortsMap;
+        private final Map<Long, List<NodePortTuple>> externalPortsMap;
         private final int numTunnelPorts;
         public TopologyEventInfo(int numOpenflowClustersWithTunnels,
                                  int numOpenflowClustersWithoutTunnels,
-                                 Map<DatapathId, List<NodePortTuple>> externalPortsMap,
+                                 Map<Long, List<NodePortTuple>> externalPortsMap,
                                  int numTunnelPorts) {
             super();
             this.numOpenflowClustersWithTunnels = numOpenflowClustersWithTunnels;
@@ -221,7 +215,7 @@ public class TopologyManager implements
             if (numExternalClusters > 0) {
                 builder.append(" { ");
                 int count = 0;
-                for (DatapathId extCluster : externalPortsMap.keySet()) {
+                for (Long extCluster : externalPortsMap.keySet()) {
                     builder.append("#" + extCluster + ":Ext Ports: ");
                     builder.append(externalPortsMap.get(extCluster).size());
                     if (++count < numExternalClusters) {
@@ -293,7 +287,7 @@ public class TopologyManager implements
             catch (Exception e) {
                 log.error("Error in topology instance task thread", e);
             } finally {
-                if (floodlightProvider.getRole() != HARole.STANDBY)
+                if (floodlightProvider.getRole() != Role.SLAVE)
                     newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
                                            TimeUnit.MILLISECONDS);
             }
@@ -354,12 +348,12 @@ public class TopologyManager implements
     }
 
     @Override
-    public boolean isAttachmentPointPort(DatapathId switchid, OFPort port) {
+    public boolean isAttachmentPointPort(long switchid, short port) {
         return isAttachmentPointPort(switchid, port, true);
     }
 
     @Override
-    public boolean isAttachmentPointPort(DatapathId switchid, OFPort port,
+    public boolean isAttachmentPointPort(long switchid, short port,
                                          boolean tunnelEnabled) {
 
         // If the switch port is 'tun-bsn' port, it is not
@@ -377,56 +371,55 @@ public class TopologyManager implements
 
         // Check whether the port is a physical port. We should not learn
         // attachment points on "special" ports.
-        //TODO @Ryan port numbers should be handled as ints now, not shorts. I suppose anything above 65280 up to 65533 is a "special" non-physical port.
-        if ((port.getShortPortNumber() & 0xff00) == 0xff00 && port.getShortPortNumber() != (short)0xfffe) return false;
+        if ((port & 0xff00) == 0xff00 && port != (short)0xfffe) return false;
 
         // Make sure that the port is enabled.
-        IOFSwitch sw = switchService.getActiveSwitch(switchid);
+        IOFSwitch sw = floodlightProvider.getSwitch(switchid);
         if (sw == null) return false;
         return (sw.portEnabled(port));
     }
 
     @Override
-    public DatapathId getOpenflowDomainId(DatapathId switchId) {
+    public long getOpenflowDomainId(long switchId) {
         return getOpenflowDomainId(switchId, true);
     }
 
     @Override
-    public DatapathId getOpenflowDomainId(DatapathId switchId, boolean tunnelEnabled) {
+    public long getOpenflowDomainId(long switchId, boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getOpenflowDomainId(switchId);
     }
 
     @Override
-    public DatapathId getL2DomainId(DatapathId switchId) {
+    public long getL2DomainId(long switchId) {
         return getL2DomainId(switchId, true);
     }
 
     @Override
-    public DatapathId getL2DomainId(DatapathId switchId, boolean tunnelEnabled) {
+    public long getL2DomainId(long switchId, boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getL2DomainId(switchId);
     }
 
     @Override
-    public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2) {
+    public boolean inSameOpenflowDomain(long switch1, long switch2) {
         return inSameOpenflowDomain(switch1, switch2, true);
     }
 
     @Override
-    public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2,
+    public boolean inSameOpenflowDomain(long switch1, long switch2,
                                         boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.inSameOpenflowDomain(switch1, switch2);
     }
 
     @Override
-    public boolean isAllowed(DatapathId sw, OFPort portId) {
+    public boolean isAllowed(long sw, short portId) {
         return isAllowed(sw, portId, true);
     }
 
     @Override
-    public boolean isAllowed(DatapathId sw, OFPort portId, boolean tunnelEnabled) {
+    public boolean isAllowed(long sw, short portId, boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.isAllowed(sw, portId);
     }
@@ -434,12 +427,12 @@ public class TopologyManager implements
     ////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////
     @Override
-    public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId) {
+    public boolean isIncomingBroadcastAllowed(long sw, short portId) {
         return isIncomingBroadcastAllowed(sw, portId, true);
     }
 
     @Override
-    public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId,
+    public boolean isIncomingBroadcastAllowed(long sw, short portId,
                                               boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.isIncomingBroadcastAllowedOnSwitchPort(sw, portId);
@@ -449,13 +442,13 @@ public class TopologyManager implements
     ////////////////////////////////////////////////////////////////////////
     /** Get all the ports connected to the switch */
     @Override
-    public Set<OFPort> getPortsWithLinks(DatapathId sw) {
+    public Set<Short> getPortsWithLinks(long sw) {
         return getPortsWithLinks(sw, true);
     }
 
     /** Get all the ports connected to the switch */
     @Override
-    public Set<OFPort> getPortsWithLinks(DatapathId sw, boolean tunnelEnabled) {
+    public Set<Short> getPortsWithLinks(long sw, boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getPortsWithLinks(sw);
     }
@@ -467,8 +460,8 @@ public class TopologyManager implements
      * is on switch port (src, srcPort).
      */
     @Override
-    public Set<OFPort> getBroadcastPorts(DatapathId targetSw,
-    		DatapathId src, OFPort srcPort) {
+    public Set<Short> getBroadcastPorts(long targetSw,
+                                        long src, short srcPort) {
         return getBroadcastPorts(targetSw, src, srcPort, true);
     }
 
@@ -477,8 +470,8 @@ public class TopologyManager implements
      * is on switch port (src, srcPort).
      */
     @Override
-    public Set<OFPort> getBroadcastPorts(DatapathId targetSw,
-    		DatapathId src, OFPort srcPort,
+    public Set<Short> getBroadcastPorts(long targetSw,
+                                        long src, short srcPort,
                                         boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getBroadcastPorts(targetSw, src, srcPort);
@@ -487,15 +480,15 @@ public class TopologyManager implements
     ////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////
     @Override
-    public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
-    		DatapathId dst, OFPort dstPort) {
+    public NodePortTuple getOutgoingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort) {
         // Use this function to redirect traffic if needed.
         return getOutgoingSwitchPort(src, srcPort, dst, dstPort, true);
     }
 
     @Override
-    public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
-    		DatapathId dst, OFPort dstPort,
+    public NodePortTuple getOutgoingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort,
                                                boolean tunnelEnabled) {
         // Use this function to redirect traffic if needed.
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
@@ -506,14 +499,14 @@ public class TopologyManager implements
     ////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////
     @Override
-    public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
-    		DatapathId dst, OFPort dstPort) {
+    public NodePortTuple getIncomingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort) {
         return getIncomingSwitchPort(src, srcPort, dst, dstPort, true);
     }
 
     @Override
-    public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
-    		DatapathId dst, OFPort dstPort,
+    public NodePortTuple getIncomingSwitchPort(long src, short srcPort,
+                                               long dst, short dstPort,
                                                boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getIncomingSwitchPort(src, srcPort,
@@ -526,15 +519,15 @@ public class TopologyManager implements
      * Checks if the two switchports belong to the same broadcast domain.
      */
     @Override
-    public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1, DatapathId s2,
-    		OFPort p2) {
+    public boolean isInSameBroadcastDomain(long s1, short p1, long s2,
+                                           short p2) {
         return isInSameBroadcastDomain(s1, p1, s2, p2, true);
 
     }
 
     @Override
-    public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1,
-    		DatapathId s2, OFPort p2,
+    public boolean isInSameBroadcastDomain(long s1, short p1,
+                                           long s2, short p2,
                                            boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.inSameBroadcastDomain(s1, p1, s2, p2);
@@ -547,12 +540,12 @@ public class TopologyManager implements
      * Checks if the switchport is a broadcast domain port or not.
      */
     @Override
-    public boolean isBroadcastDomainPort(DatapathId sw, OFPort port) {
+    public boolean isBroadcastDomainPort(long sw, short port) {
         return isBroadcastDomainPort(sw, port, true);
     }
 
     @Override
-    public boolean isBroadcastDomainPort(DatapathId sw, OFPort port,
+    public boolean isBroadcastDomainPort(long sw, short port,
                                          boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.isBroadcastDomainPort(new NodePortTuple(sw, port));
@@ -565,15 +558,15 @@ public class TopologyManager implements
      * old attachment point port.
      */
     @Override
-    public boolean isConsistent(DatapathId oldSw, OFPort oldPort,
-    		DatapathId newSw, OFPort newPort) {
+    public boolean isConsistent(long oldSw, short oldPort,
+                                long newSw, short newPort) {
         return isConsistent(oldSw, oldPort,
                                             newSw, newPort, true);
     }
 
     @Override
-    public boolean isConsistent(DatapathId oldSw, OFPort oldPort,
-    		DatapathId newSw, OFPort newPort,
+    public boolean isConsistent(long oldSw, short oldPort,
+                                long newSw, short newPort,
                                 boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.isConsistent(oldSw, oldPort, newSw, newPort);
@@ -585,12 +578,12 @@ public class TopologyManager implements
      * Checks if the two switches are in the same Layer 2 domain.
      */
     @Override
-    public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2) {
+    public boolean inSameL2Domain(long switch1, long switch2) {
         return inSameL2Domain(switch1, switch2, true);
     }
 
     @Override
-    public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2,
+    public boolean inSameL2Domain(long switch1, long switch2,
                                   boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.inSameL2Domain(switch1, switch2);
@@ -599,19 +592,19 @@ public class TopologyManager implements
     ////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////
     @Override
-    public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src,
-    		OFPort srcPort,
-                                                         DatapathId dst,
-                                                         OFPort dstPort) {
+    public NodePortTuple getAllowedOutgoingBroadcastPort(long src,
+                                                         short srcPort,
+                                                         long dst,
+                                                         short dstPort) {
         return getAllowedOutgoingBroadcastPort(src, srcPort,
                                                dst, dstPort, true);
     }
 
     @Override
-    public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src,
-    		OFPort srcPort,
-                                                         DatapathId dst,
-                                                         OFPort dstPort,
+    public NodePortTuple getAllowedOutgoingBroadcastPort(long src,
+                                                         short srcPort,
+                                                         long dst,
+                                                         short dstPort,
                                                          boolean tunnelEnabled){
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getAllowedOutgoingBroadcastPort(src, srcPort,
@@ -621,13 +614,13 @@ public class TopologyManager implements
     ////////////////////////////////////////////////////////////////////////
     @Override
     public NodePortTuple
-    getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort) {
+    getAllowedIncomingBroadcastPort(long src, short srcPort) {
         return getAllowedIncomingBroadcastPort(src,srcPort, true);
     }
 
     @Override
     public NodePortTuple
-    getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort,
+    getAllowedIncomingBroadcastPort(long src, short srcPort,
                                     boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getAllowedIncomingBroadcastPort(src,srcPort);
@@ -636,12 +629,12 @@ public class TopologyManager implements
     ////////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////////
     @Override
-    public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID) {
+    public Set<Long> getSwitchesInOpenflowDomain(long switchDPID) {
         return getSwitchesInOpenflowDomain(switchDPID, true);
     }
 
     @Override
-    public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID,
+    public Set<Long> getSwitchesInOpenflowDomain(long switchDPID,
                                                  boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getSwitchesInOpenflowDomain(switchDPID);
@@ -685,41 +678,41 @@ public class TopologyManager implements
     // ***************
 
     @Override
-    public Route getRoute(DatapathId src, DatapathId dst, long cookie) {
+    public Route getRoute(long src, long dst, long cookie) {
         return getRoute(src, dst, cookie, true);
     }
 
     @Override
-    public Route getRoute(DatapathId src, DatapathId dst, long cookie, boolean tunnelEnabled) {
+    public Route getRoute(long src, long dst, long cookie, boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getRoute(src, dst, cookie);
     }
 
     @Override
-    public Route getRoute(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort, long cookie) {
+    public Route getRoute(long src, short srcPort, long dst, short dstPort, long cookie) {
         return getRoute(src, srcPort, dst, dstPort, cookie, true);
     }
 
     @Override
-    public Route getRoute(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort, long cookie,
+    public Route getRoute(long src, short srcPort, long dst, short dstPort, long cookie,
                           boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.getRoute(null, src, srcPort, dst, dstPort, cookie);
     }
 
     @Override
-    public boolean routeExists(DatapathId src, DatapathId dst) {
+    public boolean routeExists(long src, long dst) {
         return routeExists(src, dst, true);
     }
 
     @Override
-    public boolean routeExists(DatapathId src, DatapathId dst, boolean tunnelEnabled) {
+    public boolean routeExists(long src, long dst, boolean tunnelEnabled) {
         TopologyInstance ti = getCurrentInstance(tunnelEnabled);
         return ti.routeExists(src, dst);
     }
 
     @Override
-    public ArrayList<Route> getRoutes(DatapathId srcDpid, DatapathId dstDpid,
+    public ArrayList<Route> getRoutes(long srcDpid, long dstDpid,
                                       boolean tunnelEnabled) {
         // Floodlight supports single path routing now
 
@@ -753,7 +746,7 @@ public class TopologyManager implements
                            FloodlightContext cntx) {
         switch (msg.getType()) {
             case PACKET_IN:
-                ctrIncoming.increment();
+                ctrIncoming.updateCounterNoFlush();
                 return this.processPacketInMessage(sw,
                                                    (OFPacketIn) msg, cntx);
             default:
@@ -769,10 +762,10 @@ public class TopologyManager implements
 
     private class HAListenerDelegate implements IHAListener {
         @Override
-        public void transitionToActive() {
-            role = HARole.ACTIVE;
+        public void transitionToMaster() {
+            role = Role.MASTER;
             log.debug("Re-computing topology due " +
-                    "to HA change from STANDBY->ACTIVE");
+                    "to HA change from SLAVE->MASTER");
             newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
                                        TimeUnit.MILLISECONDS);
         }
@@ -803,12 +796,6 @@ public class TopologyManager implements
             // TODO Auto-generated method stub
             return false;
         }
-
-		@Override
-		public void transitionToStandby() {
-			// TODO Auto-generated method stub
-			
-		}
     }
 
     // *****************
@@ -845,7 +832,6 @@ public class TopologyManager implements
         l.add(ILinkDiscoveryService.class);
         l.add(IThreadPoolService.class);
         l.add(IFloodlightProviderService.class);
-        l.add(IOFSwitchService.class);
         l.add(ICounterStoreService.class);
         l.add(IRestApiService.class);
         return l;
@@ -858,12 +844,11 @@ public class TopologyManager implements
         threadPool = context.getServiceImpl(IThreadPoolService.class);
         floodlightProvider =
                 context.getServiceImpl(IFloodlightProviderService.class);
-        switchService = context.getServiceImpl(IOFSwitchService.class);
         restApi = context.getServiceImpl(IRestApiService.class);
         debugCounters = context.getServiceImpl(IDebugCounterService.class);
         debugEvents = context.getServiceImpl(IDebugEventService.class);
 
-        switchPorts = new HashMap<DatapathId, Set<OFPort>>();
+        switchPorts = new HashMap<Long,Set<Short>>();
         switchPortLinks = new HashMap<NodePortTuple, Set<Link>>();
         directLinks = new HashMap<NodePortTuple, Set<Link>>();
         portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>();
@@ -899,7 +884,7 @@ public class TopologyManager implements
         ScheduledExecutorService ses = threadPool.getScheduledExecutor();
         newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker());
 
-        if (role != HARole.STANDBY)
+        if (role != Role.SLAVE)
             newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
                                    TimeUnit.MILLISECONDS);
 
@@ -939,17 +924,17 @@ public class TopologyManager implements
      * @param cntx
      * @return
      */
-    protected Command dropFilter(DatapathId sw, OFPacketIn pi,
+    protected Command dropFilter(long sw, OFPacketIn pi,
                                              FloodlightContext cntx) {
         Command result = Command.CONTINUE;
-        OFPort port = pi.getInPort();
+        short port = pi.getInPort();
 
         // If the input port is not allowed for data traffic, drop everything.
         // BDDP packets will not reach this stage.
         if (isAllowed(sw, port) == false) {
             if (log.isTraceEnabled()) {
                 log.trace("Ignoring packet because of topology " +
-                        "restriction on switch={}, port={}", sw.getLong(), port.getPortNumber());
+                        "restriction on switch={}, port={}", sw, port);
                 result = Command.STOP;
             }
         }
@@ -970,45 +955,49 @@ public class TopologyManager implements
             		"topology discovery packet",
             recommendation=LogMessageDoc.CHECK_SWITCH)
     public void doMultiActionPacketOut(byte[] packetData, IOFSwitch sw,
-                                       Set<OFPort> ports,
+                                       Set<Short> ports,
                                        FloodlightContext cntx) {
 
         if (ports == null) return;
         if (packetData == null || packetData.length <= 0) return;
 
-        //OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
-        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
+        OFPacketOut po =
+                (OFPacketOut) floodlightProvider.getOFMessageFactory().
+                getMessage(OFType.PACKET_OUT);
+
         List<OFAction> actions = new ArrayList<OFAction>();
-        for(OFPort p: ports) {
-            //actions.add(new OFActionOutput(p, (short) 0));
-            actions.add(sw.getOFFactory().actions().output(p, 0));
+        for(short p: ports) {
+            actions.add(new OFActionOutput(p, (short) 0));
         }
 
         // set actions
-        pob.setActions(actions);
+        po.setActions(actions);
         // set action length
-        //po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * ports.size()));
+        po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH *
+                ports.size()));
         // set buffer-id to BUFFER_ID_NONE
-        pob.setBufferId(OFBufferId.NO_BUFFER);
+        po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
         // set in-port to OFPP_NONE
-        pob.setInPort(OFPort.ZERO);
+        po.setInPort(OFPort.OFPP_NONE.getValue());
 
         // set packet data
-        pob.setData(packetData);
+        po.setPacketData(packetData);
 
         // compute and set packet length.
-        //short poLength = (short)(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + packetData.length);
+        short poLength = (short)(OFPacketOut.MINIMUM_LENGTH +
+                po.getActionsLength() +
+                packetData.length);
 
-        //po.setLength(poLength);
+        po.setLength(poLength);
 
         try {
             //counterStore.updatePktOutFMCounterStore(sw, po);
             if (log.isTraceEnabled()) {
                 log.trace("write broadcast packet on switch-id={} " +
                         "interaces={} packet-data={} packet-out={}",
-                        new Object[] {sw.getId(), ports, packetData, pob.build()});
+                        new Object[] {sw.getId(), ports, packetData, po});
             }
-            sw.write(pob.build(), LogicalOFMessageCategory.MAIN);
+            sw.write(po, cntx);
 
         } catch (IOException e) {
             log.error("Failure writing packet out", e);
@@ -1023,11 +1012,11 @@ public class TopologyManager implements
      * @param sid
      * @return
      */
-    protected Set<OFPort> getPortsToEliminateForBDDP(DatapathId sid) {
+    protected Set<Short> getPortsToEliminateForBDDP(long sid) {
         Set<NodePortTuple> suppressedNptList = linkDiscovery.getSuppressLLDPsInfo();
         if (suppressedNptList == null) return null;
 
-        Set<OFPort> resultPorts = new HashSet<OFPort>();
+        Set<Short> resultPorts = new HashSet<Short>();
         for(NodePortTuple npt: suppressedNptList) {
             if (npt.getNodeId() == sid) {
                 resultPorts.add(npt.getPortId());
@@ -1046,36 +1035,36 @@ public class TopologyManager implements
      * @param pi
      * @param cntx
      */
-    protected void doFloodBDDP(DatapathId pinSwitch, OFPacketIn pi,
+    protected void doFloodBDDP(long pinSwitch, OFPacketIn pi,
                                FloodlightContext cntx) {
 
         TopologyInstance ti = getCurrentInstance(false);
 
-        Set<DatapathId> switches = ti.getSwitchesInOpenflowDomain(pinSwitch);
+        Set<Long> switches = ti.getSwitchesInOpenflowDomain(pinSwitch);
 
         if (switches == null)
         {
             // indicates no links are connected to the switches
-            switches = new HashSet<DatapathId>();
+            switches = new HashSet<Long>();
             switches.add(pinSwitch);
         }
 
-        for(DatapathId sid: switches) {
-            IOFSwitch sw = switchService.getSwitch(sid);
+        for(long sid: switches) {
+            IOFSwitch sw = floodlightProvider.getSwitch(sid);
             if (sw == null) continue;
-            Collection<OFPort> enabledPorts = sw.getEnabledPortNumbers();
+            Collection<Short> enabledPorts = sw.getEnabledPortNumbers();
             if (enabledPorts == null)
                 continue;
-            Set<OFPort> ports = new HashSet<OFPort>();
+            Set<Short> ports = new HashSet<Short>();
             ports.addAll(enabledPorts);
 
             // all the ports known to topology // without tunnels.
             // out of these, we need to choose only those that are
             // broadcast port, otherwise, we should eliminate.
-            Set<OFPort> portsKnownToTopo = ti.getPortsWithLinks(sid);
+            Set<Short> portsKnownToTopo = ti.getPortsWithLinks(sid);
 
             if (portsKnownToTopo != null) {
-                for(OFPort p: portsKnownToTopo) {
+                for(short p: portsKnownToTopo) {
                     NodePortTuple npt =
                             new NodePortTuple(sid, p);
                     if (ti.isBroadcastDomainPort(npt) == false) {
@@ -1084,7 +1073,7 @@ public class TopologyManager implements
                 }
             }
 
-            Set<OFPort> portsToEliminate = getPortsToEliminateForBDDP(sid);
+            Set<Short> portsToEliminate = getPortsToEliminateForBDDP(sid);
             if (portsToEliminate != null) {
                 ports.removeAll(portsToEliminate);
             }
@@ -1095,7 +1084,7 @@ public class TopologyManager implements
             }
 
             // we have all the switch ports to which we need to broadcast.
-            doMultiActionPacketOut(pi.getData(), sw, ports, cntx);
+            doMultiActionPacketOut(pi.getPacketData(), sw, ports, cntx);
         }
 
     }
@@ -1179,18 +1168,18 @@ public class TopologyManager implements
         return (Collections.unmodifiableList(appliedUpdates));
     }
 
-    protected void addOrUpdateSwitch(DatapathId sw) {
+    protected void addOrUpdateSwitch(long sw) {
         // nothing to do here for the time being.
         return;
     }
 
-    public void addTunnelPort(DatapathId sw, OFPort port) {
+    public void addTunnelPort(long sw, short port) {
         NodePortTuple npt = new NodePortTuple(sw, port);
         tunnelPorts.add(npt);
         tunnelPortsUpdated = true;
     }
 
-    public void removeTunnelPort(DatapathId sw, OFPort port) {
+    public void removeTunnelPort(long sw, short port) {
         NodePortTuple npt = new NodePortTuple(sw, port);
         tunnelPorts.remove(npt);
         tunnelPortsUpdated = true;
@@ -1259,7 +1248,7 @@ public class TopologyManager implements
 
         TopologyEventInfo topologyInfo =
                 new TopologyEventInfo(0, nt.getClusters().size(),
-                                      new HashMap<DatapathId, List<NodePortTuple>>(),
+                                      new HashMap<Long, List<NodePortTuple>>(),
                                       0);
         evTopology.updateEventWithFlush(new TopologyEvent(reason,
                                                           topologyInfo));
@@ -1329,27 +1318,27 @@ public class TopologyManager implements
 
     public void informListeners(List<LDUpdate> linkUpdates) {
 
-        if (role != null && role != HARole.ACTIVE)
+        if (role != null && role != Role.MASTER)
             return;
 
-        for(int i=0; i < topologyAware.size(); ++i) {
+        for(int i=0; i<topologyAware.size(); ++i) {
             ITopologyListener listener = topologyAware.get(i);
             listener.topologyChanged(linkUpdates);
         }
     }
 
-    public void addSwitch(DatapathId sid) {
+    public void addSwitch(long sid) {
         if (switchPorts.containsKey(sid) == false) {
-            switchPorts.put(sid, new HashSet<OFPort>());
+            switchPorts.put(sid, new HashSet<Short>());
         }
     }
 
-    private void addPortToSwitch(DatapathId s, OFPort p) {
+    private void addPortToSwitch(long s, short p) {
         addSwitch(s);
         switchPorts.get(s).add(p);
     }
 
-    public void removeSwitch(DatapathId sid) {
+    public void removeSwitch(long sid) {
         // Delete all the links in the switch, switch and all
         // associated data should be deleted.
         if (switchPorts.containsKey(sid) == false) return;
@@ -1362,7 +1351,7 @@ public class TopologyManager implements
         }
 
         Set<Link> linksToRemove = new HashSet<Link>();
-        for(OFPort p: switchPorts.get(sid)) {
+        for(Short p: switchPorts.get(sid)) {
             NodePortTuple n1 = new NodePortTuple(sid, p);
             linksToRemove.addAll(switchPortLinks.get(n1));
         }
@@ -1425,13 +1414,13 @@ public class TopologyManager implements
         return result1 || result2;
     }
 
-    protected void addOrUpdateTunnelLink(DatapathId srcId, OFPort srcPort, DatapathId dstId,
-                                    OFPort dstPort) {
+    protected void addOrUpdateTunnelLink(long srcId, short srcPort, long dstId,
+                                    short dstPort) {
         // If you need to handle tunnel links, this is a placeholder.
     }
 
-    public void addOrUpdateLink(DatapathId srcId, OFPort srcPort, DatapathId dstId,
-                                OFPort dstPort, LinkType type) {
+    public void addOrUpdateLink(long srcId, short srcPort, long dstId,
+                                short dstPort, LinkType type) {
         Link link = new Link(srcId, srcPort, dstId, dstPort);
 
         if (type.equals(LinkType.MULTIHOP_LINK)) {
@@ -1488,8 +1477,8 @@ public class TopologyManager implements
         }
     }
 
-    public void removeLink(DatapathId srcId, OFPort srcPort,
-    		DatapathId dstId, OFPort dstPort) {
+    public void removeLink(long srcId, short srcPort,
+                           long dstId, short dstPort) {
         Link link = new Link(srcId, srcPort, dstId, dstPort);
         removeLink(link);
     }
@@ -1518,7 +1507,7 @@ public class TopologyManager implements
     /**
      * Getters.  No Setters.
      */
-    public Map<DatapathId, Set<OFPort>> getSwitchPorts() {
+    public Map<Long, Set<Short>> getSwitchPorts() {
         return switchPorts;
     }
 
@@ -1544,15 +1533,15 @@ public class TopologyManager implements
      *  Switch methods
      */
     @Override
-    public Set<OFPort> getPorts(DatapathId sw) {
-        IOFSwitch iofSwitch = switchService.getSwitch(sw);
+    public Set<Short> getPorts(long sw) {
+        IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
         if (iofSwitch == null) return Collections.emptySet();
 
-        Collection<OFPort> ofpList = iofSwitch.getEnabledPortNumbers();
+        Collection<Short> ofpList = iofSwitch.getEnabledPortNumbers();
         if (ofpList == null) return Collections.emptySet();
 
-        Set<OFPort> ports = new HashSet<OFPort>(ofpList);
-        Set<OFPort> qPorts = linkDiscovery.getQuarantinedPorts(sw);
+        Set<Short> ports = new HashSet<Short>(ofpList);
+        Set<Short> qPorts = linkDiscovery.getQuarantinedPorts(sw);
         if (qPorts != null)
             ports.removeAll(qPorts);
 
diff --git a/src/main/java/net/floodlightcontroller/util/OFMessageDamper.java b/src/main/java/net/floodlightcontroller/util/OFMessageDamper.java
index eb4c368e80b4131d8eff36879cbb5b86564f2ae9..75b0b00d3a9fb082e14a18e3da34712fcdee4e36 100644
--- a/src/main/java/net/floodlightcontroller/util/OFMessageDamper.java
+++ b/src/main/java/net/floodlightcontroller/util/OFMessageDamper.java
@@ -22,10 +22,9 @@ import java.util.Set;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.LogicalOFMessageCategory;
 
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFType;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
 
 /**
  * Dampens OFMessages sent to an OF switch. A message is only written to 
@@ -135,7 +134,7 @@ public class OFMessageDamper {
                         FloodlightContext cntx, boolean flush) 
             throws IOException {
         if (! msgTypesToCache.contains(msg.getType())) {
-            sw.write(msg, LogicalOFMessageCategory.MAIN);
+            sw.writeThrottled(msg, cntx);
             if (flush) {
                 sw.flush();
             }
@@ -147,7 +146,7 @@ public class OFMessageDamper {
             // entry exists in cache. Dampening.
             return false; 
         } else {
-            sw.write(msg, LogicalOFMessageCategory.MAIN);
+            sw.writeThrottled(msg, cntx);
             if (flush) {
                 sw.flush();
             }
diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java
index 258368329d1a5c71023c73c2037e7d59c23c31ab..1d64144dcf19a3d9a73fce36b3976f8b7d4cbaec 100644
--- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java
+++ b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java
@@ -28,14 +28,14 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
-import org.projectfloodlight.openflow.protocol.OFFlowMod;
-import org.projectfloodlight.openflow.protocol.OFMatch;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.util.HexString;
+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.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/src/main/java/org/openflow/protocol/Instantiable.java b/src/main/java/org/openflow/protocol/Instantiable.java
new file mode 100644
index 0000000000000000000000000000000000000000..1358ba7526f2b59d7f37ea23e94a723c8e2d2e50
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/Instantiable.java
@@ -0,0 +1,31 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface Instantiable<E> {
+
+    /**
+     * Create a new instance of a given subclass.
+     * @return the new instance.
+     */
+    public E instantiate();
+}
diff --git a/src/main/java/org/openflow/protocol/OFBarrierReply.java b/src/main/java/org/openflow/protocol/OFBarrierReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..a79a15f07918f4db09db438f68f03b048cfc4bf1
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFBarrierReply.java
@@ -0,0 +1,32 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an OFPT_BARRIER_REPLY message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFBarrierReply extends OFMessage {
+    public OFBarrierReply() {
+        super();
+        this.type = OFType.BARRIER_REPLY;
+        this.length = U16.t(OFMessage.MINIMUM_LENGTH);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFBarrierRequest.java b/src/main/java/org/openflow/protocol/OFBarrierRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..999218636550dac8af837f95a69480a3b596aa02
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFBarrierRequest.java
@@ -0,0 +1,32 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an OFPT_BARRIER_REQUEST message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFBarrierRequest extends OFMessage {
+    public OFBarrierRequest() {
+        super();
+        this.type = OFType.BARRIER_REQUEST;
+        this.length = U16.t(OFMessage.MINIMUM_LENGTH);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFEchoReply.java b/src/main/java/org/openflow/protocol/OFEchoReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e282a74a052e5dcb1792e40d2402e1352555244
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFEchoReply.java
@@ -0,0 +1,36 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_echo_reply message
+ * 
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+
+public class OFEchoReply extends OFEchoRequest {
+    public static int MINIMUM_LENGTH = 8;
+
+    public OFEchoReply() {
+        super();
+        this.type = OFType.ECHO_REPLY;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFEchoRequest.java b/src/main/java/org/openflow/protocol/OFEchoRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..295a3972e8a29d5ed928150d2076ac6d6e16fd52
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFEchoRequest.java
@@ -0,0 +1,101 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_echo_request message
+ * 
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+
+public class OFEchoRequest extends OFMessage {
+    public static int MINIMUM_LENGTH = 8;
+    byte[] payload;
+
+    public OFEchoRequest() {
+        super();
+        this.type = OFType.ECHO_REQUEST;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer bb) {
+        super.readFrom(bb);
+        int datalen = this.getLengthU() - MINIMUM_LENGTH;
+        if (datalen > 0) {
+            this.payload = new byte[datalen];
+            bb.readBytes(payload);
+        }
+    }
+
+    /**
+     * @return the payload
+     */
+    public byte[] getPayload() {
+        return payload;
+    }
+
+    /**
+     * @param payload
+     *            the payload to set
+     */
+    public void setPayload(byte[] payload) {
+        this.payload = payload;
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer bb) {
+        super.writeTo(bb);
+        if (payload != null)
+            bb.writeBytes(payload);
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(payload);
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        OFEchoRequest other = (OFEchoRequest) obj;
+        if (!Arrays.equals(payload, other.payload))
+            return false;
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFError.java b/src/main/java/org/openflow/protocol/OFError.java
new file mode 100644
index 0000000000000000000000000000000000000000..df7b236024c9370d43c5f28392548319cd83f7ce
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFError.java
@@ -0,0 +1,325 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.factory.MessageParseException;
+import org.openflow.protocol.factory.OFMessageFactory;
+import org.openflow.protocol.factory.OFMessageFactoryAware;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_error_msg
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class OFError extends OFMessage implements OFMessageFactoryAware {
+    public static int MINIMUM_LENGTH = 12;
+
+    public enum OFErrorType {
+        // OFPET_VENDOR_ERROR is an extension that was added in Open vSwitch and isn't
+        // in the OF 1.0 spec, but it was easier to add it here instead of adding
+        // generic support for extensible vendor-defined error messages.
+        // It uses the random value 0xb0c2 to avoid conflicts with other possible new
+        // error types. Support for vendor-defined extended errors has been standardized
+        // in the OF 1.2 spec, so this workaround is only needed for 1.0.
+        OFPET_HELLO_FAILED, OFPET_BAD_REQUEST, OFPET_BAD_ACTION, OFPET_FLOW_MOD_FAILED, OFPET_PORT_MOD_FAILED, OFPET_QUEUE_OP_FAILED, OFPET_VENDOR_ERROR((short)0xb0c2);
+
+        protected short value;
+
+        private OFErrorType() {
+            this.value = (short) this.ordinal();
+        }
+
+        private OFErrorType(short value) {
+            this.value = value;
+        }
+
+        public short getValue() {
+            return value;
+        }
+    }
+
+    public enum OFHelloFailedCode {
+        OFPHFC_INCOMPATIBLE, OFPHFC_EPERM
+    }
+
+    public enum OFBadRequestCode {
+        OFPBRC_BAD_VERSION, OFPBRC_BAD_TYPE, OFPBRC_BAD_STAT, OFPBRC_BAD_VENDOR, OFPBRC_BAD_SUBTYPE, OFPBRC_EPERM, OFPBRC_BAD_LEN, OFPBRC_BUFFER_EMPTY, OFPBRC_BUFFER_UNKNOWN
+    }
+
+    public enum OFBadActionCode {
+        OFPBAC_BAD_TYPE, OFPBAC_BAD_LEN, OFPBAC_BAD_VENDOR, OFPBAC_BAD_VENDOR_TYPE, OFPBAC_BAD_OUT_PORT, OFPBAC_BAD_ARGUMENT, OFPBAC_EPERM, OFPBAC_TOO_MANY, OFPBAC_BAD_QUEUE
+    }
+
+    public enum OFFlowModFailedCode {
+        OFPFMFC_ALL_TABLES_FULL, OFPFMFC_OVERLAP, OFPFMFC_EPERM, OFPFMFC_BAD_EMERG_TIMEOUT, OFPFMFC_BAD_COMMAND, OFPFMFC_UNSUPPORTED
+    }
+
+    public enum OFPortModFailedCode {
+        OFPPMFC_BAD_PORT, OFPPMFC_BAD_HW_ADDR
+    }
+
+    public enum OFQueueOpFailedCode {
+        OFPQOFC_BAD_PORT, OFPQOFC_BAD_QUEUE, OFPQOFC_EPERM
+    }
+
+    protected short errorType;
+    protected short errorCode;
+    protected int vendor;
+    protected int vendorErrorType;
+    protected short vendorErrorCode;
+    protected OFMessageFactory factory;
+    protected byte[] error;
+    protected boolean errorIsAscii;
+
+    public OFError() {
+        super();
+        this.type = OFType.ERROR;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /** convenience constructor */
+    public OFError(OFErrorType errorType) {
+        this();
+        setErrorType(errorType);
+    }
+
+    /**
+     * @return the errorType
+     */
+    public short getErrorType() {
+        return errorType;
+    }
+
+    /**
+     * @param errorType
+     *            the errorType to set
+     */
+    public void setErrorType(short errorType) {
+        this.errorType = errorType;
+    }
+
+    public void setErrorType(OFErrorType type) {
+        this.errorType = type.getValue();
+    }
+
+    /**
+     * @return true if the error is an extended vendor error
+     */
+    public boolean isVendorError() {
+        return errorType == OFErrorType.OFPET_VENDOR_ERROR.getValue();
+    }
+
+    /**
+     * @return the errorCode
+     */
+    public short getErrorCode() {
+        return errorCode;
+    }
+
+    /**
+     * @param errorCode
+     *            the errorCode to set
+     */
+    public void setErrorCode(OFHelloFailedCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(short errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    public void setErrorCode(OFBadRequestCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(OFBadActionCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(OFFlowModFailedCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(OFPortModFailedCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public void setErrorCode(OFQueueOpFailedCode code) {
+        this.errorCode = (short) code.ordinal();
+    }
+
+    public int getVendorErrorType() {
+        return vendorErrorType;
+    }
+
+    public void setVendorErrorType(int vendorErrorType) {
+        this.vendorErrorType = vendorErrorType;
+    }
+
+    public short getVendorErrorCode() {
+        return vendorErrorCode;
+    }
+
+    public void setVendorErrorCode(short vendorErrorCode) {
+        this.vendorErrorCode = vendorErrorCode;
+    }
+
+    public OFMessage getOffendingMsg() throws MessageParseException {
+        // should only have one message embedded; if more than one, just
+        // grab first
+        if (this.error == null)
+            return null;
+        ChannelBuffer errorMsg = ChannelBuffers.wrappedBuffer(this.error);
+        if (factory == null)
+            throw new RuntimeException("MessageFactory not set");
+
+        List<OFMessage> msglist = this.factory.parseMessage(errorMsg);
+        if (msglist == null)
+                return null;
+        return msglist.get(0);
+    }
+
+    /**
+     * Write this offending message into the payload of the Error message
+     *
+     * @param offendingMsg
+     */
+
+    public void setOffendingMsg(OFMessage offendingMsg) {
+        if (offendingMsg == null) {
+            super.setLengthU(MINIMUM_LENGTH);
+        } else {
+            this.error = new byte[offendingMsg.getLengthU()];
+            ChannelBuffer data = ChannelBuffers.wrappedBuffer(this.error);
+            data.writerIndex(0);
+            offendingMsg.writeTo(data);
+            super.setLengthU(MINIMUM_LENGTH + offendingMsg.getLengthU());
+        }
+    }
+
+    public OFMessageFactory getFactory() {
+        return factory;
+    }
+
+    @Override
+    public void setMessageFactory(OFMessageFactory factory) {
+        this.factory = factory;
+    }
+
+    /**
+     * @return the error
+     */
+    public byte[] getError() {
+        return error;
+    }
+
+    /**
+     * @param error
+     *            the error to set
+     */
+    public void setError(byte[] error) {
+        this.error = error;
+    }
+
+    /**
+     * @return the errorIsAscii
+     */
+    public boolean isErrorIsAscii() {
+        return errorIsAscii;
+    }
+
+    /**
+     * @param errorIsAscii
+     *            the errorIsAscii to set
+     */
+    public void setErrorIsAscii(boolean errorIsAscii) {
+        this.errorIsAscii = errorIsAscii;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.errorType = data.readShort();
+        this.errorCode = data.readShort();
+        int dataLength = this.getLengthU() - MINIMUM_LENGTH;
+        if (dataLength > 0) {
+            this.error = new byte[dataLength];
+            data.readBytes(this.error);
+            if (this.errorType == OFErrorType.OFPET_HELLO_FAILED.getValue())
+                this.errorIsAscii = true;
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(errorType);
+        data.writeShort(errorCode);
+        if (error != null)
+            data.writeBytes(error);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(error);
+        result = prime * result + errorCode;
+        result = prime * result + (errorIsAscii ? 1231 : 1237);
+        result = prime * result + errorType;
+        return result;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        OFError other = (OFError) obj;
+        if (!Arrays.equals(error, other.error))
+            return false;
+        if (errorCode != other.errorCode)
+            return false;
+        if (errorIsAscii != other.errorIsAscii)
+            return false;
+        if (errorType != other.errorType)
+            return false;
+        return true;
+    }
+
+}
diff --git a/src/main/java/org/openflow/protocol/OFFeaturesReply.java b/src/main/java/org/openflow/protocol/OFFeaturesReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c2cc51cf21dca6c83978dc1d995deb5ba0d4421
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFFeaturesReply.java
@@ -0,0 +1,261 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.serializers.OFFeaturesReplyJSONSerializer;
+import org.openflow.protocol.serializers.StringDpidToLongJSONDeserializer;
+import org.openflow.util.U16;
+
+
+/**
+ * Represents a features reply message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+@JsonSerialize(using=OFFeaturesReplyJSONSerializer.class)
+public class OFFeaturesReply extends OFMessage {
+    public static int MINIMUM_LENGTH = 32;
+
+    /**
+     * Corresponds to bits on the capabilities field
+     */
+    public enum OFCapabilities {
+        OFPC_FLOW_STATS     (1 << 0),
+        OFPC_TABLE_STATS    (1 << 1),
+        OFPC_PORT_STATS     (1 << 2),
+        OFPC_STP            (1 << 3),
+        OFPC_RESERVED       (1 << 4),
+        OFPC_IP_REASM       (1 << 5),
+        OFPC_QUEUE_STATS    (1 << 6),
+        OFPC_ARP_MATCH_IP   (1 << 7);
+
+        protected int value;
+
+        private OFCapabilities(int value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value
+         */
+        public int getValue() {
+            return value;
+        }
+    }
+
+    protected long datapathId;
+    protected int buffers;
+    protected byte tables;
+    protected int capabilities;
+    protected int actions;
+    protected List<OFPhysicalPort> ports;
+
+    public OFFeaturesReply() {
+        super();
+        this.type = OFType.FEATURES_REPLY;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the datapathId
+     */
+    public long getDatapathId() {
+        return datapathId;
+    }
+
+    /**
+     * @param datapathId the datapathId to set
+     */
+    @JsonDeserialize(using=StringDpidToLongJSONDeserializer.class)
+    public void setDatapathId(long datapathId) {
+        this.datapathId = datapathId;
+    }
+
+    /**
+     * @return the buffers
+     */
+    public int getBuffers() {
+        return buffers;
+    }
+
+    /**
+     * @param buffers the buffers to set
+     */
+    public void setBuffers(int buffers) {
+        this.buffers = buffers;
+    }
+
+    /**
+     * @return the tables
+     */
+    public byte getTables() {
+        return tables;
+    }
+
+    /**
+     * @param tables the tables to set
+     */
+    public void setTables(byte tables) {
+        this.tables = tables;
+    }
+
+    /**
+     * @return the capabilities
+     */
+    public int getCapabilities() {
+        return capabilities;
+    }
+
+    /**
+     * @param capabilities the capabilities to set
+     */
+    public void setCapabilities(int capabilities) {
+        this.capabilities = capabilities;
+    }
+
+    /**
+     * @return the actions
+     */
+    public int getActions() {
+        return actions;
+    }
+
+    /**
+     * @param actions the actions to set
+     */
+    public void setActions(int actions) {
+        this.actions = actions;
+    }
+
+    /**
+     * @return the ports
+     */
+    public List<OFPhysicalPort> getPorts() {
+        return ports;
+    }
+
+    /**
+     * @param ports the ports to set
+     */
+    public void setPorts(List<OFPhysicalPort> ports) {
+        this.ports = ports;
+        if (ports == null) {
+            this.setLengthU(MINIMUM_LENGTH);
+        } else {
+            this.setLengthU(MINIMUM_LENGTH + ports.size()
+                    * OFPhysicalPort.MINIMUM_LENGTH);
+        }
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.datapathId = data.readLong();
+        this.buffers = data.readInt();
+        this.tables = data.readByte();
+        data.readerIndex(data.readerIndex() + 3); // pad
+        this.capabilities = data.readInt();
+        this.actions = data.readInt();
+        if (this.ports == null) {
+            this.ports = new ArrayList<OFPhysicalPort>();
+        } else {
+            this.ports.clear();
+        }
+        int portCount = (super.getLengthU() - 32)
+                / OFPhysicalPort.MINIMUM_LENGTH;
+        OFPhysicalPort port;
+        for (int i = 0; i < portCount; ++i) {
+            port = new OFPhysicalPort();
+            port.readFrom(data);
+            this.ports.add(port);
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeLong(this.datapathId);
+        data.writeInt(this.buffers);
+        data.writeByte(this.tables);
+        data.writeShort((short) 0); // pad
+        data.writeByte((byte) 0); // pad
+        data.writeInt(this.capabilities);
+        data.writeInt(this.actions);
+        if (this.ports != null)
+            for (OFPhysicalPort port : this.ports) {
+                port.writeTo(data);
+            }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 139;
+        int result = super.hashCode();
+        result = prime * result + actions;
+        result = prime * result + buffers;
+        result = prime * result + capabilities;
+        result = prime * result + (int) (datapathId ^ (datapathId >>> 32));
+        result = prime * result + ((ports == null) ? 0 : ports.hashCode());
+        result = prime * result + tables;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFFeaturesReply)) {
+            return false;
+        }
+        OFFeaturesReply other = (OFFeaturesReply) obj;
+        if (actions != other.actions) {
+            return false;
+        }
+        if (buffers != other.buffers) {
+            return false;
+        }
+        if (capabilities != other.capabilities) {
+            return false;
+        }
+        if (datapathId != other.datapathId) {
+            return false;
+        }
+        if (ports == null) {
+            if (other.ports != null) {
+                return false;
+            }
+        } else if (!ports.equals(other.ports)) {
+            return false;
+        }
+        if (tables != other.tables) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFFeaturesRequest.java b/src/main/java/org/openflow/protocol/OFFeaturesRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a89e4f57f1559afcbc751cb80d9f9fb10700a93
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFFeaturesRequest.java
@@ -0,0 +1,36 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.openflow.util.U16;
+
+
+/**
+ * Represents a features request message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public class OFFeaturesRequest extends OFMessage {
+    public static int MINIMUM_LENGTH = 8;
+
+    public OFFeaturesRequest() {
+        super();
+        this.type = OFType.FEATURES_REQUEST;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFFlowMod.java b/src/main/java/org/openflow/protocol/OFFlowMod.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d2aad2157d4bfcbf19572bb943d5fb026c6cbb7
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFFlowMod.java
@@ -0,0 +1,389 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.factory.OFActionFactory;
+import org.openflow.protocol.factory.OFActionFactoryAware;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_flow_mod message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public class OFFlowMod extends OFMessage implements OFActionFactoryAware, Cloneable {
+    public static int MINIMUM_LENGTH = 72;
+
+    public static final short OFPFC_ADD = 0;                /* New flow. */
+    public static final short OFPFC_MODIFY = 1;             /* Modify all matching flows. */
+    public static final short OFPFC_MODIFY_STRICT = 2;      /* Modify entry strictly matching wildcards */
+    public static final short OFPFC_DELETE=3;               /* Delete all matching flows. */
+    public static final short OFPFC_DELETE_STRICT =4;       /* Strictly match wildcards and priority. */
+
+    // Open Flow Flow Mod Flags. Use "or" operation to set multiple flags
+    public static final short OFPFF_SEND_FLOW_REM = 0x1; // 1 << 0
+    public static final short OFPFF_CHECK_OVERLAP = 0x2; // 1 << 1
+    public static final short OFPFF_EMERG         = 0x4; // 1 << 2
+
+    protected OFActionFactory actionFactory;
+    protected OFMatch match;
+    protected long cookie;
+    protected short command;
+    protected short idleTimeout;
+    protected short hardTimeout;
+    protected short priority;
+    protected int bufferId;
+    protected short outPort;
+    protected short flags;
+    protected List<OFAction> actions;
+
+    public OFFlowMod() {
+        super();
+        this.outPort = OFPort.OFPP_NONE.getValue();
+        this.type = OFType.FLOW_MOD;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * Get buffer_id
+     * @return
+     */
+    public int getBufferId() {
+        return this.bufferId;
+    }
+
+    /**
+     * Set buffer_id
+     * @param bufferId
+     */
+    public OFFlowMod setBufferId(int bufferId) {
+        this.bufferId = bufferId;
+        return this;
+    }
+
+    /**
+     * Get cookie
+     * @return
+     */
+    public long getCookie() {
+        return this.cookie;
+    }
+
+    /**
+     * Set cookie
+     * @param cookie
+     */
+    public OFFlowMod setCookie(long cookie) {
+        this.cookie = cookie;
+        return this;
+    }
+
+    /**
+     * Get command
+     * @return
+     */
+    public short getCommand() {
+        return this.command;
+    }
+
+    /**
+     * Set command
+     * @param command
+     */
+    public OFFlowMod setCommand(short command) {
+        this.command = command;
+        return this;
+    }
+
+    /**
+     * Get flags
+     * @return
+     */
+    public short getFlags() {
+        return this.flags;
+    }
+
+    /**
+     * Set flags
+     * @param flags
+     */
+    public OFFlowMod setFlags(short flags) {
+        this.flags = flags;
+        return this;
+    }
+
+    /**
+     * Get hard_timeout
+     * @return
+     */
+    public short getHardTimeout() {
+        return this.hardTimeout;
+    }
+
+    /**
+     * Set hard_timeout
+     * @param hardTimeout
+     */
+    public OFFlowMod setHardTimeout(short hardTimeout) {
+        this.hardTimeout = hardTimeout;
+        return this;
+    }
+
+    /**
+     * Get idle_timeout
+     * @return
+     */
+    public short getIdleTimeout() {
+        return this.idleTimeout;
+    }
+
+    /**
+     * Set idle_timeout
+     * @param idleTimeout
+     */
+    public OFFlowMod setIdleTimeout(short idleTimeout) {
+        this.idleTimeout = idleTimeout;
+        return this;
+    }
+
+    /**
+     * Gets a copy of the OFMatch object for this FlowMod, changes to this
+     * object do not modify the FlowMod
+     * @return
+     */
+    public OFMatch getMatch() {
+        return this.match;
+    }
+
+    /**
+     * Set match
+     * @param match
+     */
+    public OFFlowMod setMatch(OFMatch match) {
+        this.match = match;
+        return this;
+    }
+
+    /**
+     * Get out_port
+     * @return
+     */
+    public short getOutPort() {
+        return this.outPort;
+    }
+
+    /**
+     * Set out_port
+     * @param outPort
+     */
+    public OFFlowMod setOutPort(short outPort) {
+        this.outPort = outPort;
+        return this;
+    }
+
+    /**
+     * Set out_port
+     * @param port
+     */
+    public OFFlowMod setOutPort(OFPort port) {
+        this.outPort = port.getValue();
+        return this;
+    }
+
+    /**
+     * Get priority
+     * @return
+     */
+    public short getPriority() {
+        return this.priority;
+    }
+
+    /**
+     * Set priority
+     * @param priority
+     */
+    public OFFlowMod setPriority(short priority) {
+        this.priority = priority;
+        return this;
+    }
+
+    /**
+     * Returns read-only copies of the actions contained in this Flow Mod
+     * @return a list of ordered OFAction objects
+     */
+    public List<OFAction> getActions() {
+        return this.actions;
+    }
+
+    /**
+     * Sets the list of actions this Flow Mod contains
+     * @param actions a list of ordered OFAction objects
+     */
+    public OFFlowMod setActions(List<OFAction> actions) {
+        this.actions = actions;
+        return this;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.cookie = data.readLong();
+        this.command = data.readShort();
+        this.idleTimeout = data.readShort();
+        this.hardTimeout = data.readShort();
+        this.priority = data.readShort();
+        this.bufferId = data.readInt();
+        this.outPort = data.readShort();
+        this.flags = data.readShort();
+        if (this.actionFactory == null)
+            throw new RuntimeException("OFActionFactory not set");
+        this.actions = this.actionFactory.parseActions(data, getLengthU() -
+                MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        this.match.writeTo(data);
+        data.writeLong(cookie);
+        data.writeShort(command);
+        data.writeShort(idleTimeout);
+        data.writeShort(hardTimeout);
+        data.writeShort(priority);
+        data.writeInt(bufferId);
+        data.writeShort(outPort);
+        data.writeShort(flags);
+        if (actions != null) {
+            for (OFAction action : actions) {
+                action.writeTo(data);
+            }
+        }
+    }
+
+    @Override
+    public void setActionFactory(OFActionFactory actionFactory) {
+        this.actionFactory = actionFactory;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 227;
+        int result = super.hashCode();
+        result = prime * result + ((actions == null) ? 0 : actions.hashCode());
+        result = prime * result + bufferId;
+        result = prime * result + command;
+        result = prime * result + (int) (cookie ^ (cookie >>> 32));
+        result = prime * result + flags;
+        result = prime * result + hardTimeout;
+        result = prime * result + idleTimeout;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + outPort;
+        result = prime * result + priority;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFFlowMod)) {
+            return false;
+        }
+        OFFlowMod other = (OFFlowMod) obj;
+        if (actions == null) {
+            if (other.actions != null) {
+                return false;
+            }
+        } else if (!actions.equals(other.actions)) {
+            return false;
+        }
+        if (bufferId != other.bufferId) {
+            return false;
+        }
+        if (command != other.command) {
+            return false;
+        }
+        if (cookie != other.cookie) {
+            return false;
+        }
+        if (flags != other.flags) {
+            return false;
+        }
+        if (hardTimeout != other.hardTimeout) {
+            return false;
+        }
+        if (idleTimeout != other.idleTimeout) {
+            return false;
+        }
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (outPort != other.outPort) {
+            return false;
+        }
+        if (priority != other.priority) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#clone()
+     */
+    @Override
+    public OFFlowMod clone() throws CloneNotSupportedException {
+        OFMatch neoMatch = match.clone();
+        OFFlowMod flowMod= (OFFlowMod) super.clone();
+        flowMod.setMatch(neoMatch);
+        List<OFAction> neoActions = new LinkedList<OFAction>();
+        for(OFAction action: this.actions)
+            neoActions.add(action.clone());
+        flowMod.setActions(neoActions);
+        return flowMod;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "OFFlowMod [actionFactory=" + actionFactory + ", actions="
+                + actions + ", bufferId=" + bufferId + ", command=" + command
+                + ", cookie=" + Long.toHexString(cookie) + ", flags=" + flags + ", hardTimeout="
+                + hardTimeout + ", idleTimeout=" + idleTimeout + ", match="
+                + match + ", outPort=" + outPort + ", priority=" + priority
+                + ", length=" + length + ", type=" + type + ", version="
+                + version + ", xid=" + xid + "]";
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFFlowRemoved.java b/src/main/java/org/openflow/protocol/OFFlowRemoved.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfe2e14ce34691a6b6b096c181cfd67fa5c214aa
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFFlowRemoved.java
@@ -0,0 +1,294 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_flow_removed message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public class OFFlowRemoved extends OFMessage {
+    public static int MINIMUM_LENGTH = 88;
+
+    public enum OFFlowRemovedReason {
+        OFPRR_IDLE_TIMEOUT,
+        OFPRR_HARD_TIMEOUT,
+        OFPRR_DELETE
+    }
+
+    protected OFMatch match;
+    protected long cookie;
+    protected short priority;
+    protected OFFlowRemovedReason reason;
+    protected int durationSeconds;
+    protected int durationNanoseconds;
+    protected short idleTimeout;
+    protected long packetCount;
+    protected long byteCount;
+    
+    public OFFlowRemoved() {
+        super();
+        this.type = OFType.FLOW_REMOVED;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * Get cookie
+     * @return
+     */
+    public long getCookie() {
+        return this.cookie;
+    }
+
+    /**
+     * Set cookie
+     * @param cookie
+     */
+    public void setCookie(long cookie) {
+        this.cookie = cookie;
+    }
+
+    /**
+     * Get idle_timeout
+     * @return
+     */
+    public short getIdleTimeout() {
+        return this.idleTimeout;
+    }
+
+    /**
+     * Set idle_timeout
+     * @param idleTimeout
+     */
+    public void setIdleTimeout(short idleTimeout) {
+        this.idleTimeout = idleTimeout;
+    }
+
+    /**
+     * Gets a copy of the OFMatch object for this FlowMod, changes to this
+     * object do not modify the FlowMod
+     * @return
+     */
+    public OFMatch getMatch() {
+        return this.match;
+    }
+
+    /**
+     * Set match
+     * @param match
+     */
+    public void setMatch(OFMatch match) {
+        this.match = match;
+    }
+
+    /**
+     * Get priority
+     * @return
+     */
+    public short getPriority() {
+        return this.priority;
+    }
+
+    /**
+     * Set priority
+     * @param priority
+     */
+    public void setPriority(short priority) {
+        this.priority = priority;
+    }
+
+    /**
+     * @return the reason
+     */
+    public OFFlowRemovedReason getReason() {
+        return reason;
+    }
+
+    /**
+     * @param reason the reason to set
+     */
+    public void setReason(OFFlowRemovedReason reason) {
+        this.reason = reason;
+    }
+
+    /**
+     * @return the durationSeconds
+     */
+    public int getDurationSeconds() {
+        return durationSeconds;
+    }
+
+    /**
+     * @param durationSeconds the durationSeconds to set
+     */
+    public void setDurationSeconds(int durationSeconds) {
+        this.durationSeconds = durationSeconds;
+    }
+
+    /**
+     * @return the durationNanoseconds
+     */
+    public int getDurationNanoseconds() {
+        return durationNanoseconds;
+    }
+
+    /**
+     * @param durationNanoseconds the durationNanoseconds to set
+     */
+    public void setDurationNanoseconds(int durationNanoseconds) {
+        this.durationNanoseconds = durationNanoseconds;
+    }
+
+    /**
+     * @return the packetCount
+     */
+    public long getPacketCount() {
+        return packetCount;
+    }
+
+    /**
+     * @param packetCount the packetCount to set
+     */
+    public void setPacketCount(long packetCount) {
+        this.packetCount = packetCount;
+    }
+
+    /**
+     * @return the byteCount
+     */
+    public long getByteCount() {
+        return byteCount;
+    }
+
+    /**
+     * @param byteCount the byteCount to set
+     */
+    public void setByteCount(long byteCount) {
+        this.byteCount = byteCount;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.cookie = data.readLong();
+        this.priority = data.readShort();
+        int reasonIndex = 0xff & data.readByte();
+        if (reasonIndex >= OFFlowRemovedReason.values().length) {
+            reasonIndex = OFFlowRemovedReason.values().length - 1;
+        }
+        this.reason = OFFlowRemovedReason.values()[reasonIndex];
+        data.readByte(); // pad
+        this.durationSeconds = data.readInt();
+        this.durationNanoseconds = data.readInt();
+        this.idleTimeout = data.readShort();
+        data.readByte(); // pad
+        data.readByte(); // pad
+        this.packetCount = data.readLong();
+        this.byteCount = data.readLong();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        this.match.writeTo(data);
+        data.writeLong(cookie);
+        data.writeShort(priority);
+        data.writeByte((byte) this.reason.ordinal());
+        data.writeByte((byte) 0);
+        data.writeInt(this.durationSeconds);
+        data.writeInt(this.durationNanoseconds);
+        data.writeShort(idleTimeout);
+        data.writeByte((byte) 0); // pad
+        data.writeByte((byte) 0); // pad
+        data.writeLong(this.packetCount);
+        data.writeLong(this.byteCount);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 271;
+        int result = super.hashCode();
+        result = prime * result + (int) (byteCount ^ (byteCount >>> 32));
+        result = prime * result + (int) (cookie ^ (cookie >>> 32));
+        result = prime * result + durationNanoseconds;
+        result = prime * result + durationSeconds;
+        result = prime * result + idleTimeout;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + (int) (packetCount ^ (packetCount >>> 32));
+        result = prime * result + priority;
+        result = prime * result + ((reason == null) ? 0 : reason.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFFlowRemoved)) {
+            return false;
+        }
+        OFFlowRemoved other = (OFFlowRemoved) obj;
+        if (byteCount != other.byteCount) {
+            return false;
+        }
+        if (cookie != other.cookie) {
+            return false;
+        }
+        if (durationNanoseconds != other.durationNanoseconds) {
+            return false;
+        }
+        if (durationSeconds != other.durationSeconds) {
+            return false;
+        }
+        if (idleTimeout != other.idleTimeout) {
+            return false;
+        }
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (packetCount != other.packetCount) {
+            return false;
+        }
+        if (priority != other.priority) {
+            return false;
+        }
+        if (reason == null) {
+            if (other.reason != null) {
+                return false;
+            }
+        } else if (!reason.equals(other.reason)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFGetConfigReply.java b/src/main/java/org/openflow/protocol/OFGetConfigReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..257867afa521eb4b1c753c1e98c03e5433e8cdab
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFGetConfigReply.java
@@ -0,0 +1,29 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+/**
+ * Represents an OFPT_GET_CONFIG_REPLY type message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFGetConfigReply extends OFSwitchConfig {
+    public OFGetConfigReply() {
+        super();
+        this.type = OFType.GET_CONFIG_REPLY;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFGetConfigRequest.java b/src/main/java/org/openflow/protocol/OFGetConfigRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..85c7499243fc73d4c31aa4b0035e9a3353662f89
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFGetConfigRequest.java
@@ -0,0 +1,32 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an OFPT_GET_CONFIG_REQUEST type message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFGetConfigRequest extends OFMessage {
+    public OFGetConfigRequest() {
+        super();
+        this.type = OFType.GET_CONFIG_REQUEST;
+        this.length = U16.t(OFMessage.MINIMUM_LENGTH);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFHello.java b/src/main/java/org/openflow/protocol/OFHello.java
new file mode 100644
index 0000000000000000000000000000000000000000..e702ca4d98d986da7b3176bda07abaefe07e2145
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFHello.java
@@ -0,0 +1,39 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.openflow.util.U16;
+
+
+/**
+ * Represents an ofp_hello message
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Feb 8, 2010
+ */
+public class OFHello extends OFMessage {
+    public static int MINIMUM_LENGTH = 8;
+
+    /**
+     * Construct a ofp_hello message
+     */
+    public OFHello() {
+        super();
+        this.type = OFType.HELLO;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFMatch.java b/src/main/java/org/openflow/protocol/OFMatch.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c3c9f495bb300567d2fac10ad76e8d3fe097df6
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFMatch.java
@@ -0,0 +1,1145 @@
+/**
+ *    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+ *    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 org.openflow.protocol;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import net.floodlightcontroller.packet.Ethernet;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.serializers.OFMatchJSONSerializer;
+import org.openflow.util.HexString;
+import org.openflow.util.U16;
+import org.openflow.util.U8;
+
+/**
+ * Represents an ofp_match structure
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+@JsonSerialize(using = OFMatchJSONSerializer.class)
+public class OFMatch implements Cloneable, Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+    public static int MINIMUM_LENGTH = 40;
+    final public static int OFPFW_ALL = ((1 << 22) - 1);
+
+    final public static int OFPFW_IN_PORT = 1 << 0; /* Switch input port. */
+    final public static int OFPFW_DL_VLAN = 1 << 1; /* VLAN id. */
+    final public static int OFPFW_DL_SRC = 1 << 2; /* Ethernet source address. */
+    final public static int OFPFW_DL_DST = 1 << 3; /*
+                                                    * Ethernet destination
+                                                    * address.
+                                                    */
+    final public static int OFPFW_DL_TYPE = 1 << 4; /* Ethernet frame type. */
+    final public static int OFPFW_NW_PROTO = 1 << 5; /* IP protocol. */
+    final public static int OFPFW_TP_SRC = 1 << 6; /* TCP/UDP source port. */
+    final public static int OFPFW_TP_DST = 1 << 7; /* TCP/UDP destination port. */
+
+    /*
+     * IP source address wildcard bit count. 0 is exact match, 1 ignores the
+     * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
+     * the entire field. This is the *opposite* of the usual convention where
+     * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded.
+     */
+    final public static int OFPFW_NW_SRC_SHIFT = 8;
+    final public static int OFPFW_NW_SRC_BITS = 6;
+    final public static int OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT;
+    final public static int OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT;
+
+    /* IP destination address wildcard bit count. Same format as source. */
+    final public static int OFPFW_NW_DST_SHIFT = 14;
+    final public static int OFPFW_NW_DST_BITS = 6;
+    final public static int OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT;
+    final public static int OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT;
+
+    final public static int OFPFW_DL_VLAN_PCP = 1 << 20; /* VLAN priority. */
+    final public static int OFPFW_NW_TOS = 1 << 21; /*
+                                                     * IP ToS (DSCP field, 6
+                                                     * bits).
+                                                     */
+
+    final public static int OFPFW_ALL_SANITIZED = (((1 << 22) - 1)
+                                                   & ~OFPFW_NW_SRC_MASK & ~OFPFW_NW_DST_MASK)
+                                                  | OFPFW_NW_SRC_ALL
+                                                  | OFPFW_NW_DST_ALL;
+
+    /* List of Strings for marshalling and unmarshalling to human readable forms */
+    final public static String STR_IN_PORT = "in_port";
+    final public static String STR_DL_DST = "dl_dst";
+    final public static String STR_DL_SRC = "dl_src";
+    final public static String STR_DL_TYPE = "dl_type";
+    final public static String STR_DL_VLAN = "dl_vlan";
+    final public static String STR_DL_VLAN_PCP = "dl_vlan_pcp";
+    final public static String STR_NW_DST = "nw_dst";
+    final public static String STR_NW_SRC = "nw_src";
+    final public static String STR_NW_PROTO = "nw_proto";
+    final public static String STR_NW_TOS = "nw_tos";
+    final public static String STR_TP_DST = "tp_dst";
+    final public static String STR_TP_SRC = "tp_src";
+
+    protected int wildcards;
+    protected short inputPort;
+    protected byte[] dataLayerSource;
+    protected byte[] dataLayerDestination;
+    protected short dataLayerVirtualLan;
+    protected byte dataLayerVirtualLanPriorityCodePoint;
+    protected short dataLayerType;
+    protected byte networkTypeOfService;
+    protected byte networkProtocol;
+    protected int networkSource;
+    protected int networkDestination;
+    protected short transportSource;
+    protected short transportDestination;
+
+    /**
+     * By default, create a OFMatch that matches everything (mostly because it's
+     * the least amount of work to make a valid OFMatch)
+     */
+    public OFMatch() {
+        this.wildcards = OFPFW_ALL;
+        this.dataLayerDestination = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0,
+                                                0x0 };
+        this.dataLayerSource = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
+        this.dataLayerVirtualLan = Ethernet.VLAN_UNTAGGED;
+        this.dataLayerVirtualLanPriorityCodePoint = 0;
+        this.dataLayerType = 0;
+        this.inputPort = 0;
+        this.networkProtocol = 0;
+        this.networkTypeOfService = 0;
+        this.networkSource = 0;
+        this.networkDestination = 0;
+        this.transportDestination = 0;
+        this.transportSource = 0;
+    }
+
+    /**
+     * Get dl_dst
+     *
+     * @return an arrays of bytes
+     */
+    public byte[] getDataLayerDestination() {
+        return this.dataLayerDestination;
+    }
+
+    /**
+     * Set dl_dst
+     *
+     * @param dataLayerDestination
+     */
+    public OFMatch setDataLayerDestination(byte[] dataLayerDestination) {
+        this.dataLayerDestination = dataLayerDestination;
+        return this;
+    }
+
+    /**
+     * Set dl_dst, but first translate to byte[] using HexString
+     *
+     * @param mac
+     *            A colon separated string of 6 pairs of octets, e..g.,
+     *            "00:17:42:EF:CD:8D"
+     */
+    public OFMatch setDataLayerDestination(String mac) {
+        byte bytes[] = HexString.fromHexString(mac);
+        if (bytes.length != 6)
+                              throw new IllegalArgumentException(
+                                                                 "expected string with 6 octets, got '"
+                                                                         + mac
+                                                                         + "'");
+        this.dataLayerDestination = bytes;
+        return this;
+    }
+
+    /**
+     * Get dl_src
+     *
+     * @return an array of bytes
+     */
+    public byte[] getDataLayerSource() {
+        return this.dataLayerSource;
+    }
+
+    /**
+     * Set dl_src
+     *
+     * @param dataLayerSource
+     */
+    public OFMatch setDataLayerSource(byte[] dataLayerSource) {
+        this.dataLayerSource = dataLayerSource;
+        return this;
+    }
+
+    /**
+     * Set dl_src, but first translate to byte[] using HexString
+     *
+     * @param mac
+     *            A colon separated string of 6 pairs of octets, e..g.,
+     *            "00:17:42:EF:CD:8D"
+     */
+    public OFMatch setDataLayerSource(String mac) {
+        byte bytes[] = HexString.fromHexString(mac);
+        if (bytes.length != 6)
+                              throw new IllegalArgumentException(
+                                                                 "expected string with 6 octets, got '"
+                                                                         + mac
+                                                                         + "'");
+        this.dataLayerSource = bytes;
+        return this;
+    }
+
+    /**
+     * Get dl_type
+     *
+     * @return ether_type
+     */
+    public short getDataLayerType() {
+        return this.dataLayerType;
+    }
+
+    /**
+     * Set dl_type
+     *
+     * @param dataLayerType
+     */
+    public OFMatch setDataLayerType(short dataLayerType) {
+        this.dataLayerType = dataLayerType;
+        return this;
+    }
+
+    /**
+     * Get dl_vlan
+     *
+     * @return vlan tag; VLAN_NONE == no tag
+     */
+    public short getDataLayerVirtualLan() {
+        return this.dataLayerVirtualLan;
+    }
+
+    /**
+     * Set dl_vlan
+     *
+     * @param dataLayerVirtualLan
+     */
+    public OFMatch setDataLayerVirtualLan(short dataLayerVirtualLan) {
+        this.dataLayerVirtualLan = dataLayerVirtualLan;
+        return this;
+    }
+
+    /**
+     * Get dl_vlan_pcp
+     *
+     * @return
+     */
+    public byte getDataLayerVirtualLanPriorityCodePoint() {
+        return this.dataLayerVirtualLanPriorityCodePoint;
+    }
+
+    /**
+     * Set dl_vlan_pcp
+     *
+     * @param pcp
+     */
+    public OFMatch setDataLayerVirtualLanPriorityCodePoint(byte pcp) {
+        this.dataLayerVirtualLanPriorityCodePoint = pcp;
+        return this;
+    }
+
+    /**
+     * Get in_port
+     *
+     * @return
+     */
+    public short getInputPort() {
+        return this.inputPort;
+    }
+
+    /**
+     * Set in_port
+     *
+     * @param inputPort
+     */
+    public OFMatch setInputPort(short inputPort) {
+        this.inputPort = inputPort;
+        return this;
+    }
+
+    /**
+     * Get nw_dst
+     *
+     * @return
+     */
+    public int getNetworkDestination() {
+        return this.networkDestination;
+    }
+
+    /**
+     * Set nw_dst
+     *
+     * @param networkDestination
+     */
+    public OFMatch setNetworkDestination(int networkDestination) {
+        this.networkDestination = networkDestination;
+        return this;
+    }
+
+    /**
+     * Parse this match's wildcard fields and return the number of significant
+     * bits in the IP destination field. NOTE: this returns the number of bits
+     * that are fixed, i.e., like CIDR, not the number of bits that are free
+     * like OpenFlow encodes.
+     *
+     * @return a number between 0 (matches all IPs) and 63 ( 32>= implies exact
+     *         match)
+     */
+    public int getNetworkDestinationMaskLen() {
+        return Math.max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT),
+                        0);
+    }
+
+    /**
+     * Parse this match's wildcard fields and return the number of significant
+     * bits in the IP destination field. NOTE: this returns the number of bits
+     * that are fixed, i.e., like CIDR, not the number of bits that are free
+     * like OpenFlow encodes.
+     *
+     * @return a number between 0 (matches all IPs) and 32 (exact match)
+     */
+    public int getNetworkSourceMaskLen() {
+        return Math.max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT),
+                        0);
+    }
+
+    /**
+     * Get nw_proto
+     *
+     * @return
+     */
+    public byte getNetworkProtocol() {
+        return this.networkProtocol;
+    }
+
+    /**
+     * Set nw_proto
+     *
+     * @param networkProtocol
+     */
+    public OFMatch setNetworkProtocol(byte networkProtocol) {
+        this.networkProtocol = networkProtocol;
+        return this;
+    }
+
+    /**
+     * Get nw_src
+     *
+     * @return
+     */
+    public int getNetworkSource() {
+        return this.networkSource;
+    }
+
+    /**
+     * Set nw_src
+     *
+     * @param networkSource
+     */
+    public OFMatch setNetworkSource(int networkSource) {
+        this.networkSource = networkSource;
+        return this;
+    }
+
+    /**
+     * Get nw_tos OFMatch stores the ToS bits as top 6-bits, so right shift by 2
+     * bits before returning the value
+     *
+     * @return : 6-bit DSCP value (0-63)
+     */
+    public byte getNetworkTypeOfService() {
+        return (byte) ((this.networkTypeOfService >> 2) & 0x3f);
+    }
+
+    /**
+     * Set nw_tos OFMatch stores the ToS bits as top 6-bits, so left shift by 2
+     * bits before storing the value
+     *
+     * @param networkTypeOfService
+     *            : 6-bit DSCP value (0-63)
+     */
+    public OFMatch setNetworkTypeOfService(byte networkTypeOfService) {
+        this.networkTypeOfService = (byte) (networkTypeOfService << 2);
+        return this;
+    }
+
+    /**
+     * Get tp_dst
+     *
+     * @return
+     */
+    public short getTransportDestination() {
+        return this.transportDestination;
+    }
+
+    /**
+     * Set tp_dst
+     *
+     * @param transportDestination
+     */
+    public OFMatch setTransportDestination(short transportDestination) {
+        this.transportDestination = transportDestination;
+        return this;
+    }
+
+    /**
+     * Get tp_src
+     *
+     * @return
+     */
+    public short getTransportSource() {
+        return this.transportSource;
+    }
+
+    /**
+     * Set tp_src
+     *
+     * @param transportSource
+     */
+    public OFMatch setTransportSource(short transportSource) {
+        this.transportSource = transportSource;
+        return this;
+    }
+
+    /**
+     * Get wildcards
+     *
+     * @return
+     */
+    public int getWildcards() {
+        return this.wildcards;
+    }
+
+    /**
+     * Get wildcards
+     *
+     * @return
+     */
+    public Wildcards getWildcardObj() {
+        return Wildcards.of(wildcards);
+    }
+
+    /**
+     * Set wildcards
+     *
+     * @param wildcards
+     */
+    public OFMatch setWildcards(int wildcards) {
+        this.wildcards = wildcards;
+        return this;
+    }
+
+    /** set the wildcard using the Wildcards convenience object */
+    public OFMatch setWildcards(Wildcards wildcards) {
+        this.wildcards = wildcards.getInt();
+        return this;
+    }
+
+    /**
+     * Initializes this OFMatch structure with the corresponding data from the
+     * specified packet. Must specify the input port, to ensure that
+     * this.in_port is set correctly. Specify OFPort.NONE or OFPort.ANY if input
+     * port not applicable or available
+     *
+     * @param packetData
+     *            The packet's data
+     * @param inputPort
+     *            the port the packet arrived on
+     */
+    public OFMatch loadFromPacket(byte[] packetData, short inputPort) {
+        short scratch;
+        int transportOffset = 34;
+        ByteBuffer packetDataBB = ByteBuffer.wrap(packetData);
+        int limit = packetDataBB.limit();
+
+        this.wildcards = 0; // all fields have explicit entries
+
+        this.inputPort = inputPort;
+
+        if (inputPort == OFPort.OFPP_ALL.getValue())
+                                                    this.wildcards |= OFPFW_IN_PORT;
+
+        assert (limit >= 14);
+        // dl dst
+        this.dataLayerDestination = new byte[6];
+        packetDataBB.get(this.dataLayerDestination);
+        // dl src
+        this.dataLayerSource = new byte[6];
+        packetDataBB.get(this.dataLayerSource);
+        // dl type
+        this.dataLayerType = packetDataBB.getShort();
+
+        if (getDataLayerType() != (short) 0x8100) { // need cast to avoid signed
+            // bug
+            setDataLayerVirtualLan((short) 0xffff);
+            setDataLayerVirtualLanPriorityCodePoint((byte) 0);
+        } else {
+            // has vlan tag
+            scratch = packetDataBB.getShort();
+            setDataLayerVirtualLan((short) (0xfff & scratch));
+            setDataLayerVirtualLanPriorityCodePoint((byte) ((0xe000 & scratch) >> 13));
+            this.dataLayerType = packetDataBB.getShort();
+        }
+
+        switch (getDataLayerType()) {
+            case 0x0800:
+                // ipv4
+                // check packet length
+                scratch = packetDataBB.get();
+                scratch = (short) (0xf & scratch);
+                transportOffset = (packetDataBB.position() - 1)
+                                  + (scratch * 4);
+                // nw tos (dscp)
+                scratch = packetDataBB.get();
+                setNetworkTypeOfService((byte) ((0xfc & scratch) >> 2));
+                // nw protocol
+                packetDataBB.position(packetDataBB.position() + 7);
+                this.networkProtocol = packetDataBB.get();
+                // nw src
+                packetDataBB.position(packetDataBB.position() + 2);
+                this.networkSource = packetDataBB.getInt();
+                // nw dst
+                this.networkDestination = packetDataBB.getInt();
+                packetDataBB.position(transportOffset);
+                break;
+            case 0x0806:
+                // arp
+                int arpPos = packetDataBB.position();
+                // opcode
+                scratch = packetDataBB.getShort(arpPos + 6);
+                setNetworkProtocol((byte) (0xff & scratch));
+
+                scratch = packetDataBB.getShort(arpPos + 2);
+                // if ipv4 and addr len is 4
+                if (scratch == 0x800 && packetDataBB.get(arpPos + 5) == 4) {
+                    // nw src
+                    this.networkSource = packetDataBB.getInt(arpPos + 14);
+                    // nw dst
+                    this.networkDestination = packetDataBB.getInt(arpPos + 24);
+                } else {
+                    setNetworkSource(0);
+                    setNetworkDestination(0);
+                }
+                break;
+            default:
+                // Not ARP or IP. Wildcard NW_DST and NW_SRC
+                this.wildcards |= OFPFW_NW_DST_ALL |
+                                  OFPFW_NW_SRC_ALL |
+                                  OFPFW_NW_PROTO |
+                                  OFPFW_NW_TOS;
+                setNetworkTypeOfService((byte) 0);
+                setNetworkProtocol((byte) 0);
+                setNetworkSource(0);
+                setNetworkDestination(0);
+                break;
+        }
+
+        switch (getNetworkProtocol()) {
+            case 0x01:
+                // icmp
+                // type
+                this.transportSource = U8.f(packetDataBB.get());
+                // code
+                this.transportDestination = U8.f(packetDataBB.get());
+                break;
+            case 0x06:
+                // tcp
+                // tcp src
+                this.transportSource = packetDataBB.getShort();
+                // tcp dest
+                this.transportDestination = packetDataBB.getShort();
+                break;
+            case 0x11:
+                // udp
+                // udp src
+                this.transportSource = packetDataBB.getShort();
+                // udp dest
+                this.transportDestination = packetDataBB.getShort();
+                break;
+            default:
+                // Unknown network proto.
+                this.wildcards |= OFPFW_TP_DST | OFPFW_TP_SRC;
+                setTransportDestination((short) 0);
+                setTransportSource((short) 0);
+                break;
+        }
+        return this;
+    }
+
+    /**
+     * Read this message off the wire from the specified ByteBuffer
+     *
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data) {
+        this.wildcards = data.readInt();
+        this.inputPort = data.readShort();
+        this.dataLayerSource = new byte[6];
+        data.readBytes(this.dataLayerSource);
+        this.dataLayerDestination = new byte[6];
+        data.readBytes(this.dataLayerDestination);
+        this.dataLayerVirtualLan = data.readShort();
+        this.dataLayerVirtualLanPriorityCodePoint = data.readByte();
+        data.readByte(); // pad
+        this.dataLayerType = data.readShort();
+        this.networkTypeOfService = data.readByte();
+        this.networkProtocol = data.readByte();
+        data.readByte(); // pad
+        data.readByte(); // pad
+        this.networkSource = data.readInt();
+        this.networkDestination = data.readInt();
+        this.transportSource = data.readShort();
+        this.transportDestination = data.readShort();
+    }
+
+    /**
+     * Write this message's binary format to the specified ByteBuffer
+     *
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(wildcards);
+        data.writeShort(inputPort);
+        data.writeBytes(this.dataLayerSource);
+        data.writeBytes(this.dataLayerDestination);
+        data.writeShort(dataLayerVirtualLan);
+        data.writeByte(dataLayerVirtualLanPriorityCodePoint);
+        data.writeByte((byte) 0x0); // pad
+        data.writeShort(dataLayerType);
+        data.writeByte(networkTypeOfService);
+        data.writeByte(networkProtocol);
+        data.writeByte((byte) 0x0); // pad
+        data.writeByte((byte) 0x0); // pad
+        data.writeInt(networkSource);
+        data.writeInt(networkDestination);
+        data.writeShort(transportSource);
+        data.writeShort(transportDestination);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 131;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(dataLayerDestination);
+        result = prime * result + Arrays.hashCode(dataLayerSource);
+        result = prime * result + dataLayerType;
+        result = prime * result + dataLayerVirtualLan;
+        result = prime * result + dataLayerVirtualLanPriorityCodePoint;
+        result = prime * result + inputPort;
+        result = prime * result + networkDestination;
+        result = prime * result + networkProtocol;
+        result = prime * result + networkSource;
+        result = prime * result + networkTypeOfService;
+        result = prime * result + transportDestination;
+        result = prime * result + transportSource;
+        result = prime * result + wildcards;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFMatch)) {
+            return false;
+        }
+        OFMatch other = (OFMatch) obj;
+        if (!Arrays.equals(dataLayerDestination, other.dataLayerDestination)) {
+            return false;
+        }
+        if (!Arrays.equals(dataLayerSource, other.dataLayerSource)) {
+            return false;
+        }
+        if (dataLayerType != other.dataLayerType) {
+            return false;
+        }
+        if (dataLayerVirtualLan != other.dataLayerVirtualLan) {
+            return false;
+        }
+        if (dataLayerVirtualLanPriorityCodePoint != other.dataLayerVirtualLanPriorityCodePoint) {
+            return false;
+        }
+        if (inputPort != other.inputPort) {
+            return false;
+        }
+        if (networkDestination != other.networkDestination) {
+            return false;
+        }
+        if (networkProtocol != other.networkProtocol) {
+            return false;
+        }
+        if (networkSource != other.networkSource) {
+            return false;
+        }
+        if (networkTypeOfService != other.networkTypeOfService) {
+            return false;
+        }
+        if (transportDestination != other.transportDestination) {
+            return false;
+        }
+        if (transportSource != other.transportSource) {
+            return false;
+        }
+        if ((wildcards & OFMatch.OFPFW_ALL) != (other.wildcards & OFPFW_ALL)) { // only
+            // consider
+            // allocated
+            // part
+            // of
+            // wildcards
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Implement clonable interface
+     */
+    @Override
+    public OFMatch clone() {
+        try {
+            OFMatch ret = (OFMatch) super.clone();
+            ret.dataLayerDestination = this.dataLayerDestination.clone();
+            ret.dataLayerSource = this.dataLayerSource.clone();
+            return ret;
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * matching two OFMatch
+     * @param toCompare
+     * @return
+     */
+    public boolean match(OFMatch toCompare) {
+        if ((wildcards & OFPFW_IN_PORT) == 0 &&
+                this.inputPort != toCompare.getInputPort())
+            return false;
+        if ((wildcards & OFPFW_DL_DST) == 0 &&
+                !Arrays.equals(this.dataLayerDestination, toCompare.getDataLayerDestination()))
+            return false;
+        if ((wildcards & OFPFW_DL_SRC) == 0 &&
+                !Arrays.equals(this.dataLayerSource, toCompare.getDataLayerSource()))
+            return false;
+        if ((wildcards & OFPFW_DL_TYPE) == 0
+                && this.dataLayerType != toCompare.getDataLayerType())
+            return false;
+        if ((wildcards & OFPFW_DL_VLAN) == 0 &&
+                this.dataLayerVirtualLan != toCompare.getDataLayerVirtualLan())
+            return false;
+        if ((wildcards & OFPFW_DL_VLAN_PCP) == 0 &&
+                this.dataLayerVirtualLanPriorityCodePoint != toCompare.getDataLayerVirtualLanPriorityCodePoint())
+            return false;
+        if ((wildcards & OFPFW_NW_PROTO) == 0 &&
+                this.networkProtocol != toCompare.getNetworkProtocol())
+            return false;
+        if ((wildcards & OFPFW_NW_TOS) == 0 &&
+                this.networkTypeOfService != toCompare.getNetworkTypeOfService())
+            return false;
+        //compare network layer src/dst
+
+        int dstmasklen = getNetworkDestinationMaskLen();
+        int srcmasklen = getNetworkSourceMaskLen();
+        if (dstmasklen >= 32 && networkDestination != toCompare.getNetworkDestination())
+            return false;
+        if (srcmasklen >= 32 && networkSource != toCompare.getNetworkSource())
+            return false;
+        int dstmask = ~((1 << (32 - dstmasklen)) - 1);
+        int srcmask = ~((1 << (32 - srcmasklen)) - 1);
+        if (dstmasklen < 32 &&
+                (networkDestination & dstmask) != (toCompare.getNetworkDestination() & dstmask))
+            return false;
+        if (srcmasklen < 32 &&
+                (networkSource & srcmask) != (toCompare.getNetworkSource() & srcmask))
+            return false;
+        //layer 4
+        if ((wildcards & OFPFW_TP_DST) == 0 &&
+                this.transportDestination != toCompare.getTransportDestination())
+            return false;
+        if ((wildcards & OFPFW_TP_SRC) == 0 &&
+                this.transportSource != toCompare.getTransportSource())
+            return false;
+        return true;
+    }
+
+    /**
+     * Output a dpctl-styled string, i.e., only list the elements that are not
+     * wildcarded A match-everything OFMatch outputs "OFMatch[]"
+     *
+     * @return
+     *         "OFMatch[dl_src:00:20:01:11:22:33,nw_src:192.168.0.0/24,tp_dst:80]"
+     */
+    @Override
+    public String toString() {
+        String str = "";
+
+        // l1
+        if ((wildcards & OFPFW_IN_PORT) == 0)
+                                             str += "," + STR_IN_PORT + "="
+                                                    + U16.f(this.inputPort);
+
+        // l2
+        if ((wildcards & OFPFW_DL_DST) == 0)
+                                            str += ","
+                                                   + STR_DL_DST
+                                                   + "="
+                                                   + HexString.toHexString(this.dataLayerDestination);
+        if ((wildcards & OFPFW_DL_SRC) == 0)
+                                            str += ","
+                                                   + STR_DL_SRC
+                                                   + "="
+                                                   + HexString.toHexString(this.dataLayerSource);
+        if ((wildcards & OFPFW_DL_TYPE) == 0)
+                                             str += ","
+                                                    + STR_DL_TYPE
+                                                    + "=0x"
+                                                    + Integer.toHexString(U16.f(this.dataLayerType));
+        if ((wildcards & OFPFW_DL_VLAN) == 0)
+                                             str += ","
+                                                    + STR_DL_VLAN
+                                                    + "=0x"
+                                                    + Integer.toHexString(U16.f(this.dataLayerVirtualLan));
+        if ((wildcards & OFPFW_DL_VLAN_PCP) == 0)
+                                                 str += ","
+                                                        + STR_DL_VLAN_PCP
+                                                        + "="
+                                                        + Integer.toHexString(U8.f(this.dataLayerVirtualLanPriorityCodePoint));
+
+        // l3
+        if (getNetworkDestinationMaskLen() > 0)
+                                               str += ","
+                                                      + STR_NW_DST
+                                                      + "="
+                                                      + cidrToString(networkDestination,
+                                                                     getNetworkDestinationMaskLen());
+        if (getNetworkSourceMaskLen() > 0)
+                                          str += ","
+                                                 + STR_NW_SRC
+                                                 + "="
+                                                 + cidrToString(networkSource,
+                                                                getNetworkSourceMaskLen());
+        if ((wildcards & OFPFW_NW_PROTO) == 0)
+                                              str += "," + STR_NW_PROTO
+                                                     + "="
+                                                     + this.networkProtocol;
+        if ((wildcards & OFPFW_NW_TOS) == 0)
+                                            str += ","
+                                                   + STR_NW_TOS
+                                                   + "="
+                                                   + this.getNetworkTypeOfService();
+
+        // l4
+        if ((wildcards & OFPFW_TP_DST) == 0)
+                                            str += ","
+                                                   + STR_TP_DST
+                                                   + "="
+                                                   + this.transportDestination;
+        if ((wildcards & OFPFW_TP_SRC) == 0)
+                                            str += "," + STR_TP_SRC + "="
+                                                   + this.transportSource;
+        if ((str.length() > 0) && (str.charAt(0) == ','))
+                                                         str = str.substring(1); // trim
+                                                                                 // the
+                                                                                 // leading
+                                                                                 // ","
+        // done
+        return "OFMatch[" + str + "]";
+    }
+
+    /**
+     * Return a string including all match fields, regardless whether they
+     * are wildcarded or not.
+     */
+    public String toStringUnmasked() {
+        String str = "";
+
+        // l1
+        str += STR_IN_PORT + "=" + U16.f(this.inputPort);
+
+        // l2
+        str += "," + STR_DL_DST + "="
+                + HexString.toHexString(this.dataLayerDestination);
+        str += "," + STR_DL_SRC + "="
+                + HexString.toHexString(this.dataLayerSource);
+        str += "," + STR_DL_TYPE + "=0x"
+                + Integer.toHexString(U16.f(this.dataLayerType));
+        str += "," + STR_DL_VLAN + "=0x"
+                + Integer.toHexString(U16.f(this.dataLayerVirtualLan));
+        str += "," + STR_DL_VLAN_PCP + "="
+                + Integer.toHexString(U8.f(this.dataLayerVirtualLanPriorityCodePoint));
+
+        // l3
+        str += "," + STR_NW_DST + "="
+                + cidrToString(networkDestination,
+                               getNetworkDestinationMaskLen());
+        str += "," + STR_NW_SRC + "="
+                + cidrToString(networkSource,
+                               getNetworkSourceMaskLen());
+        str += "," + STR_NW_PROTO + "=" + this.networkProtocol;
+        str += "," + STR_NW_TOS + "=" + this.getNetworkTypeOfService();
+
+        // l4
+        str += "," + STR_TP_DST + "=" + this.transportDestination;
+        str += "," + STR_TP_SRC + "=" + this.transportSource;
+
+        // wildcards
+        str += ", wildcards=" + debugWildCards(wildcards);
+        return "OFMatch[" + str + "]";
+    }
+
+    /**
+     * debug a set of wildcards
+     */
+    public static String debugWildCards(int wildcards) {
+        String str = "";
+
+        // l1
+        if ((wildcards & OFPFW_IN_PORT) != 0) str += "|" + STR_IN_PORT;
+
+        // l2
+        if ((wildcards & OFPFW_DL_DST) != 0) str += "|" + STR_DL_DST;
+        if ((wildcards & OFPFW_DL_SRC) != 0) str += "|" + STR_DL_SRC;
+        if ((wildcards & OFPFW_DL_TYPE) != 0) str += "|" + STR_DL_TYPE;
+        if ((wildcards & OFPFW_DL_VLAN) != 0) str += "|" + STR_DL_VLAN;
+        if ((wildcards & OFPFW_DL_VLAN_PCP) != 0)
+                                                 str += "|"
+                                                        + STR_DL_VLAN_PCP;
+
+        int nwDstMask = Math.max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT),
+                                 0);
+        int nwSrcMask = Math.max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT),
+                                 0);
+
+        // l3
+        if (nwDstMask < 32)
+                           str += "|" + STR_NW_DST + "(/" + nwDstMask + ")";
+
+        if (nwSrcMask < 32)
+                           str += "|" + STR_NW_SRC + "(/" + nwSrcMask + ")";
+
+        if ((wildcards & OFPFW_NW_PROTO) != 0) str += "|" + STR_NW_PROTO;
+        if ((wildcards & OFPFW_NW_TOS) != 0) str += "|" + STR_NW_TOS;
+
+        // l4
+        if ((wildcards & OFPFW_TP_DST) != 0) str += "|" + STR_TP_DST;
+        if ((wildcards & OFPFW_TP_SRC) != 0) str += "|" + STR_TP_SRC;
+        if ((str.length() > 0) && (str.charAt(0) == '|'))
+                                                         str = str.substring(1); // trim
+                                                                                 // the
+                                                                                 // leading
+                                                                                 // ","
+        // done
+        return str;
+    }
+
+    private String cidrToString(int ip, int prefix) {
+        String str;
+        if (prefix >= 32) {
+            str = ipToString(ip);
+        } else {
+            // use the negation of mask to fake endian magic
+            int mask = ~((1 << (32 - prefix)) - 1);
+            str = ipToString(ip & mask) + "/" + prefix;
+        }
+
+        return str;
+    }
+
+    /**
+     * Set this OFMatch's parameters based on a comma-separated key=value pair
+     * dpctl-style string, e.g., from the output of OFMatch.toString() <br>
+     * <p>
+     * Supported keys/values include <br>
+     * <p>
+     * <TABLE border=1>
+     * <TR>
+     * <TD>KEY(s)
+     * <TD>VALUE
+     * </TR>
+     * <TR>
+     * <TD>"in_port","input_port"
+     * <TD>integer
+     * </TR>
+     * <TR>
+     * <TD>"dl_src","eth_src", "dl_dst","eth_dst"
+     * <TD>hex-string
+     * </TR>
+     * <TR>
+     * <TD>"dl_type", "dl_vlan", "dl_vlan_pcp"
+     * <TD>integer
+     * </TR>
+     * <TR>
+     * <TD>"nw_src", "nw_dst", "ip_src", "ip_dst"
+     * <TD>CIDR-style netmask
+     * </TR>
+     * <TR>
+     * <TD>"tp_src","tp_dst"
+     * <TD>integer (max 64k)
+     * </TR>
+     * </TABLE>
+     * <p>
+     * The CIDR-style netmasks assume 32 netmask if none given, so:
+     * "128.8.128.118/32" is the same as "128.8.128.118"
+     *
+     * @param match
+     *            a key=value comma separated string, e.g.
+     *            "in_port=5,ip_dst=192.168.0.0/16,tp_src=80"
+     * @throws IllegalArgumentException
+     *             on unexpected key or value
+     */
+
+    public void fromString(String match) throws IllegalArgumentException {
+        if (match.equals("") || match.equalsIgnoreCase("any")
+            || match.equalsIgnoreCase("all") || match.equals("[]"))
+                                                                   match = "OFMatch[]";
+        String[] tokens = match.split("[\\[,\\]]");
+        String[] values;
+        int initArg = 0;
+        if (tokens[0].equals("OFMatch")) initArg = 1;
+        this.wildcards = OFPFW_ALL;
+        int i;
+        for (i = initArg; i < tokens.length; i++) {
+            values = tokens[i].split("=");
+            if (values.length != 2)
+                                   throw new IllegalArgumentException(
+                                                                      "Token "
+                                                                              + tokens[i]
+                                                                              + " does not have form 'key=value' parsing "
+                                                                              + match);
+            values[0] = values[0].toLowerCase(); // try to make this case insens
+            if (values[0].equals(STR_IN_PORT)
+                || values[0].equals("input_port")) {
+                this.inputPort = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_IN_PORT;
+            } else if (values[0].equals(STR_DL_DST)
+                       || values[0].equals("eth_dst")) {
+                this.dataLayerDestination = HexString.fromHexString(values[1]);
+                this.wildcards &= ~OFPFW_DL_DST;
+            } else if (values[0].equals(STR_DL_SRC)
+                       || values[0].equals("eth_src")) {
+                this.dataLayerSource = HexString.fromHexString(values[1]);
+                this.wildcards &= ~OFPFW_DL_SRC;
+            } else if (values[0].equals(STR_DL_TYPE)
+                       || values[0].equals("eth_type")) {
+                if (values[1].startsWith("0x"))
+                    this.dataLayerType = U16.t(Integer.valueOf(values[1].replaceFirst("0x",
+                                                                                      ""),
+                                                               16));
+                else
+                    this.dataLayerType = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_DL_TYPE;
+            } else if (values[0].equals(STR_DL_VLAN)) {
+                if (values[1].startsWith("0x"))
+                    this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1].replaceFirst("0x",
+                                                                                            ""),
+                                                                     16));
+                else
+                    this.dataLayerVirtualLan = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_DL_VLAN;
+            } else if (values[0].equals(STR_DL_VLAN_PCP)) {
+                this.dataLayerVirtualLanPriorityCodePoint = U8.t(Short.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_DL_VLAN_PCP;
+            } else if (values[0].equals(STR_NW_DST)
+                       || values[0].equals("ip_dst")) {
+                setFromCIDR(values[1], STR_NW_DST);
+            } else if (values[0].equals(STR_NW_SRC)
+                       || values[0].equals("ip_src")) {
+                setFromCIDR(values[1], STR_NW_SRC);
+            } else if (values[0].equals(STR_NW_PROTO)) {
+                if (values[1].startsWith("0x"))
+                    this.networkProtocol = U8.t(Short.valueOf(values[1].replaceFirst("0x",""),16));
+                else
+                    this.networkProtocol = U8.t(Short.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_NW_PROTO;
+            } else if (values[0].equals(STR_NW_TOS)) {
+                this.setNetworkTypeOfService(U8.t(Short.valueOf(values[1])));
+                this.wildcards &= ~OFPFW_NW_TOS;
+            } else if (values[0].equals(STR_TP_DST)) {
+                this.transportDestination = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_TP_DST;
+            } else if (values[0].equals(STR_TP_SRC)) {
+                this.transportSource = U16.t(Integer.valueOf(values[1]));
+                this.wildcards &= ~OFPFW_TP_SRC;
+            } else {
+                throw new IllegalArgumentException("unknown token "
+                                                   + tokens[i] + " parsing "
+                                                   + match);
+            }
+        }
+    }
+
+    /**
+     * Set the networkSource or networkDestionation address and their wildcards
+     * from the CIDR string
+     *
+     * @param cidr
+     *            "192.168.0.0/16" or "172.16.1.5"
+     * @param which
+     *            one of STR_NW_DST or STR_NW_SRC
+     * @throws IllegalArgumentException
+     */
+    private
+            void
+            setFromCIDR(String cidr, String which)
+                                                  throws IllegalArgumentException {
+        String values[] = cidr.split("/");
+        String[] ip_str = values[0].split("\\.");
+        int ip = 0;
+        ip += Integer.valueOf(ip_str[0]) << 24;
+        ip += Integer.valueOf(ip_str[1]) << 16;
+        ip += Integer.valueOf(ip_str[2]) << 8;
+        ip += Integer.valueOf(ip_str[3]);
+        int prefix = 32; // all bits are fixed, by default
+
+        if (values.length >= 2) prefix = Integer.valueOf(values[1]);
+        int mask = 32 - prefix;
+        if (which.equals(STR_NW_DST)) {
+            this.networkDestination = ip;
+            this.wildcards = (wildcards & ~OFPFW_NW_DST_MASK)
+                             | (mask << OFPFW_NW_DST_SHIFT);
+        } else if (which.equals(STR_NW_SRC)) {
+            this.networkSource = ip;
+            this.wildcards = (wildcards & ~OFPFW_NW_SRC_MASK)
+                             | (mask << OFPFW_NW_SRC_SHIFT);
+        }
+    }
+
+    protected static String ipToString(int ip) {
+        return Integer.toString(U8.f((byte) ((ip & 0xff000000) >> 24)))
+               + "." + Integer.toString((ip & 0x00ff0000) >> 16) + "."
+               + Integer.toString((ip & 0x0000ff00) >> 8) + "."
+               + Integer.toString(ip & 0x000000ff);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFMatchBeanInfo.java b/src/main/java/org/openflow/protocol/OFMatchBeanInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..97e14a5592b90062153acd0d77b28168250edb38
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFMatchBeanInfo.java
@@ -0,0 +1,101 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import java.beans.SimpleBeanInfo;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Extra info for how to treat OFMatch as a JavaBean
+ *
+ * For some (inane!) reason, using chained setters in OFMatch breaks a lot of the JavaBean defaults.
+ *
+ * We don't really use OFMatch as a java bean, but there are a lot of nice XML utils that work for
+ * free if OFMatch follows the java bean paradigm.
+ *
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ *
+ */
+
+public class OFMatchBeanInfo extends SimpleBeanInfo {
+
+    @Override
+    public PropertyDescriptor[] getPropertyDescriptors() {
+        List<PropertyDescriptor> descs = new LinkedList<PropertyDescriptor>();
+        Field[] fields = OFMatch.class.getDeclaredFields();
+        String name;
+        for (int i=0; i< fields.length; i++) {
+            int mod = fields[i].getModifiers();
+            if(Modifier.isFinal(mod) ||     // don't expose static or final fields
+                    Modifier.isStatic(mod))
+                continue;
+
+            name = fields[i].getName();
+            Class<?> type = fields[i].getType();
+
+            try {
+                descs.add(new PropertyDescriptor(name,
+                        name2getter(OFMatch.class, name),
+                        name2setter(OFMatch.class, name, type)));
+            } catch (IntrospectionException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        return descs.toArray(new PropertyDescriptor[0]);
+    }
+
+
+    private Method name2setter(Class<OFMatch> c, String name, Class<?> type) {
+        String mName = "set" + toLeadingCaps(name);
+        Method m = null;
+        try {
+            m = c.getMethod(mName, new Class[]{ type});
+        } catch (SecurityException e) {
+            throw new RuntimeException(e);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException(e);
+        }
+        return m;
+    }
+
+    private Method name2getter(Class<OFMatch> c, String name) {
+        String mName= "get" + toLeadingCaps(name);
+        Method m = null;
+        try {
+            m = c.getMethod(mName, new Class[]{});
+        } catch (SecurityException e) {
+            throw new RuntimeException(e);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException(e);
+        }
+        return m;
+    }
+
+    private String toLeadingCaps(String s) {
+        char[] array = s.toCharArray();
+        array[0] = Character.toUpperCase(array[0]);
+        return String.valueOf(array, 0, array.length);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java b/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java
new file mode 100644
index 0000000000000000000000000000000000000000..04ecf5e5edea269c912af7b0f5d8b65b17ebaa80
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFMatchWithSwDpid.java
@@ -0,0 +1,92 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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 org.openflow.protocol;
+
+import org.openflow.util.HexString;
+
+public class OFMatchWithSwDpid {
+    protected OFMatch ofMatch;
+    protected long  switchDataPathId;
+
+    public OFMatchWithSwDpid() {
+    	this.ofMatch = new OFMatch();
+    	this.switchDataPathId = 0;
+    }
+    
+    public OFMatchWithSwDpid(OFMatch ofm, long swDpid) {
+    	this.ofMatch = ofm.clone();
+    	this.switchDataPathId = swDpid;
+    }
+    public OFMatch getOfMatch() {
+		return ofMatch;
+	}
+
+	public void setOfMatch(OFMatch ofMatch) {
+		this.ofMatch = ofMatch.clone();
+	}
+
+	public long getSwitchDataPathId() {
+        return this.switchDataPathId;
+    }
+
+    public OFMatchWithSwDpid setSwitchDataPathId(long dpid) {
+        this.switchDataPathId = dpid;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return "OFMatchWithSwDpid [" + HexString.toHexString(switchDataPathId)
+                + " " + ofMatch + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result
+                 + ((ofMatch == null) ? 0 : ofMatch.hashCode());
+        result = prime * result
+                 + (int) (switchDataPathId ^ (switchDataPathId >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFMatchWithSwDpid)) {
+            return false;
+        }
+        OFMatchWithSwDpid other = (OFMatchWithSwDpid) obj;
+        if (ofMatch == null) {
+            if (other.ofMatch != null) {
+                return false;
+            }
+        } else if (!ofMatch.equals(other.ofMatch)) {
+            return false;
+        }
+        if (switchDataPathId != other.switchDataPathId) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFMessage.java b/src/main/java/org/openflow/protocol/OFMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..38f4e477317e79682416b2145985bd4fa3948f5f
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFMessage.java
@@ -0,0 +1,336 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.ConcurrentHashMap;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.packet.Ethernet;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.HexString;
+import org.openflow.util.U16;
+import org.openflow.util.U32;
+import org.openflow.util.U8;
+
+/**
+ * The base class for all OpenFlow protocol messages. This class contains the
+ * equivalent of the ofp_header which is present in all OpenFlow messages.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Feb 3, 2010
+ * @author Rob Sherwood (rob.sherwood@stanford.edu) - Feb 3, 2010
+ */
+public class OFMessage {
+    public static final int MAXIMUM_LENGTH = (1 << 16) - 1;
+    public static byte OFP_VERSION = 0x01;
+    public static int MINIMUM_LENGTH = 8;
+
+    protected byte version;
+    protected OFType type;
+    protected short length;
+    protected int xid;
+
+    private ConcurrentHashMap<String, Object> storage;
+
+    public OFMessage() {
+        storage = null;
+        this.version = OFP_VERSION;
+    }
+
+    protected synchronized ConcurrentHashMap<String, Object> getMessageStore() {
+        if (storage == null) {
+            storage = new ConcurrentHashMap<String, Object>();;
+        }
+        return storage;
+    }
+
+    /**
+     * Get the length of this message
+     *
+     * @return
+     */
+    public short getLength() {
+        return length;
+    }
+
+    /**
+     * Get the length of this message, unsigned
+     *
+     * @return
+     */
+    public int getLengthU() {
+        return U16.f(length);
+    }
+
+    /**
+     * Set the length of this message
+     *
+     * @param length
+     */
+    public OFMessage setLength(short length) {
+        this.length = length;
+        return this;
+    }
+
+    /**
+     * Set the length of this message, unsigned
+     *
+     * @param length
+     */
+    public OFMessage setLengthU(int length) {
+        this.length = U16.t(length);
+        return this;
+    }
+
+    /**
+     * Get the type of this message
+     *
+     * @return
+     */
+    public OFType getType() {
+        return type;
+    }
+
+    /**
+     * Set the type of this message
+     *
+     * @param type
+     */
+    public void setType(OFType type) {
+        this.type = type;
+    }
+
+    /**
+     * Get the OpenFlow version of this message
+     *
+     * @return
+     */
+    public byte getVersion() {
+        return version;
+    }
+
+    /**
+     * Set the OpenFlow version of this message
+     *
+     * @param version
+     */
+    public void setVersion(byte version) {
+        this.version = version;
+    }
+
+    /**
+     * Get the transaction id of this message
+     *
+     * @return
+     */
+    public int getXid() {
+        return xid;
+    }
+
+    /**
+     * Set the transaction id of this message
+     *
+     * @param xid
+     */
+    public void setXid(int xid) {
+        this.xid = xid;
+    }
+
+    /**
+     * Read this message off the wire from the specified ByteBuffer
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data) {
+        this.version = data.readByte();
+        this.type = OFType.valueOf(data.readByte());
+        this.length = data.readShort();
+        this.xid = data.readInt();
+    }
+
+    /**
+     * Write this message's binary format to the specified ByteBuffer
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data) {
+        data.writeByte(version);
+        data.writeByte(type.getTypeValue());
+        data.writeShort(length);
+        data.writeInt(xid);
+    }
+
+    /**
+     * Returns a summary of the message
+     * @return "ofmsg=v=$version;t=$type:l=$len:xid=$xid"
+     */
+    @Override
+    public String toString() {
+        return "ofmsg" +
+            ":v=" + U8.f(this.getVersion()) +
+            ";t=" + this.getType() +
+            ";l=" + this.getLengthU() +
+            ";x=" + U32.f(this.getXid());
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 97;
+        int result = 1;
+        result = prime * result + length;
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        result = prime * result + version;
+        result = prime * result + xid;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFMessage)) {
+            return false;
+        }
+        OFMessage other = (OFMessage) obj;
+        if (length != other.length) {
+            return false;
+        }
+        if (type == null) {
+            if (other.type != null) {
+                return false;
+            }
+        } else if (!type.equals(other.type)) {
+            return false;
+        }
+        if (version != other.version) {
+            return false;
+        }
+        if (xid != other.xid) {
+            return false;
+        }
+        return true;
+    }
+
+    public static String getDataAsString(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+
+        Ethernet eth;
+        StringBuffer sb =  new StringBuffer("");
+
+        DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
+        Date date = new Date();
+
+        sb.append(dateFormat.format(date));
+        sb.append("      ");
+
+        switch (msg.getType()) {
+            case PACKET_IN:
+                OFPacketIn pktIn = (OFPacketIn) msg;
+                sb.append("packet_in          [ ");
+                sb.append(sw.getStringId());
+                sb.append(" -> Controller");
+                sb.append(" ]");
+
+                sb.append("\ntotal length: ");
+                sb.append(pktIn.getTotalLength());
+                sb.append("\nin_port: ");
+                sb.append(pktIn.getInPort());
+                sb.append("\ndata_length: ");
+                sb.append(pktIn.getTotalLength() - OFPacketIn.MINIMUM_LENGTH);
+                sb.append("\nbuffer: ");
+                sb.append(pktIn.getBufferId());
+
+                // If the conext is not set by floodlight, then ignore.
+                if (cntx != null) {
+                // packet type  icmp, arp, etc.
+                    eth = IFloodlightProviderService.bcStore.get(cntx,
+                            IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+                    if (eth != null)
+                           sb.append(eth.toString());
+                }
+                break;
+
+            case PACKET_OUT:
+                OFPacketOut pktOut = (OFPacketOut) msg;
+                sb.append("packet_out         [ ");
+                sb.append("Controller -> ");
+                sb.append(HexString.toHexString(sw.getId()));
+                sb.append(" ]");
+
+                sb.append("\nin_port: ");
+                sb.append(pktOut.getInPort());
+                sb.append("\nactions_len: ");
+                sb.append(pktOut.getActionsLength());
+                if (pktOut.getActions() != null) {
+                    sb.append("\nactions: ");
+                    sb.append(pktOut.getActions().toString());
+                }
+                break;
+
+            case FLOW_MOD:
+                OFFlowMod fm = (OFFlowMod) msg;
+                sb.append("flow_mod           [ ");
+                sb.append("Controller -> ");
+                sb.append(HexString.toHexString(sw.getId()));
+                sb.append(" ]");
+
+                // If the conext is not set by floodlight, then ignore.
+                if (cntx != null) {
+                    eth = IFloodlightProviderService.bcStore.get(cntx,
+                        IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+                    if (eth != null)
+                        sb.append(eth.toString());
+                }
+
+                sb.append("\nADD: cookie: ");
+                sb.append(fm.getCookie());
+                sb.append(" idle: ");
+                sb.append(fm.getIdleTimeout());
+                sb.append(" hard: ");
+                sb.append(fm.getHardTimeout());
+                sb.append(" pri: ");
+                sb.append(fm.getPriority());
+                sb.append(" buf: ");
+                sb.append(fm.getBufferId());
+                sb.append(" flg: ");
+                sb.append(fm.getFlags());
+                if (fm.getActions() != null) {
+                    sb.append("\nactions: ");
+                    sb.append(fm.getActions().toString());
+                }
+                break;
+
+            default:
+                sb.append("[Unknown Packet]");
+        }
+
+        sb.append("\n\n");
+        return sb.toString();
+
+    }
+
+    public static byte[] getData(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+        return OFMessage.getDataAsString(sw, msg, cntx).getBytes();
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFMessageContextStore.java b/src/main/java/org/openflow/protocol/OFMessageContextStore.java
new file mode 100644
index 0000000000000000000000000000000000000000..b60aa1cd4b981ef94335bf1eb67447894de2cf15
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFMessageContextStore.java
@@ -0,0 +1,39 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.openflow.protocol.OFMessage;
+
+public class OFMessageContextStore<V> {
+    protected OFMessage msg;
+    String namespace;
+    
+    public OFMessageContextStore(OFMessage msg, String namespace) {
+        this.msg = msg;
+        this.namespace = namespace;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public V get(String key) {
+        return (V)msg.getMessageStore().get(namespace + "|" + key);
+    }
+    
+    public void put(String key, V value) {
+        msg.getMessageStore().put(namespace + "|" + key, value);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFPacketIn.java b/src/main/java/org/openflow/protocol/OFPacketIn.java
new file mode 100644
index 0000000000000000000000000000000000000000..c37c9184cc0bd710989a0b8197aab5146b6d8ad2
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFPacketIn.java
@@ -0,0 +1,211 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+import org.openflow.util.U32;
+import org.openflow.util.U8;
+
+/**
+ * Represents an ofp_packet_in
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Feb 8, 2010
+ */
+public class OFPacketIn extends OFMessage {
+    public static short MINIMUM_LENGTH = 18;
+
+    public enum OFPacketInReason {
+        NO_MATCH, ACTION
+    }
+
+    protected int bufferId;
+    protected short totalLength;
+    protected short inPort;
+    protected OFPacketInReason reason;
+    protected byte[] packetData;
+
+    public OFPacketIn() {
+        super();
+        this.type = OFType.PACKET_IN;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * Get buffer_id
+     * @return
+     */
+    public int getBufferId() {
+        return this.bufferId;
+    }
+
+    /**
+     * Set buffer_id
+     * @param bufferId
+     */
+    public OFPacketIn setBufferId(int bufferId) {
+        this.bufferId = bufferId;
+        return this;
+    }
+
+    /**
+     * Returns the packet data
+     * @return
+     */
+    public byte[] getPacketData() {
+        return this.packetData;
+    }
+
+    /**
+     * Sets the packet data, and updates the length of this message
+     * @param packetData
+     */
+    public OFPacketIn setPacketData(byte[] packetData) {
+        this.packetData = packetData;
+        this.length = U16.t(OFPacketIn.MINIMUM_LENGTH + packetData.length);
+        return this;
+    }
+
+    /**
+     * Get in_port
+     * @return
+     */
+    public short getInPort() {
+        return this.inPort;
+    }
+
+    /**
+     * Set in_port
+     * @param inPort
+     */
+    public OFPacketIn setInPort(short inPort) {
+        this.inPort = inPort;
+        return this;
+    }
+
+    /**
+     * Get reason
+     * @return
+     */
+    public OFPacketInReason getReason() {
+        return this.reason;
+    }
+
+    /**
+     * Set reason
+     * @param reason
+     */
+    public OFPacketIn setReason(OFPacketInReason reason) {
+        this.reason = reason;
+        return this;
+    }
+
+    /**
+     * Get total_len
+     * @return
+     */
+    public short getTotalLength() {
+        return this.totalLength;
+    }
+
+    /**
+     * Set total_len
+     * @param totalLength
+     */
+    public OFPacketIn setTotalLength(short totalLength) {
+        this.totalLength = totalLength;
+        return this;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.bufferId = data.readInt();
+        this.totalLength = data.readShort();
+        this.inPort = data.readShort();
+        this.reason = OFPacketInReason.values()[U8.f(data.readByte())];
+        data.readByte(); // pad
+        this.packetData = new byte[getLengthU() - MINIMUM_LENGTH];
+        data.readBytes(this.packetData);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(bufferId);
+        data.writeShort(totalLength);
+        data.writeShort(inPort);
+        data.writeByte((byte) reason.ordinal());
+        data.writeByte((byte) 0x0); // pad
+        data.writeBytes(this.packetData);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 283;
+        int result = super.hashCode();
+        result = prime * result + bufferId;
+        result = prime * result + inPort;
+        result = prime * result + Arrays.hashCode(packetData);
+        result = prime * result + ((reason == null) ? 0 : reason.hashCode());
+        result = prime * result + totalLength;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPacketIn)) {
+            return false;
+        }
+        OFPacketIn other = (OFPacketIn) obj;
+        if (bufferId != other.bufferId) {
+            return false;
+        }
+        if (inPort != other.inPort) {
+            return false;
+        }
+        if (!Arrays.equals(packetData, other.packetData)) {
+            return false;
+        }
+        if (reason == null) {
+            if (other.reason != null) {
+                return false;
+            }
+        } else if (!reason.equals(other.reason)) {
+            return false;
+        }
+        if (totalLength != other.totalLength) {
+            return false;
+        }
+        return true;
+    }
+
+    public String toString() {
+        String myStr = super.toString();
+        return "packetIn" +
+            ":bufferId=" + U32.f(this.bufferId) + myStr;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFPacketOut.java b/src/main/java/org/openflow/protocol/OFPacketOut.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef4aa61f1b0e86a245bc6dd5ba9aa55c0ba2557d
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFPacketOut.java
@@ -0,0 +1,260 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.factory.OFActionFactory;
+import org.openflow.protocol.factory.OFActionFactoryAware;
+import org.openflow.util.HexString;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_packet_out message
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 12, 2010
+ */
+public class OFPacketOut extends OFMessage implements OFActionFactoryAware {
+    public static int MINIMUM_LENGTH = 16;
+    public static int BUFFER_ID_NONE = 0xffffffff;
+
+    protected OFActionFactory actionFactory;
+    protected int bufferId;
+    protected short inPort;
+    protected short actionsLength;
+    protected List<OFAction> actions;
+    protected byte[] packetData;
+
+    public OFPacketOut() {
+        super();
+        this.type = OFType.PACKET_OUT;
+        this.length = U16.t(MINIMUM_LENGTH);
+        this.bufferId = BUFFER_ID_NONE;
+    }
+
+    /**
+     * Get buffer_id
+     * @return
+     */
+    public int getBufferId() {
+        return this.bufferId;
+    }
+
+    /**
+     * Set buffer_id
+     * @param bufferId
+     */
+    public OFPacketOut setBufferId(int bufferId) {
+        if (packetData != null && packetData.length > 0 && bufferId != BUFFER_ID_NONE) {
+            throw new IllegalArgumentException(
+                    "PacketOut should not have both bufferId and packetData set");
+        }
+        this.bufferId = bufferId;
+        return this;
+    }
+
+    /**
+     * Returns the packet data
+     * @return
+     */
+    public byte[] getPacketData() {
+        return this.packetData;
+    }
+
+    /**
+     * Sets the packet data
+     * @param packetData
+     */
+    public OFPacketOut setPacketData(byte[] packetData) {
+        if (packetData != null && packetData.length > 0 && bufferId != BUFFER_ID_NONE) {
+            throw new IllegalArgumentException(
+                    "PacketOut should not have both bufferId and packetData set");
+        }
+        this.packetData = packetData;
+        return this;
+    }
+
+    /**
+     * Get in_port
+     * @return
+     */
+    public short getInPort() {
+        return this.inPort;
+    }
+
+    /**
+     * Set in_port
+     * @param inPort
+     */
+    public OFPacketOut setInPort(short inPort) {
+        this.inPort = inPort;
+        return this;
+    }
+
+    /**
+     * Set in_port. Convenience method using OFPort enum.
+     * @param inPort
+     */
+    public OFPacketOut setInPort(OFPort inPort) {
+        this.inPort = inPort.getValue();
+        return this;
+    }
+
+    /**
+     * Get actions_len
+     * @return
+     */
+    public short getActionsLength() {
+        return this.actionsLength;
+    }
+
+    /**
+     * Get actions_len, unsigned
+     * @return
+     */
+    public int getActionsLengthU() {
+        return U16.f(this.actionsLength);
+    }
+
+    /**
+     * Set actions_len
+     * @param actionsLength
+     */
+    public OFPacketOut setActionsLength(short actionsLength) {
+        this.actionsLength = actionsLength;
+        return this;
+    }
+
+    /**
+     * Returns the actions contained in this message
+     * @return a list of ordered OFAction objects
+     */
+    public List<OFAction> getActions() {
+        return this.actions;
+    }
+
+    /**
+     * Sets the list of actions on this message
+     * @param actions a list of ordered OFAction objects
+     */
+    public OFPacketOut setActions(List<OFAction> actions) {
+        this.actions = actions;
+        return this;
+    }
+
+    @Override
+    public void setActionFactory(OFActionFactory actionFactory) {
+        this.actionFactory = actionFactory;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.bufferId = data.readInt();
+        this.inPort = data.readShort();
+        this.actionsLength = data.readShort();
+        if ( this.actionFactory == null)
+            throw new RuntimeException("ActionFactory not set");
+        this.actions = this.actionFactory.parseActions(data, getActionsLengthU());
+        this.packetData = new byte[getLengthU() - MINIMUM_LENGTH - getActionsLengthU()];
+        data.readBytes(this.packetData);
+        validate();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        validate();
+        super.writeTo(data);
+        data.writeInt(bufferId);
+        data.writeShort(inPort);
+        data.writeShort(actionsLength);
+        for (OFAction action : actions) {
+            action.writeTo(data);
+        }
+        if (this.packetData != null)
+            data.writeBytes(this.packetData);
+    }
+
+    /** validate the invariants of this OFMessage hold */
+    public void validate() {
+        if (!((bufferId != BUFFER_ID_NONE) ^ (packetData != null && packetData.length > 0))) {
+            throw new IllegalStateException(
+                    "OFPacketOut must have exactly one of (bufferId, packetData) set (not one, not both)");
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 293;
+        int result = super.hashCode();
+        result = prime * result + ((actions == null) ? 0 : actions.hashCode());
+        result = prime * result + actionsLength;
+        result = prime * result + bufferId;
+        result = prime * result + inPort;
+        result = prime * result + Arrays.hashCode(packetData);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPacketOut)) {
+            return false;
+        }
+        OFPacketOut other = (OFPacketOut) obj;
+        if (actions == null) {
+            if (other.actions != null) {
+                return false;
+            }
+        } else if (!actions.equals(other.actions)) {
+            return false;
+        }
+        if (actionsLength != other.actionsLength) {
+            return false;
+        }
+        if (bufferId != other.bufferId) {
+            return false;
+        }
+        if (inPort != other.inPort) {
+            return false;
+        }
+        if (!Arrays.equals(packetData, other.packetData)) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "OFPacketOut [actionFactory=" + actionFactory + ", actions="
+                + actions + ", actionsLength=" + actionsLength + ", bufferId=0x"
+                + Integer.toHexString(bufferId) + ", inPort=" + inPort + ", packetData="
+                + HexString.toHexString(packetData) + "]";
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFPacketQueue.java b/src/main/java/org/openflow/protocol/OFPacketQueue.java
new file mode 100644
index 0000000000000000000000000000000000000000..e8de1af56b950465c23cc140ad4991e0922aa34f
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFPacketQueue.java
@@ -0,0 +1,142 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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 org.openflow.protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents ofp_packet_queue
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFPacketQueue {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected int queueId;
+    protected short length;
+    protected List<OFQueueProp> properties = new ArrayList<OFQueueProp>();
+
+    public OFPacketQueue() {
+        this.queueId = -1;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    public OFPacketQueue(int queueId) {
+        this.queueId = queueId;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the queueId
+     */
+    public long getQueueId() {
+        return queueId;
+    }
+
+    /**
+     * @param queueId the queueId to set
+     */
+    public void setQueueId(int queueId) {
+        this.queueId = queueId;
+    }
+
+    /**
+     * @return the queue's properties
+     */
+    public List<OFQueueProp> getProperties() {
+        return properties;
+    }
+
+    /**
+     * @param properties the properties to set
+     */
+    public void setProperties(List<OFQueueProp> properties) {
+        this.properties = properties;
+
+        this.length = U16.t(MINIMUM_LENGTH);
+        for (OFQueueProp prop : properties) {
+            this.length += prop.getLength();
+        }
+    }
+
+    /**
+     * @return the length
+     */
+    public short getLength() {
+        return length;
+    }
+
+    public void readFrom(ChannelBuffer data) {
+        this.queueId = data.readInt();
+        this.length = data.readShort();
+        data.readShort(); // pad
+
+        int availLength = (this.length - MINIMUM_LENGTH);
+        this.properties.clear();
+
+        while (availLength > 0) {
+            OFQueueProp prop = new OFQueueProp();
+            prop.readFrom(data);
+            properties.add(prop);
+            availLength -= prop.getLength();
+        }
+    }
+
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(queueId);
+        data.writeShort(length);
+        data.writeShort(0); // pad
+
+        for (OFQueueProp prop : properties) {
+            prop.writeTo(data);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 359;
+        int result = super.hashCode();
+        result = prime * result + queueId;
+        result = prime * result + length;
+        result = prime * result + properties.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPacketQueue)) {
+            return false;
+        }
+        OFPacketQueue other = (OFPacketQueue) obj;
+        if (queueId != other.queueId) {
+            return false;
+        }
+        if (! properties.equals(other.properties)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFPhysicalPort.java b/src/main/java/org/openflow/protocol/OFPhysicalPort.java
new file mode 100644
index 0000000000000000000000000000000000000000..88de8f6570cb3d62370d1d2726fb6350fae36547
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFPhysicalPort.java
@@ -0,0 +1,614 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import net.floodlightcontroller.core.web.serializers.ByteArrayMACSerializer;
+import net.floodlightcontroller.core.web.serializers.UShortSerializer;
+import net.floodlightcontroller.util.EnumBitmaps;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.HexString;
+
+/**
+ * Represents ofp_phy_port
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 25, 2010
+ */
+public class OFPhysicalPort {
+    public final static int MINIMUM_LENGTH = 48;
+    public final static int OFP_ETH_ALEN = 6;
+
+    public enum OFPortConfig implements EnumBitmaps.BitmapableEnum {
+        OFPPC_PORT_DOWN    (1 << 0) {
+            @Override
+            public String toString() {
+                return "port-down (0x1)";
+            }
+        },
+        OFPPC_NO_STP       (1 << 1) {
+            @Override
+            public String toString() {
+                return "no-stp (0x2)";
+            }
+        },
+        OFPPC_NO_RECV      (1 << 2) {
+            @Override
+            public String toString() {
+                return "no-recv (0x4)";
+            }
+        },
+        OFPPC_NO_RECV_STP  (1 << 3) {
+            @Override
+            public String toString() {
+                return "no-recv-stp (0x8)";
+            }
+        },
+        OFPPC_NO_FLOOD     (1 << 4) {
+            @Override
+            public String toString() {
+                return "no-flood (0x10)";
+            }
+        },
+        OFPPC_NO_FWD       (1 << 5) {
+            @Override
+            public String toString() {
+                return "no-fwd (0x20)";
+            }
+        },
+        OFPPC_NO_PACKET_IN (1 << 6) {
+            @Override
+            public String toString() {
+                return "no-pkt-in (0x40)";
+            }
+        },
+        OFPPC_BSN_MIRROR_DEST (1 << 31) {
+            @Override
+            public String toString() {
+                return "bsn-mirror-dest (0x80000000)";
+            }
+        };
+
+
+        protected int value;
+
+        private OFPortConfig(int value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value
+         */
+        @Override
+        public int getValue() {
+            return value;
+        }
+    }
+
+    public enum OFPortState {
+        OFPPS_LINK_DOWN   (1 << 0, false) {
+            @Override
+            public String toString() {
+                return "link-down (0x1)";
+            }
+        },
+        OFPPS_STP_LISTEN  (0 << 8, true) {
+            @Override
+            public String toString() {
+                return "listen (0x0)";
+            }
+        },
+        OFPPS_STP_LEARN   (1 << 8, true) {
+            @Override
+            public String toString() {
+                return "learn-no-relay (0x100)";
+            }
+        },
+        OFPPS_STP_FORWARD (2 << 8, true) {
+            @Override
+            public String toString() {
+                return "forward (0x200)";
+            }
+        },
+        OFPPS_STP_BLOCK   (3 << 8, true) {
+            @Override
+            public String toString() {
+                return "block-broadcast (0x300)";
+            }
+        },
+        OFPPS_STP_MASK    (3 << 8, false) { // used for STP but not an STP state
+            @Override
+            public String toString() {
+                return "block-broadcast (0x300)";
+            }
+        };
+
+        protected int value;
+        protected boolean isStpState;
+
+        private OFPortState(int value, boolean isStpState) {
+            this.value = value;
+            this.isStpState = isStpState;
+        }
+
+        /**
+         * Returns true if this constants represents one of the four STP
+         * states
+         * @return
+         */
+        public boolean isStpState() {
+            return isStpState;
+        }
+
+        /**
+         * return the STP state represented by the given integer.
+         * the returned value will have isStpState() == true
+         * @param state
+         * @return
+         */
+        public static OFPortState getStpState(int state) {
+            // this ain't pretty
+            state = state & OFPortState.OFPPS_STP_MASK.getValue();
+            for (OFPortState s: OFPortState.values()) {
+                if (!s.isStpState())
+                    continue;
+                if (state == s.getValue())
+                    return s;
+            }
+            return null; // will never happen
+        }
+
+        public static boolean isPortDown(int state) {
+            if ((state & OFPPS_LINK_DOWN.getValue()) != 0)
+                return true;
+            else
+                return false;
+        }
+
+        /**
+         * @return the value
+         */
+        public int getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * Represents the speed of a port
+     */
+    public enum PortSpeed {
+        /** no speed set */
+        SPEED_NONE(0),
+        SPEED_10MB(10),
+        SPEED_100MB(100),
+        SPEED_1GB(1000),
+        SPEED_10GB(10000);
+
+        private long speedInBps;
+        private PortSpeed(int speedInMbps) {
+            this.speedInBps = speedInMbps * 1000*1000;
+        }
+
+        public long getSpeedBps() {
+            return this.speedInBps;
+        }
+
+        public static PortSpeed max(PortSpeed s1, PortSpeed s2) {
+            return (s1.getSpeedBps() > s2.getSpeedBps()) ? s1 : s2;
+        }
+
+        public static PortSpeed min(PortSpeed s1, PortSpeed s2) {
+            return (s1.getSpeedBps() < s2.getSpeedBps()) ? s1 : s2;
+        }
+    }
+
+    public enum OFPortFeatures implements EnumBitmaps.BitmapableEnum {
+        OFPPF_10MB_HD    (1 << 0, PortSpeed.SPEED_10MB) {
+            @Override
+            public String toString() {
+                return "10mb-hd (0x1)";
+            }
+        },
+        OFPPF_10MB_FD    (1 << 1, PortSpeed.SPEED_10MB) {
+            @Override
+            public String toString() {
+                return "10mb-fd (0x2)";
+            }
+        },
+        OFPPF_100MB_HD   (1 << 2, PortSpeed.SPEED_100MB) {
+            @Override
+            public String toString() {
+                return "100mb-hd (0x4)";
+            }
+        },
+        OFPPF_100MB_FD   (1 << 3, PortSpeed.SPEED_100MB) {
+            @Override
+            public String toString() {
+                return "100mb-fd (0x8)";
+            }
+        },
+        OFPPF_1GB_HD     (1 << 4, PortSpeed.SPEED_1GB) {
+            @Override
+            public String toString() {
+                return "1gb-hd (0x10)";
+            }
+        },
+        OFPPF_1GB_FD     (1 << 5, PortSpeed.SPEED_1GB) {
+            @Override
+            public String toString() {
+                return "1gb-fd (0x20)";
+            }
+        },
+        OFPPF_10GB_FD    (1 << 6, PortSpeed.SPEED_10GB) {
+            @Override
+            public String toString() {
+                return "10gb-fd (0x40)";
+            }
+        },
+        OFPPF_COPPER     (1 << 7, PortSpeed.SPEED_NONE) {
+            @Override
+            public String toString() {
+                return "copper (0x80)";
+            }
+        },
+        OFPPF_FIBER      (1 << 8, PortSpeed.SPEED_NONE) {
+            @Override
+            public String toString() {
+                return "fiber (0x100)";
+            }
+        },
+        OFPPF_AUTONEG    (1 << 9, PortSpeed.SPEED_NONE) {
+            @Override
+            public String toString() {
+                return "autoneg (0x200)";
+            }
+        },
+        OFPPF_PAUSE      (1 << 10, PortSpeed.SPEED_NONE) {
+            @Override
+            public String toString() {
+                return "pause (0x400)";
+            }
+        },
+        OFPPF_PAUSE_ASYM (1 << 11, PortSpeed.SPEED_NONE) {
+            @Override
+            public String toString() {
+                return "pause-asym (0x800)";
+            }
+        };
+
+        protected int value;
+        protected PortSpeed speed;
+
+        private OFPortFeatures(int value, PortSpeed speed) {
+            this.value = value;
+            if (speed == null)
+                throw new NullPointerException();
+            this.speed = speed;
+        }
+
+        /**
+         * @return the bitmap value for this constant
+         */
+        @Override
+        public int getValue() {
+            return value;
+        }
+
+        /**
+         * @return the port speed associated with this constant. If the
+         * constant doesn't represent a port speed it returns SPEED_NONE
+         */
+        public PortSpeed getSpeed() {
+            return speed;
+        }
+    }
+
+    protected short portNumber;
+    protected byte[] hardwareAddress;
+    protected String name;
+    protected int config;
+    protected int state;
+    protected int currentFeatures;
+    protected int advertisedFeatures;
+    protected int supportedFeatures;
+    protected int peerFeatures;
+
+    /**
+     * @return the portNumber
+     */
+    @JsonSerialize(using=UShortSerializer.class)
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the hardwareAddress
+     */
+    @JsonSerialize(using=ByteArrayMACSerializer.class)
+    public byte[] getHardwareAddress() {
+        return hardwareAddress;
+    }
+
+    /**
+     * @param hardwareAddress the hardwareAddress to set
+     */
+    public void setHardwareAddress(byte[] hardwareAddress) {
+        if (hardwareAddress.length != OFP_ETH_ALEN)
+            throw new RuntimeException("Hardware address must have length "
+                    + OFP_ETH_ALEN);
+        this.hardwareAddress = hardwareAddress;
+    }
+
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the config
+     */
+    public int getConfig() {
+        return config;
+    }
+
+    /**
+     * @param config the config to set
+     */
+    public void setConfig(int config) {
+        this.config = config;
+    }
+
+    /**
+     * @return the state
+     */
+    public int getState() {
+        return state;
+    }
+
+    /**
+     * @param state the state to set
+     */
+    public void setState(int state) {
+        this.state = state;
+    }
+
+    /**
+     * @return the currentFeatures
+     */
+    public int getCurrentFeatures() {
+        return currentFeatures;
+    }
+
+    /**
+     * @param currentFeatures the currentFeatures to set
+     */
+    public void setCurrentFeatures(int currentFeatures) {
+        this.currentFeatures = currentFeatures;
+    }
+
+    /**
+     * @return the advertisedFeatures
+     */
+    public int getAdvertisedFeatures() {
+        return advertisedFeatures;
+    }
+
+    /**
+     * @param advertisedFeatures the advertisedFeatures to set
+     */
+    public void setAdvertisedFeatures(int advertisedFeatures) {
+        this.advertisedFeatures = advertisedFeatures;
+    }
+
+    /**
+     * @return the supportedFeatures
+     */
+    public int getSupportedFeatures() {
+        return supportedFeatures;
+    }
+
+    /**
+     * @param supportedFeatures the supportedFeatures to set
+     */
+    public void setSupportedFeatures(int supportedFeatures) {
+        this.supportedFeatures = supportedFeatures;
+    }
+
+    /**
+     * @return the peerFeatures
+     */
+    public int getPeerFeatures() {
+        return peerFeatures;
+    }
+
+    /**
+     * @param peerFeatures the peerFeatures to set
+     */
+    public void setPeerFeatures(int peerFeatures) {
+        this.peerFeatures = peerFeatures;
+    }
+
+    /**
+     * Read this message off the wire from the specified ByteBuffer
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        if (this.hardwareAddress == null)
+            this.hardwareAddress = new byte[OFP_ETH_ALEN];
+        data.readBytes(this.hardwareAddress);
+        byte[] name = new byte[16];
+        data.readBytes(name);
+        // find the first index of 0
+        int index = 0;
+        for (byte b : name) {
+            if (0 == b)
+                break;
+            ++index;
+        }
+        this.name = new String(Arrays.copyOf(name, index),
+                Charset.forName("ascii"));
+        this.config = data.readInt();
+        this.state = data.readInt();
+        this.currentFeatures = data.readInt();
+        this.advertisedFeatures = data.readInt();
+        this.supportedFeatures = data.readInt();
+        this.peerFeatures = data.readInt();
+    }
+
+    /**
+     * Write this message's binary format to the specified ByteBuffer
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeBytes(hardwareAddress);
+        try {
+            byte[] name = this.name.getBytes("ASCII");
+            if (name.length < 16) {
+                data.writeBytes(name);
+                for (int i = name.length; i < 16; ++i) {
+                    data.writeByte((byte) 0);
+                }
+            } else {
+                data.writeBytes(name, 0, 15);
+                data.writeByte((byte) 0);
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        data.writeInt(this.config);
+        data.writeInt(this.state);
+        data.writeInt(this.currentFeatures);
+        data.writeInt(this.advertisedFeatures);
+        data.writeInt(this.supportedFeatures);
+        data.writeInt(this.peerFeatures);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 307;
+        int result = 1;
+        result = prime * result + advertisedFeatures;
+        result = prime * result + config;
+        result = prime * result + currentFeatures;
+        result = prime * result + Arrays.hashCode(hardwareAddress);
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + peerFeatures;
+        result = prime * result + portNumber;
+        result = prime * result + state;
+        result = prime * result + supportedFeatures;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFPhysicalPort)) {
+            return false;
+        }
+        OFPhysicalPort other = (OFPhysicalPort) obj;
+        if (advertisedFeatures != other.advertisedFeatures) {
+            return false;
+        }
+        if (config != other.config) {
+            return false;
+        }
+        if (currentFeatures != other.currentFeatures) {
+            return false;
+        }
+        if (!Arrays.equals(hardwareAddress, other.hardwareAddress)) {
+            return false;
+        }
+        if (name == null) {
+            if (other.name != null) {
+                return false;
+            }
+        } else if (!name.equals(other.name)) {
+            return false;
+        }
+        if (peerFeatures != other.peerFeatures) {
+            return false;
+        }
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        if (state != other.state) {
+            return false;
+        }
+        if (supportedFeatures != other.supportedFeatures) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        String linkState, linkSpeed;
+        if ((state & OFPortState.OFPPS_LINK_DOWN.getValue()) != 0) {
+            linkState = "down";
+        } else {
+            linkState = "up";
+        }
+        if ((currentFeatures & OFPortFeatures.OFPPF_10GB_FD.getValue()) != 0) {
+            linkSpeed = "10G";
+        } else if ((currentFeatures & OFPortFeatures.OFPPF_1GB_FD.getValue()) != 0) {
+            linkSpeed = "1G";
+        } else if ((currentFeatures & OFPortFeatures.OFPPF_1GB_HD.getValue()) != 0) {
+            linkSpeed = "1G(half-duplex)";
+        } else if ((currentFeatures & OFPortFeatures.OFPPF_100MB_FD.getValue()) != 0) {
+            linkSpeed = "100M";
+        } else if ((currentFeatures & OFPortFeatures.OFPPF_100MB_HD.getValue()) != 0) {
+            linkSpeed = "100M(half-duplex)";
+        } else if ((currentFeatures & OFPortFeatures.OFPPF_10MB_FD.getValue()) != 0) {
+            linkSpeed = "10M";
+        } else if ((currentFeatures & OFPortFeatures.OFPPF_10MB_HD.getValue()) != 0) {
+            linkSpeed = "10M(half-duplex)";
+        } else {
+            linkSpeed = "unknown";
+        }
+        return "port " + name + " (" +  portNumber + ")" +
+               ", mac " + HexString.toHexString(hardwareAddress) +
+               ", state " + linkState +
+               ", speed " + linkSpeed;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFPort.java b/src/main/java/org/openflow/protocol/OFPort.java
new file mode 100644
index 0000000000000000000000000000000000000000..93301bcb097486e454ec9c82bfd5768144d2cd77
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFPort.java
@@ -0,0 +1,43 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+public enum OFPort {
+    OFPP_MAX                ((short)0xff00),
+    OFPP_IN_PORT            ((short)0xfff8),
+    OFPP_TABLE              ((short)0xfff9),
+    OFPP_NORMAL             ((short)0xfffa),
+    OFPP_FLOOD              ((short)0xfffb),
+    OFPP_ALL                ((short)0xfffc),
+    OFPP_CONTROLLER         ((short)0xfffd),
+    OFPP_LOCAL              ((short)0xfffe),
+    OFPP_NONE               ((short)0xffff);
+
+    protected short value;
+
+    private OFPort(short value) {
+        this.value = value;
+    }
+
+    /**
+     * @return the value
+     */
+    public short getValue() {
+        return value;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFPortMod.java b/src/main/java/org/openflow/protocol/OFPortMod.java
new file mode 100644
index 0000000000000000000000000000000000000000..876e856700788c8a8d64b4ab37fe8febf87b5da7
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFPortMod.java
@@ -0,0 +1,182 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_port_mod message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFPortMod extends OFMessage {
+    public static int MINIMUM_LENGTH = 32;
+
+    protected short portNumber;
+    protected byte[] hardwareAddress;
+    protected int config;
+    protected int mask;
+    protected int advertise;
+
+    public OFPortMod() {
+        super();
+        this.type = OFType.PORT_MOD;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the hardwareAddress
+     */
+    public byte[] getHardwareAddress() {
+        return hardwareAddress;
+    }
+
+    /**
+     * @param hardwareAddress the hardwareAddress to set
+     */
+    public void setHardwareAddress(byte[] hardwareAddress) {
+        if (hardwareAddress.length != OFPhysicalPort.OFP_ETH_ALEN)
+            throw new RuntimeException("Hardware address must have length "
+                    + OFPhysicalPort.OFP_ETH_ALEN);
+        this.hardwareAddress = hardwareAddress;
+    }
+
+    /**
+     * @return the config
+     */
+    public int getConfig() {
+        return config;
+    }
+
+    /**
+     * @param config the config to set
+     */
+    public void setConfig(int config) {
+        this.config = config;
+    }
+
+    /**
+     * @return the mask
+     */
+    public int getMask() {
+        return mask;
+    }
+
+    /**
+     * @param mask the mask to set
+     */
+    public void setMask(int mask) {
+        this.mask = mask;
+    }
+
+    /**
+     * @return the advertise
+     */
+    public int getAdvertise() {
+        return advertise;
+    }
+
+    /**
+     * @param advertise the advertise to set
+     */
+    public void setAdvertise(int advertise) {
+        this.advertise = advertise;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.portNumber = data.readShort();
+        if (this.hardwareAddress == null)
+            this.hardwareAddress = new byte[OFPhysicalPort.OFP_ETH_ALEN];
+        data.readBytes(this.hardwareAddress);
+        this.config = data.readInt();
+        this.mask = data.readInt();
+        this.advertise = data.readInt();
+        data.readInt(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeBytes(this.hardwareAddress);
+        data.writeInt(this.config);
+        data.writeInt(this.mask);
+        data.writeInt(this.advertise);
+        data.writeInt(0); // pad
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 311;
+        int result = super.hashCode();
+        result = prime * result + advertise;
+        result = prime * result + config;
+        result = prime * result + Arrays.hashCode(hardwareAddress);
+        result = prime * result + mask;
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPortMod)) {
+            return false;
+        }
+        OFPortMod other = (OFPortMod) obj;
+        if (advertise != other.advertise) {
+            return false;
+        }
+        if (config != other.config) {
+            return false;
+        }
+        if (!Arrays.equals(hardwareAddress, other.hardwareAddress)) {
+            return false;
+        }
+        if (mask != other.mask) {
+            return false;
+        }
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFPortStatus.java b/src/main/java/org/openflow/protocol/OFPortStatus.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7a3158ceee2ef7d6cc99086089cbe8e4203531f
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFPortStatus.java
@@ -0,0 +1,144 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_port_status message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFPortStatus extends OFMessage {
+    public static int MINIMUM_LENGTH = 64;
+
+    public enum OFPortReason {
+        OFPPR_ADD((byte)0),
+        OFPPR_DELETE((byte)1),
+        OFPPR_MODIFY((byte)2);
+
+        private byte reason;
+
+        private OFPortReason(byte reason) {
+            this.reason = reason;
+        }
+
+        public byte getReasonCode() {
+            return this.reason;
+        }
+
+        public static OFPortReason fromReasonCode(byte reason) {
+            for (OFPortReason r: OFPortReason.values()) {
+                if (r.getReasonCode() == reason)
+                    return r;
+            }
+            return null;
+        }
+    }
+
+    protected byte reason;
+    protected OFPhysicalPort desc;
+
+    /**
+     * @return the reason
+     */
+    public byte getReason() {
+        return reason;
+    }
+
+    /**
+     * @param reason the reason to set
+     */
+    public void setReason(byte reason) {
+        this.reason = reason;
+    }
+
+    /**
+     * @return the desc
+     */
+    public OFPhysicalPort getDesc() {
+        return desc;
+    }
+
+    /**
+     * @param desc the desc to set
+     */
+    public void setDesc(OFPhysicalPort desc) {
+        this.desc = desc;
+    }
+
+    public OFPortStatus() {
+        super();
+        this.type = OFType.PORT_STATUS;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.reason = data.readByte();
+        data.readerIndex(data.readerIndex() + 7); // skip 7 bytes of padding
+        if (this.desc == null)
+            this.desc = new OFPhysicalPort();
+        this.desc.readFrom(data);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeByte(this.reason);
+        for (int i = 0; i < 7; ++i)
+            data.writeByte((byte) 0);
+        this.desc.writeTo(data);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 313;
+        int result = super.hashCode();
+        result = prime * result + ((desc == null) ? 0 : desc.hashCode());
+        result = prime * result + reason;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPortStatus)) {
+            return false;
+        }
+        OFPortStatus other = (OFPortStatus) obj;
+        if (desc == null) {
+            if (other.desc != null) {
+                return false;
+            }
+        } else if (!desc.equals(other.desc)) {
+            return false;
+        }
+        if (reason != other.reason) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFQueueGetConfigReply.java b/src/main/java/org/openflow/protocol/OFQueueGetConfigReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..62be90d59f4106e8a6581dcf81bc5153cee83ce1
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFQueueGetConfigReply.java
@@ -0,0 +1,125 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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 org.openflow.protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_queue_get_config_request message
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueGetConfigReply extends OFMessage {
+    public static int MINIMUM_LENGTH = 16;
+
+    protected short portNumber;
+    protected List<OFPacketQueue> queues = new ArrayList<OFPacketQueue>();
+
+    public OFQueueGetConfigReply() {
+        super();
+        this.type = OFType.QUEUE_GET_CONFIG_REPLY;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the port's queues
+     */
+    public List<OFPacketQueue> getQueues() {
+        return queues;
+    }
+
+    /**
+     * @param queues the queues to set
+     */
+    public void setQueues(List<OFPacketQueue> queues) {
+        this.queues.clear();
+        this.queues.addAll(queues);
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.portNumber = data.readShort();
+        data.readInt();   // pad
+        data.readShort(); // pad
+
+        int availLength = (this.length - MINIMUM_LENGTH);
+        this.queues.clear();
+
+        while (availLength > 0) {
+            OFPacketQueue queue = new OFPacketQueue();
+            queue.readFrom(data);
+            queues.add(queue);
+            availLength -= queue.getLength();
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeInt(0);   // pad
+        data.writeShort(0); // pad
+
+        for (OFPacketQueue queue : queues) {
+            queue.writeTo(data);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 349;
+        int result = super.hashCode();
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueGetConfigReply)) {
+            return false;
+        }
+        OFQueueGetConfigReply other = (OFQueueGetConfigReply) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFQueueGetConfigRequest.java b/src/main/java/org/openflow/protocol/OFQueueGetConfigRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..cbb4a3734b9bc6510362afa237b6121398d9e4cd
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFQueueGetConfigRequest.java
@@ -0,0 +1,95 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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 org.openflow.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_queue_get_config_request message
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueGetConfigRequest extends OFMessage {
+    public static int MINIMUM_LENGTH = 12;
+
+    protected short portNumber;
+
+    public OFQueueGetConfigRequest(short portNumber) {
+        super();
+        this.type = OFType.QUEUE_GET_CONFIG_REQUEST;
+        this.length = U16.t(MINIMUM_LENGTH);
+        this.portNumber = portNumber;
+    }
+
+    public OFQueueGetConfigRequest() {
+        this((short) 0);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeShort(0); // pad
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 347;
+        int result = super.hashCode();
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueGetConfigRequest)) {
+            return false;
+        }
+        OFQueueGetConfigRequest other = (OFQueueGetConfigRequest) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFQueueProp.java b/src/main/java/org/openflow/protocol/OFQueueProp.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e12224bbbf1a7baf86c4a61eac9c3ab32f72580
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFQueueProp.java
@@ -0,0 +1,175 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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 org.openflow.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+public class OFQueueProp {
+    private int NONE_MINIMUM_LENGTH = 8;
+    private int RATE_MINIMUM_LENGTH = 16;
+
+    public enum OFQueuePropType {
+        OFPQT_NONE       (0),
+        OFPQT_MIN_RATE   (1),
+        OFPQT_MAX_RATE   (2);
+
+        protected int value;
+
+        private OFQueuePropType(int value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value
+         */
+        public int getValue() {
+            return value;
+        }
+
+        public static OFQueuePropType fromShort(short x) {
+            switch (x) {
+                case 0:
+                    return OFPQT_NONE;
+                case 1:
+                    return OFPQT_MIN_RATE;
+                case 2:
+                    return OFPQT_MAX_RATE;
+            }
+            return null;
+        }
+    }
+
+    protected OFQueuePropType type;
+    protected short length;
+    protected short rate = -1; // not valid if type == OFPQT_NONE
+
+    public OFQueueProp() {
+        this.type = OFQueuePropType.OFPQT_NONE;
+        this.length = U16.t(NONE_MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the type
+     */
+    public OFQueuePropType getType() {
+        return type;
+    }
+
+    /**
+     * @param type the type to set
+     */
+    public void setType(OFQueuePropType type) {
+        this.type = type;
+
+        switch (type) {
+            case OFPQT_NONE:
+                this.length = U16.t(NONE_MINIMUM_LENGTH);
+                break;
+            case OFPQT_MIN_RATE:
+                this.length = U16.t(RATE_MINIMUM_LENGTH);
+                break;
+            case OFPQT_MAX_RATE:
+                this.length = U16.t(RATE_MINIMUM_LENGTH);
+                break;
+        }
+    }
+
+    /**
+     * @return the rate
+     */
+    public short getRate() {
+        return rate;
+    }
+
+    /**
+     * @param rate the rate to set
+     */
+    public void setRate(short rate) {
+        this.rate = rate;
+    }
+
+    /**
+     * @return the length
+     */
+    public short getLength() {
+        return length;
+    }
+
+    public void readFrom(ChannelBuffer data) {
+        this.type = OFQueuePropType.fromShort(data.readShort());
+        this.length = data.readShort();
+        data.readInt(); // pad
+
+        if (this.type == OFQueuePropType.OFPQT_MIN_RATE ||
+            this.type == OFQueuePropType.OFPQT_MAX_RATE) {
+            assert(this.length == RATE_MINIMUM_LENGTH);
+
+            this.rate = data.readShort();
+            data.readInt(); // pad
+            data.readShort(); // pad
+        } else {
+            assert(this.length == NONE_MINIMUM_LENGTH);
+        }
+    }
+
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.type.getValue());
+        data.writeShort(this.length);
+        data.writeInt(0); // pad
+
+        if (this.type == OFQueuePropType.OFPQT_MIN_RATE ||
+            this.type == OFQueuePropType.OFPQT_MAX_RATE) {
+            data.writeShort(this.rate);
+            data.writeInt(0); // pad
+            data.writeShort(0); // pad
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 353;
+        int result = super.hashCode();
+        result = prime * result + type.getValue();
+        result = prime * result + rate;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueProp)) {
+            return false;
+        }
+        OFQueueProp other = (OFQueueProp) obj;
+        if (type != other.type) {
+            return false;
+        }
+        if (type == OFQueuePropType.OFPQT_MIN_RATE ||
+            type == OFQueuePropType.OFPQT_MAX_RATE) {
+            if (rate != other.rate) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFSetConfig.java b/src/main/java/org/openflow/protocol/OFSetConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b2356476e5b1b7af304e92d239ab14dd2a2e29b
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFSetConfig.java
@@ -0,0 +1,29 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+/**
+ * Represents an OFPT_SET_CONFIG type message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFSetConfig extends OFSwitchConfig {
+    public OFSetConfig() {
+        super();
+        this.type = OFType.SET_CONFIG;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java b/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5a9c01e0093e29055bb75943909860490347e43
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java
@@ -0,0 +1,180 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.factory.OFStatisticsFactory;
+import org.openflow.protocol.factory.OFStatisticsFactoryAware;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+
+
+/**
+ * Base class for statistics requests/replies
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 27, 2010
+ */
+public abstract class OFStatisticsMessageBase extends OFMessage implements
+        OFStatisticsFactoryAware {
+    public static int MINIMUM_LENGTH = 12;
+
+    protected OFStatisticsFactory statisticsFactory;
+    protected OFStatisticsType statisticType;
+    protected short flags;
+
+    // TODO: this should be List<? extends OFStatistics>, to
+    // allow for type safe assignments of lists of specific message
+    protected List<? extends OFStatistics> statistics;
+
+    /**
+     * @return the statisticType
+     */
+    public OFStatisticsType getStatisticType() {
+        return statisticType;
+    }
+
+    /**
+     * @param statisticType the statisticType to set
+     */
+    public void setStatisticType(OFStatisticsType statisticType) {
+        this.statisticType = statisticType;
+    }
+
+    /**
+     * @return the flags
+     */
+    public short getFlags() {
+        return flags;
+    }
+
+    /**
+     * @param flags the flags to set
+     */
+    public void setFlags(short flags) {
+        this.flags = flags;
+    }
+
+    /**
+     * @return the statistics
+     */
+    public List<? extends OFStatistics> getStatistics() {
+        return statistics;
+    }
+
+    /**
+     * return the first statistics request in the list of statistics, for
+     * statistics messages that expect exactly one message in their body (e.g.,
+     * flow stats request, port statsrequest)
+     *
+     * @return the first and only element in the list of statistics
+     * @throw IllegalArgumentException if the list does not contain exactly one
+     *        element
+     */
+    public OFStatistics getFirstStatistics() {
+        if (statistics == null ) {
+            throw new IllegalArgumentException("Invariant violation: statistics message of type "+statisticType+" is null");
+        }
+        if (statistics.size() != 1) {
+            throw new IllegalArgumentException("Invariant violation: statistics message of type "+statisticType+" contains "+statistics.size() +" statreq/reply messages in its body (should be 1)");
+        }
+
+        return statistics.get(0);
+    }
+
+    /**
+     * @param statistics the statistics to set
+     */
+    public void setStatistics(List<? extends OFStatistics> statistics) {
+        this.statistics = statistics;
+    }
+
+    @Override
+    public void setStatisticsFactory(OFStatisticsFactory statisticsFactory) {
+        this.statisticsFactory = statisticsFactory;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.statisticType = OFStatisticsType.valueOf(data.readShort(), this
+                .getType());
+        this.flags = data.readShort();
+        if (this.statisticsFactory == null)
+            throw new RuntimeException("OFStatisticsFactory not set");
+        this.statistics = statisticsFactory.parseStatistics(this.getType(),
+                this.statisticType, data, super.getLengthU() - MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.statisticType.getTypeValue());
+        data.writeShort(this.flags);
+        if (this.statistics != null) {
+            for (OFStatistics statistic : this.statistics) {
+                statistic.writeTo(data);
+            }
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 317;
+        int result = super.hashCode();
+        result = prime * result + flags;
+        result = prime * result
+                + ((statisticType == null) ? 0 : statisticType.hashCode());
+        result = prime * result
+                + ((statistics == null) ? 0 : statistics.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFStatisticsMessageBase)) {
+            return false;
+        }
+        OFStatisticsMessageBase other = (OFStatisticsMessageBase) obj;
+        if (flags != other.flags) {
+            return false;
+        }
+        if (statisticType == null) {
+            if (other.statisticType != null) {
+                return false;
+            }
+        } else if (!statisticType.equals(other.statisticType)) {
+            return false;
+        }
+        if (statistics == null) {
+            if (other.statistics != null) {
+                return false;
+            }
+        } else if (!statistics.equals(other.statistics)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFStatisticsReply.java b/src/main/java/org/openflow/protocol/OFStatisticsReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..ddc7267425ab98431c350d393253623c894bed4f
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFStatisticsReply.java
@@ -0,0 +1,46 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_stats_reply message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFStatisticsReply extends OFStatisticsMessageBase {
+    public enum OFStatisticsReplyFlags {
+        REPLY_MORE      (1 << 0);
+
+        protected short type;
+
+        OFStatisticsReplyFlags(int type) {
+            this.type = (short) type;
+        }
+
+        public short getTypeValue() {
+            return type;
+        }
+    }
+
+    public OFStatisticsReply() {
+        super();
+        this.type = OFType.STATS_REPLY;
+        this.length = U16.t(OFStatisticsMessageBase.MINIMUM_LENGTH);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFStatisticsRequest.java b/src/main/java/org/openflow/protocol/OFStatisticsRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1d8010e921a5f7918ac3869af387e2b12185016
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFStatisticsRequest.java
@@ -0,0 +1,32 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_stats_request message
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFStatisticsRequest extends OFStatisticsMessageBase {
+    public OFStatisticsRequest() {
+        super();
+        this.type = OFType.STATS_REQUEST;
+        this.length = U16.t(OFStatisticsMessageBase.MINIMUM_LENGTH);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFSwitchConfig.java b/src/main/java/org/openflow/protocol/OFSwitchConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..e04e3fa60fe65a1f85bdc767588e63f45990efc2
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFSwitchConfig.java
@@ -0,0 +1,118 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Base class representing ofp_switch_config based messages
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public abstract class OFSwitchConfig extends OFMessage {
+    public static int MINIMUM_LENGTH = 12;
+
+    public enum OFConfigFlags {
+        OFPC_FRAG_NORMAL,
+        OFPC_FRAG_DROP,
+        OFPC_FRAG_REASM,
+        OFPC_FRAG_MASK
+    }
+
+    protected short flags;
+    protected short missSendLength;
+
+    public OFSwitchConfig() {
+        super();
+        super.setLengthU(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the flags
+     */
+    public short getFlags() {
+        return flags;
+    }
+
+    /**
+     * @param flags the flags to set
+     */
+    public OFSwitchConfig setFlags(short flags) {
+        this.flags = flags;
+        return this;
+    }
+
+    /**
+     * @return the missSendLength
+     */
+    public short getMissSendLength() {
+        return missSendLength;
+    }
+
+    /**
+     * @param missSendLength the missSendLength to set
+     */
+    public OFSwitchConfig setMissSendLength(short missSendLength) {
+        this.missSendLength = missSendLength;
+        return this;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.flags = data.readShort();
+        this.missSendLength = data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.flags);
+        data.writeShort(this.missSendLength);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 331;
+        int result = super.hashCode();
+        result = prime * result + flags;
+        result = prime * result + missSendLength;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFSwitchConfig)) {
+            return false;
+        }
+        OFSwitchConfig other = (OFSwitchConfig) obj;
+        if (flags != other.flags) {
+            return false;
+        }
+        if (missSendLength != other.missSendLength) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFType.java b/src/main/java/org/openflow/protocol/OFType.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1c81e2884b0f850efe420aa54c1fe810869442e
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFType.java
@@ -0,0 +1,249 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * List of OpenFlow types and mappings to wire protocol value and derived
+ * classes
+ *
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public enum OFType {
+    HELLO               (0, OFHello.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFHello();
+                            }}),
+    ERROR               (1, OFError.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFError();
+                            }}),
+    ECHO_REQUEST        (2, OFEchoRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFEchoRequest();
+                            }}),
+    ECHO_REPLY          (3, OFEchoReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFEchoReply();
+                            }}),
+    VENDOR              (4, OFVendor.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFVendor();
+                            }}),
+    FEATURES_REQUEST    (5, OFFeaturesRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFFeaturesRequest();
+                            }}),
+    FEATURES_REPLY      (6, OFFeaturesReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFFeaturesReply();
+                            }}),
+    GET_CONFIG_REQUEST  (7, OFGetConfigRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFGetConfigRequest();
+                            }}),
+    GET_CONFIG_REPLY    (8, OFGetConfigReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFGetConfigReply();
+                            }}),
+    SET_CONFIG          (9, OFSetConfig.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFSetConfig();
+                            }}),
+    PACKET_IN           (10, OFPacketIn.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFPacketIn();
+                            }}),
+    FLOW_REMOVED        (11, OFFlowRemoved.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFFlowRemoved();
+                            }}),
+    PORT_STATUS         (12, OFPortStatus.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFPortStatus();
+                            }}),
+    PACKET_OUT          (13, OFPacketOut.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFPacketOut();
+                            }}),
+    FLOW_MOD            (14, OFFlowMod.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFFlowMod();
+                            }}),
+    PORT_MOD            (15, OFPortMod.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFPortMod();
+                            }}),
+    STATS_REQUEST       (16, OFStatisticsRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFStatisticsRequest();
+                            }}),
+    STATS_REPLY         (17, OFStatisticsReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFStatisticsReply();
+                            }}),
+    BARRIER_REQUEST     (18, OFBarrierRequest.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFBarrierRequest();
+                            }}),
+    BARRIER_REPLY       (19, OFBarrierReply.class, new Instantiable<OFMessage>() {
+                            @Override
+                            public OFMessage instantiate() {
+                                return new OFBarrierReply();
+                            }}),
+    QUEUE_GET_CONFIG_REQUEST    (20, OFQueueGetConfigRequest.class, new Instantiable<OFMessage>() {
+                                    @Override
+                                    public OFMessage instantiate() {
+                                        return new OFQueueGetConfigRequest();
+                                    }}),
+    QUEUE_GET_CONFIG_REPLY      (21, OFQueueGetConfigReply.class, new Instantiable<OFMessage>() {
+                                    @Override
+                                    public OFMessage instantiate() {
+                                        return new OFQueueGetConfigReply();
+                                    }});
+
+    static OFType[] mapping;
+
+    protected Class<? extends OFMessage> clazz;
+    protected Constructor<? extends OFMessage> constructor;
+    protected Instantiable<OFMessage> instantiable;
+    protected byte type;
+
+    /**
+     * Store some information about the OpenFlow type, including wire protocol
+     * type number, length, and derived class
+     *
+     * @param type Wire protocol number associated with this OFType
+     * @param clazz The Java class corresponding to this type of OpenFlow
+     *              message
+     * @param instantiator An Instantiator<OFMessage> implementation that creates an
+     *          instance of the specified OFMessage
+     */
+    OFType(int type, Class<? extends OFMessage> clazz, Instantiable<OFMessage> instantiator) {
+        this.type = (byte) type;
+        this.clazz = clazz;
+        this.instantiable = instantiator;
+        try {
+            this.constructor = clazz.getConstructor(new Class[]{});
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Failure getting constructor for class: " + clazz, e);
+        }
+        OFType.addMapping(this.type, this);
+    }
+
+    /**
+     * Adds a mapping from type value to OFType enum
+     *
+     * @param i OpenFlow wire protocol type
+     * @param t type
+     */
+    static public void addMapping(byte i, OFType t) {
+        if (mapping == null)
+            mapping = new OFType[32];
+        OFType.mapping[i] = t;
+    }
+
+    /**
+     * Remove a mapping from type value to OFType enum
+     *
+     * @param i OpenFlow wire protocol type
+     */
+    static public void removeMapping(byte i) {
+        OFType.mapping[i] = null;
+    }
+
+    /**
+     * Given a wire protocol OpenFlow type number, return the OFType associated
+     * with it
+     *
+     * @param i wire protocol number
+     * @return OFType enum type
+     */
+
+    static public OFType valueOf(Byte i) {
+        return OFType.mapping[i];
+    }
+
+    /**
+     * @return Returns the wire protocol value corresponding to this OFType
+     */
+    public byte getTypeValue() {
+        return this.type;
+    }
+
+    /**
+     * @return return the OFMessage subclass corresponding to this OFType
+     */
+    public Class<? extends OFMessage> toClass() {
+        return clazz;
+    }
+
+    /**
+     * Returns the no-argument Constructor of the implementation class for
+     * this OFType
+     * @return the constructor
+     */
+    public Constructor<? extends OFMessage> getConstructor() {
+        return constructor;
+    }
+
+    /**
+     * Returns a new instance of the OFMessage represented by this OFType
+     * @return the new object
+     */
+    public OFMessage newInstance() {
+        return instantiable.instantiate();
+    }
+
+    /**
+     * @return the instantiable
+     */
+    public Instantiable<OFMessage> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * @param instantiable the instantiable to set
+     */
+    public void setInstantiable(Instantiable<OFMessage> instantiable) {
+        this.instantiable = instantiable;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFVendor.java b/src/main/java/org/openflow/protocol/OFVendor.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ecb862becf1a2ba52d4c0ddabeb8474a5c58ef5
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFVendor.java
@@ -0,0 +1,131 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+import org.openflow.protocol.factory.OFVendorDataFactory;
+import org.openflow.protocol.factory.OFVendorDataFactoryAware;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Represents ofp_vendor_header
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFVendor extends OFMessage implements OFVendorDataFactoryAware {
+    public static int MINIMUM_LENGTH = 12;
+
+    protected int vendor;
+    protected OFVendorData vendorData;
+    protected OFVendorDataFactory vendorDataFactory;
+
+    public OFVendor() {
+        super();
+        this.type = OFType.VENDOR;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the vendor
+     */
+    public int getVendor() {
+        return vendor;
+    }
+
+    /**
+     * @param vendor the vendor to set
+     */
+    public void setVendor(int vendor) {
+        this.vendor = vendor;
+    }
+
+    /**
+     * @return the data
+     */
+    public OFVendorData getVendorData() {
+        return vendorData;
+    }
+
+    /**
+     * @param data the data to set
+     */
+    public void setVendorData(OFVendorData vendorData) {
+        this.vendorData = vendorData;
+    }
+
+    @Override
+    public void setVendorDataFactory(OFVendorDataFactory vendorDataFactory) {
+        this.vendorDataFactory = vendorDataFactory;
+    }
+      
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.vendor = data.readInt();
+        if (vendorDataFactory == null)
+            throw new RuntimeException("OFVendorDataFactory not set");
+            
+        this.vendorData = vendorDataFactory.parseVendorData(vendor,
+                data, super.getLengthU() - MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(this.vendor);
+        if (vendorData != null)
+            vendorData.writeTo(data);
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 337;
+        int result = super.hashCode();
+        result = prime * result + vendor;
+        if (vendorData != null)
+            result = prime * result + vendorData.hashCode();
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        OFVendor other = (OFVendor) obj;
+        if (vendor != other.vendor)
+            return false;
+        if (vendorData == null) {
+            if (other.vendorData != null) {
+                return false;
+            }
+        } else if (!vendorData.equals(other.vendorData)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/Wildcards.java b/src/main/java/org/openflow/protocol/Wildcards.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b0ea07b5146e45c8ab69102487437ee7ff24820
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/Wildcards.java
@@ -0,0 +1,603 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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 org.openflow.protocol;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.common.base.Joiner;
+
+/**
+ * a more user friendly representation of the wildcards bits in an OpenFlow
+ * match. The Wildcards object is
+ * <ul>
+ * <li>immutable (i.e., threadsafe)</li>
+ * <li>instance managed (don't instantiate it yourself), instead call "of"</li>
+ * <ul>
+ * <p>
+ * You can construct a Wildcard object from either its integer representation
+ * </p>
+ * <code>
+ *    Wildcard.of(0x3820e0);
+ *  </code>
+ * <p>
+ * Or start with either an empty or full wildcard, and select/unselect foo.
+ * </p>
+ * <code>
+ *  Wildcard w = Wildcards.NONE
+ *                .set(Flag.DL_SRC, Flag. DL_DST, Flag.DL_VLAN_PCP)
+ *                .setNwDstMask(8)
+ *                .setNwSrcMask(8);
+ *  </code>
+ * <p>
+ * <b>Remember:</b> Wildcards objects are immutable. set... operations have
+ * <b>NO EFFECT</b> on the current wildcard object. You HAVE to use the returned
+ * changed object.
+ * </p>
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class Wildcards {
+
+    public final static Wildcards FULL = new Wildcards(OFMatch.OFPFW_ALL_SANITIZED);
+    private static final int FULL_INT = FULL.getInt();
+
+    public final static Wildcards EXACT = new Wildcards(0);
+
+    // floodlight common case: matches on inport + l2
+    public final static int INT_INPORT_L2_MATCH = 0x3820e0;
+    public final static Wildcards INPORT_L2_MATCH = new Wildcards(
+            INT_INPORT_L2_MATCH);
+
+    /**
+     * enum type for the binary flags that can be set in the wildcards field of
+     * an OFMatch. Replaces the unwieldy c-ish int constants in OFMatch.
+     */
+    public static enum Flag {
+        IN_PORT(OFMatch.OFPFW_IN_PORT),  /* Switch input port. */
+        DL_VLAN(OFMatch.OFPFW_DL_VLAN), /* VLAN id. */
+        DL_SRC(OFMatch.OFPFW_DL_SRC), /* Ethernet source address. */
+        DL_DST(OFMatch.OFPFW_DL_DST), /* Ethernet destination addr */
+        DL_TYPE(OFMatch.OFPFW_DL_TYPE), /* Ethernet frame type. */
+        NW_PROTO(OFMatch.OFPFW_NW_PROTO), /* IP protocol. */
+        TP_SRC(OFMatch.OFPFW_TP_SRC), /* TCP/UDP source port. */
+        TP_DST(OFMatch.OFPFW_TP_DST), /* TCP/UDP destination port. */
+        DL_VLAN_PCP(OFMatch.OFPFW_DL_VLAN_PCP), /* VLAN priority. */
+        NW_SRC(-1) { /*
+                      * virtual NW_SRC flag => translates to the strange 6 bits
+                      * in the header
+                      */
+            @Override
+            boolean isBolean() {
+                return false;
+            }
+
+            @Override
+            int getInt(int flags) {
+                return ((flags & OFMatch.OFPFW_NW_SRC_MASK) >> OFMatch.OFPFW_NW_SRC_SHIFT);
+            }
+
+            @Override
+            int setInt(int flags, int srcMask) {
+                return (flags & ~OFMatch.OFPFW_NW_SRC_MASK) | (srcMask << OFMatch.OFPFW_NW_SRC_SHIFT);
+            }
+
+            @Override
+            int wildcard(int flags) {
+                return flags & ~OFMatch.OFPFW_NW_SRC_MASK;
+            }
+
+            @Override
+            int matchOn(int flags) {
+                return flags | OFMatch.OFPFW_NW_SRC_ALL;
+            }
+
+            @Override
+            boolean isPartiallyOn(int flags) {
+                int intValue = getInt(flags);
+                return intValue > 0 && intValue < 32;
+            }
+
+            @Override
+            boolean isFullyOn(int flags) {
+                return getInt(flags) >= 32;
+            }
+
+        },
+        NW_DST(-1) { /*
+                      * virtual NW_SRC flag => translates to the strange 6 bits
+                      * in the header
+                      */
+            @Override
+            boolean isBolean() {
+                return false;
+            }
+
+            @Override
+            int getInt(int flags) {
+                return ((flags & OFMatch.OFPFW_NW_DST_MASK) >> OFMatch.OFPFW_NW_DST_SHIFT);
+            }
+
+            @Override
+            int setInt(int flags, int srcMask) {
+                return (flags & ~OFMatch.OFPFW_NW_DST_MASK) | (srcMask << OFMatch.OFPFW_NW_DST_SHIFT);
+            }
+
+            @Override
+            int wildcard(int flags) {
+                return flags & ~OFMatch.OFPFW_NW_DST_MASK;
+            }
+
+            @Override
+            int matchOn(int flags) {
+                return flags | OFMatch.OFPFW_NW_DST_ALL;
+            }
+
+            @Override
+            boolean isFullyOn(int flags) {
+                return getInt(flags) >= 32;
+            }
+        },
+        NW_TOS(OFMatch.OFPFW_NW_TOS); /* IP ToS (DSCP field, 6 bits). */
+
+        final int bitPosition;
+
+        Flag(int bitPosition) {
+            this.bitPosition = bitPosition;
+        }
+
+        /**
+         * @return a modified OF-1.0 flags field with this flag cleared (match
+         *         on this field)
+         */
+        int matchOn(int flags) {
+            return flags & ~this.bitPosition;
+        }
+
+        /**
+         * @return a modified OF-1.0 flags field with this flag set (wildcard
+         *         this field)
+         */
+        int wildcard(int flags) {
+            return flags | this.bitPosition;
+        }
+
+        /**
+         * @return true iff this is a true boolean flag that can either be off
+         *         or on.True in OF-1.0 for all fields except NW_SRC and NW_DST
+         */
+        boolean isBolean() {
+            return false;
+        }
+
+        /**
+         * @return true iff this wildcard field is currently 'partially on'.
+         *         Always false for true Boolean Flags. Can be true in OF-1.0
+         *         for NW_SRC, NW_DST.
+         */
+        boolean isPartiallyOn(int flags) {
+            return false;
+        }
+
+        /**
+         * @return true iff this wildcard field currently fully on (fully
+         *         wildcarded). Equivalent to the boolean flag being set in the
+         *         bitmask for bit flags, and to the wildcarded bit length set
+         *         to >=32 for NW_SRC and NW_DST
+         * @param flags
+         * @return
+         */
+        boolean isFullyOn(int flags) {
+            return (flags & this.bitPosition) != 0;
+        }
+
+        /**
+         * set the integer representation of this flag. only for NW_SRC and
+         * NW_DST
+         */
+        int setInt(int flags, int srcMask) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * set the integer representation of this flag. only for NW_SRC and
+         * NW_DST
+         */
+        int getInt(int flags) {
+            throw new UnsupportedOperationException();
+        }
+
+
+    }
+
+    private final int flags;
+
+    /** private constructor. use Wildcard.of() instead */
+    private Wildcards(int flags) {
+        this.flags = flags;
+    }
+
+    /**
+     * return a wildcard object matching the given int flags. May reuse / cache
+     * frequently used wildcard instances. Don't rely on it though (use equals
+     * not ==).
+     *
+     * @param flags
+     * @return
+     */
+    public static Wildcards of(int paramFlags) {
+        int flags = sanitizeInt(paramFlags);
+        switch(flags) {
+            case 0x0000:
+                return EXACT;
+            case OFMatch.OFPFW_ALL_SANITIZED:
+                return FULL;
+            case INT_INPORT_L2_MATCH:
+                return INPORT_L2_MATCH;
+            default:
+                return new Wildcards(flags);
+        }
+    }
+
+    /** convience method return a wildcard for exactly one set flag */
+    public static Wildcards of(Wildcards.Flag setFlag) {
+        return Wildcards.of(setFlag.wildcard(0));
+    }
+
+    /** convience method return a wildcard for exactly two set flags */
+    public static Wildcards of(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
+        return Wildcards.of(setFlag.wildcard(setFlag2.wildcard(0)));
+    }
+
+    /** convience method return a wildcard for an arbitrary number of set flags */
+    public static Wildcards of(Wildcards.Flag... setFlags) {
+        int flags = 0;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.wildcard(0);
+        return Wildcards.of(flags);
+    }
+
+    /** convience method return a wildcards for ofmatches that match on one flag */
+    public static Wildcards ofMatches(Wildcards.Flag setFlag) {
+        return Wildcards.of(setFlag.matchOn(FULL_INT));
+    }
+
+    /**
+     * convience method return a wildcard for for an ofmatch that match on two
+     * flags
+     */
+    public static Wildcards ofMatches(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
+        return Wildcards.of(setFlag.matchOn(setFlag2.matchOn(FULL_INT)));
+    }
+
+    /**
+     * convience method return a wildcard for an ofmatch that amtch on an
+     * arbitrary number of set flags
+     */
+    public static Wildcards ofMatches(Wildcards.Flag... setFlags) {
+        int flags = FULL_INT;
+        for (Wildcards.Flag flag : setFlags)
+           flags = flag.matchOn(flags);
+        return Wildcards.of(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags set
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag flag) {
+        int flags = flag.wildcard(this.flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags set
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag flag, Wildcards.Flag flag2) {
+        int flags = flag.wildcard(flag2.wildcard(this.flags));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags wildcarded
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag... setFlags) {
+        int flags = this.flags;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.wildcard(flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flag
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag flag) {
+        int flags = flag.matchOn(this.flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flags
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag flag, Wildcards.Flag flag2) {
+        int flags = flag.matchOn(flag2.matchOn(this.flags));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flags
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag... setFlags) {
+        int flags = this.flags;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.matchOn(flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return the nw src mask in normal CIDR style, e.g., 8 means x.x.x.x/8
+     * means 8 bits wildcarded
+     */
+    public int getNwSrcMask() {
+        return Math.max(0, 32 - Flag.NW_SRC.getInt(flags));
+    }
+
+    /**
+     * return the nw dst mask in normal CIDR style, e.g., 8 means x.x.x.x/8
+     * means 8 bits wildcarded
+     */
+    public int getNwDstMask() {
+        return Math.max(0, 32 - Flag.NW_DST.getInt(flags));
+    }
+
+    /**
+     * return a Wildcard object that has the given nwSrcCidrMask set.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     *
+     * @param srcCidrMask
+     *            source mask to set in <b>normal CIDR notation</b>, i.e., 8
+     *            means x.x.x.x/8
+     * @return a modified object
+     */
+    public Wildcards withNwSrcMask(int srcCidrMask) {
+        int flags = Flag.NW_SRC.setInt(this.flags, Math.max(0, 32 - srcCidrMask));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcard object that has the given nwDstCidrMask set.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     *
+     * @param dstCidrMask
+     *            dest mask to set in <b>normal CIDR notation</b>, i.e., 8 means
+     *            x.x.x.x/8
+     * @return a modified object
+     */
+    public Wildcards withNwDstMask(int dstCidrMask) {
+        int flags = Flag.NW_DST.setInt(this.flags, Math.max(0, 32 - dstCidrMask));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcard object that is inverted to this wildcard object.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     * @return a modified object
+     */
+    public Wildcards inverted() {
+        return Wildcards.of(flags ^ OFMatch.OFPFW_ALL_SANITIZED);
+    }
+
+    public boolean isWildcarded(Flag flag) {
+        return flag.isFullyOn(flags);
+    }
+
+    /**
+     * return all wildcard flags that are fully wildcarded as an EnumSet. Do not
+     * modify. Note: some flags (like NW_SRC and NW_DST) that are partially
+     * wildcarded are not returned in this set.
+     *
+     * @return the EnumSet of wildcards
+     */
+    public EnumSet<Wildcards.Flag> getWildcardedFlags() {
+        EnumSet<Wildcards.Flag> res = EnumSet.noneOf(Wildcards.Flag.class);
+        for (Wildcards.Flag flag : Flag.values()) {
+            if (flag.isFullyOn(flags)) {
+                res.add(flag);
+            }
+        }
+        return res;
+    }
+
+    /** return the OpenFlow 'wire' integer representation of these wildcards */
+    public int getInt() {
+        return flags;
+    }
+
+    /**
+     * return the OpenFlow 'wire' integer representation of these wildcards.
+     * Sanitize nw_src and nw_dst to be max. 32 (values > 32 are technically
+     * possible, but don't make semantic sense)
+     */
+    public static int sanitizeInt(int flags) {
+        if (((flags & OFMatch.OFPFW_NW_SRC_MASK) >> OFMatch.OFPFW_NW_SRC_SHIFT) > 32) {
+            flags = (flags & ~OFMatch.OFPFW_NW_SRC_MASK) | OFMatch.OFPFW_NW_SRC_ALL;
+        }
+        if (((flags & OFMatch.OFPFW_NW_DST_MASK) >> OFMatch.OFPFW_NW_DST_SHIFT) > 32) {
+            flags = (flags & ~OFMatch.OFPFW_NW_DST_MASK) | OFMatch.OFPFW_NW_DST_ALL;
+        }
+        return flags;
+    }
+
+    /**
+     * is this a wildcard set that has all flags set + and full (/0) nw_src and
+     * nw_dst wildcarding ?
+     */
+    public boolean isFull() {
+        return flags == OFMatch.OFPFW_ALL || flags == OFMatch.OFPFW_ALL_SANITIZED;
+    }
+
+    /** is this a wildcard of an exact match */
+    public boolean isExact() {
+        return flags == 0;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + flags;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Wildcards other = (Wildcards) obj;
+        if (flags != other.flags)
+            return false;
+        return true;
+    }
+
+    private final static Joiner pipeJoiner = Joiner.on("|");
+
+    @Override
+    public String toString() {
+        List<String> res = new ArrayList<String>();
+        for (Wildcards.Flag flag : Flag.values()) {
+            if (flag.isFullyOn(flags)) {
+                res.add(flag.name().toLowerCase());
+            }
+        }
+
+        if (Flag.NW_SRC.isPartiallyOn(flags)) {
+            res.add("nw_src(/" + getNwSrcMask() + ")");
+        }
+
+        if (Flag.NW_DST.isPartiallyOn(flags)) {
+            res.add("nw_dst(/" + getNwDstMask() + ")");
+        }
+
+        return pipeJoiner.join(res);
+    }
+
+    private final static Joiner commaJoiner = Joiner.on(", ");
+
+    /** a Java expression that constructs 'this' wildcards set */
+    public String toJava() {
+        if(isFull()) {
+            return "Wildcards.FULL";
+        } else  if (isExact()){
+            return "Wildcards.EXACT";
+        }
+
+        StringBuilder b = new StringBuilder();
+
+        EnumSet<Flag> myFlags = getWildcardedFlags();
+        if (myFlags.size() < 3) {
+            // default to start with empty
+            b.append("Wildcards.of("
+                     + commaJoiner.join(prefix("Flag.", myFlags.iterator())) + ")");
+        } else {
+            // too many - start with full
+
+            EnumSet<Flag> invFlags = inverted().getWildcardedFlags();
+            b.append("Wildcards.ofMatches("
+                     + commaJoiner.join(prefix("Flag.", invFlags.iterator())) + ")");
+        }
+        if (Flag.NW_SRC.isPartiallyOn(flags)) {
+            b.append(".setNwSrcMask(" + getNwSrcMask() + ")");
+        }
+        if (Flag.NW_DST.isPartiallyOn(flags)) {
+            b.append(".setNwDstMask(" + getNwDstMask() + ")");
+        }
+        return b.toString();
+    }
+
+    private Iterator<String> prefix(final String prefix, final Iterator<?> i) {
+        return new Iterator<String>() {
+
+            @Override
+            public boolean hasNext() {
+                return i.hasNext();
+            }
+
+            @Override
+            public String next() {
+                Object next = i.next();
+                return next == null ? null : prefix + next.toString();
+            }
+
+            @Override
+            public void remove() {
+                i.remove();
+            }
+        };
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/action/OFAction.java b/src/main/java/org/openflow/protocol/action/OFAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..57b5dc1efe690532e373d7663cfd6bcb4b5dcff9
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFAction.java
@@ -0,0 +1,173 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * The base class for all OpenFlow Actions.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFAction implements Cloneable {
+    /**
+     * Note the true minimum length for this header is 8 including a pad to 64
+     * bit alignment, however as this base class is used for demuxing an
+     * incoming Action, it is only necessary to read the first 4 bytes.  All
+     * Actions extending this class are responsible for reading/writing the
+     * first 8 bytes, including the pad if necessary.
+     */
+    public static int MINIMUM_LENGTH = 4;
+    public static int OFFSET_LENGTH = 2;
+    public static int OFFSET_TYPE = 0;
+
+    protected OFActionType type;
+    protected short length;
+
+    /**
+     * Get the length of this message
+     *
+     * @return
+     */
+    public short getLength() {
+        return length;
+    }
+
+    /**
+     * Get the length of this message, unsigned
+     *
+     * @return
+     */
+    public int getLengthU() {
+        return U16.f(length);
+    }
+
+    /**
+     * Set the length of this message
+     *
+     * @param length
+     */
+    public OFAction setLength(short length) {
+        this.length = length;
+        return this;
+    }
+
+    /**
+     * Get the type of this message
+     *
+     * @return OFActionType enum
+     */
+    public OFActionType getType() {
+        return this.type;
+    }
+
+    /**
+     * Set the type of this message
+     *
+     * @param type
+     */
+    public void setType(OFActionType type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns a summary of the message
+     * @return "ofmsg=v=$version;t=$type:l=$len:xid=$xid"
+     */
+    public String toString() {
+        return "ofaction" +
+            ";t=" + this.getType() +
+            ";l=" + this.getLength();
+    }
+    
+    /**
+     * Given the output from toString(), 
+     * create a new OFAction
+     * @param val
+     * @return
+     */
+    public static OFAction fromString(String val) {
+        String tokens[] = val.split(";");
+        if (!tokens[0].equals("ofaction"))
+            throw new IllegalArgumentException("expected 'ofaction' but got '" + 
+                    tokens[0] + "'");
+        String type_tokens[] = tokens[1].split("="); 
+        String len_tokens[] = tokens[2].split("=");
+        OFAction action = new OFAction();
+        action.setLength(Short.valueOf(len_tokens[1]));
+        action.setType(OFActionType.valueOf(type_tokens[1]));
+        return action;
+    }
+
+    public void readFrom(ChannelBuffer data) {
+        this.type = OFActionType.valueOf(data.readShort());
+        this.length = data.readShort();
+        // Note missing PAD, see MINIMUM_LENGTH comment for details
+    }
+
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(type.getTypeValue());
+        data.writeShort(length);
+        // Note missing PAD, see MINIMUM_LENGTH comment for details
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 347;
+        int result = 1;
+        result = prime * result + length;
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFAction)) {
+            return false;
+        }
+        OFAction other = (OFAction) obj;
+        if (length != other.length) {
+            return false;
+        }
+        if (type == null) {
+            if (other.type != null) {
+                return false;
+            }
+        } else if (!type.equals(other.type)) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#clone()
+     */
+    @Override
+    public OFAction clone() throws CloneNotSupportedException {
+        return (OFAction) super.clone();
+    }
+    
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionDataLayer.java b/src/main/java/org/openflow/protocol/action/OFActionDataLayer.java
new file mode 100644
index 0000000000000000000000000000000000000000..644dc5f2fb53d020f8d8c002d83e0df6e017b8bd
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionDataLayer.java
@@ -0,0 +1,109 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+import java.util.Arrays;
+
+import net.floodlightcontroller.core.web.serializers.ByteArrayMACSerializer;
+import net.floodlightcontroller.util.MACAddress;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFPhysicalPort;
+
+/**
+ * Represents an ofp_action_dl_addr
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public abstract class OFActionDataLayer extends OFAction {
+    public static int MINIMUM_LENGTH = 16;
+
+    protected byte[] dataLayerAddress;
+
+    /**
+     * @return the dataLayerAddress
+     */
+    @JsonSerialize(using=ByteArrayMACSerializer.class)
+    public byte[] getDataLayerAddress() {
+        return dataLayerAddress;
+    }
+
+    /**
+     * @param dataLayerAddress the dataLayerAddress to set
+     */
+    public void setDataLayerAddress(byte[] dataLayerAddress) {
+        this.dataLayerAddress = dataLayerAddress;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        if (this.dataLayerAddress == null)
+            this.dataLayerAddress = new byte[OFPhysicalPort.OFP_ETH_ALEN];
+        data.readBytes(this.dataLayerAddress);
+        data.readInt();
+        data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeBytes(this.dataLayerAddress);
+        data.writeInt(0);
+        data.writeShort((short) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 347;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(dataLayerAddress);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionDataLayer)) {
+            return false;
+        }
+        OFActionDataLayer other = (OFActionDataLayer) obj;
+        if (!Arrays.equals(dataLayerAddress, other.dataLayerAddress)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(type);
+        builder.append("[");
+        builder.append(MACAddress.valueOf(dataLayerAddress).toString());
+        builder.append("]");
+        return builder.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/action/OFActionDataLayerDestination.java b/src/main/java/org/openflow/protocol/action/OFActionDataLayerDestination.java
new file mode 100644
index 0000000000000000000000000000000000000000..48b8d0f84c4f0a7247d6949d8623cca45181692b
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionDataLayerDestination.java
@@ -0,0 +1,35 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionDataLayerDestination extends OFActionDataLayer {
+    public OFActionDataLayerDestination() {
+        super();
+        super.setType(OFActionType.SET_DL_DST);
+        super.setLength((short) OFActionDataLayer.MINIMUM_LENGTH);
+    }
+    
+    public OFActionDataLayerDestination(byte[] address) {
+        this();
+        this.dataLayerAddress = address;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionDataLayerSource.java b/src/main/java/org/openflow/protocol/action/OFActionDataLayerSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..e04561ceefdfb052386b8cf0040b90f84ec2a2ef
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionDataLayerSource.java
@@ -0,0 +1,35 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionDataLayerSource extends OFActionDataLayer {
+    public OFActionDataLayerSource() {
+        super();
+        super.setType(OFActionType.SET_DL_SRC);
+        super.setLength((short) OFActionDataLayer.MINIMUM_LENGTH);
+    }
+    
+    public OFActionDataLayerSource(byte[] address) {
+        this();
+        this.dataLayerAddress = address;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionEnqueue.java b/src/main/java/org/openflow/protocol/action/OFActionEnqueue.java
new file mode 100644
index 0000000000000000000000000000000000000000..537716612ab86bd06e513dfd5f7217fd802ad60e
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionEnqueue.java
@@ -0,0 +1,136 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_enqueue
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionEnqueue extends OFAction {
+    public static int MINIMUM_LENGTH = 16;
+
+    protected short port;
+    protected int queueId;
+
+    public OFActionEnqueue() {
+        super.setType(OFActionType.OPAQUE_ENQUEUE);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+    
+    public OFActionEnqueue(short port, int queueId) {
+        this();
+        this.port = port;
+        this.queueId = queueId;
+    }
+
+    /**
+     * Get the output port
+     * @return
+     */
+    public short getPort() {
+        return this.port;
+    }
+
+    /**
+     * Set the output port
+     * @param port
+     */
+    public void setPort(short port) {
+        this.port = port;
+    }
+
+    /**
+     * @return the queueId
+     */
+    public int getQueueId() {
+        return queueId;
+    }
+
+    /**
+     * @param queueId the queueId to set
+     */
+    public void setQueueId(int queueId) {
+        this.queueId = queueId;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.port = data.readShort();
+        data.readShort();
+        data.readInt();
+        this.queueId = data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.port);
+        data.writeShort((short) 0);
+        data.writeInt(0);
+        data.writeInt(this.queueId);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 349;
+        int result = super.hashCode();
+        result = prime * result + port;
+        result = prime * result + queueId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionEnqueue)) {
+            return false;
+        }
+        OFActionEnqueue other = (OFActionEnqueue) obj;
+        if (port != other.port) {
+            return false;
+        }
+        if (queueId != other.queueId) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(type);
+        builder.append("[");
+        builder.append("Port: ");
+        builder.append(port);
+        builder.append(", Queue Id: ");
+        builder.append(queueId);
+        builder.append("]");
+        return builder.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerAddress.java b/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerAddress.java
new file mode 100644
index 0000000000000000000000000000000000000000..67bc5a82203fe5d821aabb19a2d352b6df0eabc6
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerAddress.java
@@ -0,0 +1,98 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import net.floodlightcontroller.packet.IPv4;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_nw_addr
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public abstract class OFActionNetworkLayerAddress extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected int networkAddress;
+
+    /**
+     * @return the networkAddress
+     */
+    public int getNetworkAddress() {
+        return networkAddress;
+    }
+
+    /**
+     * @param networkAddress the networkAddress to set
+     */
+    public void setNetworkAddress(int networkAddress) {
+        this.networkAddress = networkAddress;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.networkAddress = data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(this.networkAddress);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 353;
+        int result = super.hashCode();
+        result = prime * result + networkAddress;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionNetworkLayerAddress)) {
+            return false;
+        }
+        OFActionNetworkLayerAddress other = (OFActionNetworkLayerAddress) obj;
+        if (networkAddress != other.networkAddress) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(type);
+        builder.append("[");
+        builder.append(IPv4.fromIPv4Address(networkAddress));
+        builder.append("]");
+        return builder.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerDestination.java b/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerDestination.java
new file mode 100644
index 0000000000000000000000000000000000000000..13c14ff0bfb9435c5c8e9156344583e575c04624
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerDestination.java
@@ -0,0 +1,35 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionNetworkLayerDestination extends OFActionNetworkLayerAddress {
+    public OFActionNetworkLayerDestination() {
+        super();
+        super.setType(OFActionType.SET_NW_DST);
+        super.setLength((short) OFActionNetworkLayerAddress.MINIMUM_LENGTH);
+    }
+    
+    public OFActionNetworkLayerDestination(int ip) {
+        this();
+        this.networkAddress = ip;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerSource.java b/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef1d005e32f1f5b6aa92945a52f50df236413f74
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionNetworkLayerSource.java
@@ -0,0 +1,35 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionNetworkLayerSource extends OFActionNetworkLayerAddress {
+    public OFActionNetworkLayerSource() {
+        super();
+        super.setType(OFActionType.SET_NW_SRC);
+        super.setLength((short) OFActionNetworkLayerAddress.MINIMUM_LENGTH);
+    }
+    
+    public OFActionNetworkLayerSource(int ip) {
+        this();
+        this.networkAddress = ip;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionNetworkTypeOfService.java b/src/main/java/org/openflow/protocol/action/OFActionNetworkTypeOfService.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec91c764916beff70ee7bec9e8ba4e7a27f08645
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionNetworkTypeOfService.java
@@ -0,0 +1,110 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_enqueue
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionNetworkTypeOfService extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected byte networkTypeOfService;
+
+    public OFActionNetworkTypeOfService() {
+        super.setType(OFActionType.SET_NW_TOS);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+    
+    public OFActionNetworkTypeOfService(byte tos) {
+        this();
+        this.networkTypeOfService = tos;
+    }
+    
+
+    /**
+     * @return the networkTypeOfService
+     */
+    public byte getNetworkTypeOfService() {
+        return networkTypeOfService;
+    }
+
+    /**
+     * @param networkTypeOfService the networkTypeOfService to set
+     */
+    public void setNetworkTypeOfService(byte networkTypeOfService) {
+        this.networkTypeOfService = networkTypeOfService;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.networkTypeOfService = data.readByte();
+        data.readShort();
+        data.readByte();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeByte(this.networkTypeOfService);
+        data.writeShort((short) 0);
+        data.writeByte((byte) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 359;
+        int result = super.hashCode();
+        result = prime * result + networkTypeOfService;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionNetworkTypeOfService)) {
+            return false;
+        }
+        OFActionNetworkTypeOfService other = (OFActionNetworkTypeOfService) obj;
+        if (networkTypeOfService != other.networkTypeOfService) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(type);
+        builder.append("[");
+        builder.append(networkTypeOfService);
+        builder.append("]");
+        return builder.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/action/OFActionOutput.java b/src/main/java/org/openflow/protocol/action/OFActionOutput.java
new file mode 100644
index 0000000000000000000000000000000000000000..beca7e4f21f84a146f2b01a0a5585527c8fc67ef
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionOutput.java
@@ -0,0 +1,161 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class OFActionOutput extends OFAction implements Cloneable {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected short port;
+    protected short maxLength;
+
+    public OFActionOutput() {
+        super.setType(OFActionType.OUTPUT);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+
+    /**
+     * Create an Output Action sending packets out the specified
+     * OpenFlow port.
+     *
+     * This is the most common creation pattern for OFActions.
+     *
+     * @param port
+     */
+
+    public OFActionOutput(short port) {
+        this(port, (short) 65535);
+    }
+
+    /**
+     * Create an Output Action specifying both the port AND
+     * the snaplen of the packet to send out that port.
+     * The length field is only meaningful when port == OFPort.OFPP_CONTROLLER
+     * @param port
+     * @param maxLength The maximum number of bytes of the packet to send.
+     * Most hardware only supports this value for OFPP_CONTROLLER
+     */
+
+    public OFActionOutput(short port, short maxLength) {
+        super();
+        super.setType(OFActionType.OUTPUT);
+        super.setLength((short) MINIMUM_LENGTH);
+        this.port = port;
+        this.maxLength = maxLength;
+    }
+
+    /**
+     * Get the output port
+     * @return
+     */
+    public short getPort() {
+        return this.port;
+    }
+
+    /**
+     * Set the output port
+     * @param port
+     */
+    public OFActionOutput setPort(short port) {
+        this.port = port;
+        return this;
+    }
+
+    /**
+     * Get the max length to send to the controller
+     * @return
+     */
+    public short getMaxLength() {
+        return this.maxLength;
+    }
+
+    /**
+     * Set the max length to send to the controller
+     * @param maxLength
+     */
+    public OFActionOutput setMaxLength(short maxLength) {
+        this.maxLength = maxLength;
+        return this;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.port = data.readShort();
+        this.maxLength = data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(port);
+        data.writeShort(maxLength);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 367;
+        int result = super.hashCode();
+        result = prime * result + maxLength;
+        result = prime * result + port;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionOutput)) {
+            return false;
+        }
+        OFActionOutput other = (OFActionOutput) obj;
+        if (maxLength != other.maxLength) {
+            return false;
+        }
+        if (port != other.port) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(type);
+        builder.append("[");
+        builder.append(port);
+        builder.append("]");
+        return builder.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/action/OFActionStripVirtualLan.java b/src/main/java/org/openflow/protocol/action/OFActionStripVirtualLan.java
new file mode 100644
index 0000000000000000000000000000000000000000..f79c84d391751abeb8e49606382a9e1325264f39
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionStripVirtualLan.java
@@ -0,0 +1,60 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+
+/**
+ * Represents an ofp_action_strip_vlan
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionStripVirtualLan extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    public OFActionStripVirtualLan() {
+        super();
+        super.setType(OFActionType.STRIP_VLAN);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        // PAD
+        data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        // PAD
+        data.writeInt(0);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(type);
+        return builder.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/action/OFActionTransportLayer.java b/src/main/java/org/openflow/protocol/action/OFActionTransportLayer.java
new file mode 100644
index 0000000000000000000000000000000000000000..696c1c7a29d01132c2667e0cda9639b3dcc4eec9
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionTransportLayer.java
@@ -0,0 +1,98 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_tp_port
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public abstract class OFActionTransportLayer extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected short transportPort;
+
+    /**
+     * @return the transportPort
+     */
+    public short getTransportPort() {
+        return transportPort;
+    }
+
+    /**
+     * @param transportPort the transportPort to set
+     */
+    public void setTransportPort(short transportPort) {
+        this.transportPort = transportPort;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.transportPort = data.readShort();
+        data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.transportPort);
+        data.writeShort((short) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 373;
+        int result = super.hashCode();
+        result = prime * result + transportPort;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionTransportLayer)) {
+            return false;
+        }
+        OFActionTransportLayer other = (OFActionTransportLayer) obj;
+        if (transportPort != other.transportPort) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(type);
+        builder.append("[");
+        builder.append(transportPort);
+        builder.append("]");
+        return builder.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/action/OFActionTransportLayerDestination.java b/src/main/java/org/openflow/protocol/action/OFActionTransportLayerDestination.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e7b0f1fc6539d306ed69548e1b24c33a0aa2d65
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionTransportLayerDestination.java
@@ -0,0 +1,35 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionTransportLayerDestination extends OFActionTransportLayer {
+    public OFActionTransportLayerDestination() {
+        super();
+        super.setType(OFActionType.SET_TP_DST);
+        super.setLength((short) OFActionTransportLayer.MINIMUM_LENGTH);
+    }
+    
+    public OFActionTransportLayerDestination(short port) {
+        this();
+        this.transportPort = port;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionTransportLayerSource.java b/src/main/java/org/openflow/protocol/action/OFActionTransportLayerSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..385aa53c88478f04f92644271342ee02c6e93d25
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionTransportLayerSource.java
@@ -0,0 +1,35 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFActionTransportLayerSource extends OFActionTransportLayer {
+    public OFActionTransportLayerSource() {
+        super();
+        super.setType(OFActionType.SET_TP_SRC);
+        super.setLength((short) OFActionTransportLayer.MINIMUM_LENGTH);
+    }
+    
+    public OFActionTransportLayerSource(short port) {
+        this();
+        this.transportPort = port;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionType.java b/src/main/java/org/openflow/protocol/action/OFActionType.java
new file mode 100644
index 0000000000000000000000000000000000000000..18229170b77dc1a01984cfc9f156272f5ad858c5
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionType.java
@@ -0,0 +1,203 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+import java.lang.reflect.Constructor;
+
+import org.openflow.protocol.Instantiable;
+
+/**
+ * List of OpenFlow Action types and mappings to wire protocol value and
+ * derived classes
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public enum OFActionType {
+    OUTPUT              (0, OFActionOutput.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionOutput();
+                            }}),
+    SET_VLAN_ID        (1, OFActionVirtualLanIdentifier.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionVirtualLanIdentifier();
+                            }}),
+    SET_VLAN_PCP        (2, OFActionVirtualLanPriorityCodePoint.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionVirtualLanPriorityCodePoint();
+                            }}),
+    STRIP_VLAN          (3, OFActionStripVirtualLan.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionStripVirtualLan();
+                            }}),
+    SET_DL_SRC          (4, OFActionDataLayerSource.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionDataLayerSource();
+                            }}),
+    SET_DL_DST          (5, OFActionDataLayerDestination.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionDataLayerDestination();
+                            }}),
+    SET_NW_SRC          (6, OFActionNetworkLayerSource.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionNetworkLayerSource();
+                            }}),
+    SET_NW_DST          (7, OFActionNetworkLayerDestination.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionNetworkLayerDestination();
+                            }}),
+    SET_NW_TOS          (8, OFActionNetworkTypeOfService.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionNetworkTypeOfService();
+                            }}),
+    SET_TP_SRC          (9, OFActionTransportLayerSource.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionTransportLayerSource();
+                            }}),
+    SET_TP_DST          (10, OFActionTransportLayerDestination.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionTransportLayerDestination();
+                            }}),
+    OPAQUE_ENQUEUE      (11, OFActionEnqueue.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionEnqueue();
+                            }}),
+    VENDOR              (0xffff, OFActionVendor.class, new Instantiable<OFAction>() {
+                            @Override
+                            public OFAction instantiate() {
+                                return new OFActionVendorGeneric();
+                            }});
+
+    protected static OFActionType[] mapping;
+
+    protected Class<? extends OFAction> clazz;
+    protected Constructor<? extends OFAction> constructor;
+    protected Instantiable<OFAction> instantiable;
+    protected int minLen;
+    protected short type;
+
+    /**
+     * Store some information about the OpenFlow Action type, including wire
+     * protocol type number, length, and derrived class
+     *
+     * @param type Wire protocol number associated with this OFType
+     * @param clazz The Java class corresponding to this type of OpenFlow Action
+     * @param instantiable the instantiable for the OFAction this type represents
+     */
+    OFActionType(int type, Class<? extends OFAction> clazz, Instantiable<OFAction> instantiable) {
+        this.type = (short) type;
+        this.clazz = clazz;
+        this.instantiable = instantiable;
+        try {
+            this.constructor = clazz.getConstructor(new Class[]{});
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Failure getting constructor for class: " + clazz, e);
+        }
+        OFActionType.addMapping(this.type, this);
+    }
+
+    /**
+     * Adds a mapping from type value to OFActionType enum
+     *
+     * @param i OpenFlow wire protocol Action type value
+     * @param t type
+     */
+    static public void addMapping(short i, OFActionType t) {
+        if (mapping == null)
+            mapping = new OFActionType[16];
+        // bring higher mappings down to the edge of our array
+        if (i < 0)
+            i = (short) (16 + i);
+        OFActionType.mapping[i] = t;
+    }
+
+    /**
+     * Given a wire protocol OpenFlow type number, return the OFType associated
+     * with it
+     *
+     * @param i wire protocol number
+     * @return OFType enum type
+     */
+
+    static public OFActionType valueOf(short i) {
+        if (i < 0)
+            i = (short) (16+i);
+        return OFActionType.mapping[i];
+    }
+
+    /**
+     * @return Returns the wire protocol value corresponding to this
+     *         OFActionType
+     */
+    public short getTypeValue() {
+        return this.type;
+    }
+
+    /**
+     * @return return the OFAction subclass corresponding to this OFActionType
+     */
+    public Class<? extends OFAction> toClass() {
+        return clazz;
+    }
+
+    /**
+     * Returns the no-argument Constructor of the implementation class for
+     * this OFActionType
+     * @return the constructor
+     */
+    public Constructor<? extends OFAction> getConstructor() {
+        return constructor;
+    }
+
+    /**
+     * Returns a new instance of the OFAction represented by this OFActionType
+     * @return the new object
+     */
+    public OFAction newInstance() {
+        return instantiable.instantiate();
+    }
+
+    /**
+     * @return the instantiable
+     */
+    public Instantiable<OFAction> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * @param instantiable the instantiable to set
+     */
+    public void setInstantiable(Instantiable<OFAction> instantiable) {
+        this.instantiable = instantiable;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionVendor.java b/src/main/java/org/openflow/protocol/action/OFActionVendor.java
new file mode 100644
index 0000000000000000000000000000000000000000..5860ef1160ae43fe3606a582c8e7d7ae842820eb
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionVendor.java
@@ -0,0 +1,94 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public abstract class OFActionVendor extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected int vendor;
+
+    public OFActionVendor() {
+        super();
+        super.setType(OFActionType.VENDOR);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the vendor
+     */
+    public int getVendor() {
+        return vendor;
+    }
+
+    /**
+     * @param vendor the vendor to set
+     */
+    public void setVendor(int vendor) {
+        this.vendor = vendor;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.vendor = data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(this.vendor);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 379;
+        int result = super.hashCode();
+        result = prime * result + vendor;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionVendor)) {
+            return false;
+        }
+        OFActionVendor other = (OFActionVendor) obj;
+        if (vendor != other.vendor) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + "; vendor=" + vendor;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionVendorGeneric.java b/src/main/java/org/openflow/protocol/action/OFActionVendorGeneric.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f7859f5ec43e8e13ff8340c50f5cda6f2d2311c
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionVendorGeneric.java
@@ -0,0 +1,96 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.action;
+
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/** A generic / unparsed vendor action. This action is returned by
+ *  BasicFactory.readFromWire if no more specific OFVendorActionFactory
+ *  is registered.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class OFActionVendorGeneric extends OFActionVendor {
+    public static int MINIMUM_LENGTH = 8;
+
+    private final static byte[] EMPTY_ARRAY = new byte[0];
+
+    protected byte[] vendorData;
+
+    public OFActionVendorGeneric() {
+        super();
+    }
+
+    public byte[] getVendorData() {
+        return vendorData;
+    }
+
+    public void setVendorData(byte[] vendorData) {
+        this.vendorData = vendorData;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+
+        int vendorDataLength = this.getLength() - MINIMUM_LENGTH;
+        if (vendorDataLength > 0) {
+            vendorData = new byte[vendorDataLength];
+            data.readBytes(vendorData);
+        } else {
+            vendorData = EMPTY_ARRAY;
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(this.vendor);
+        data.writeBytes(vendorData);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 379;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(vendorData);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionVendorGeneric)) {
+            return false;
+        }
+        OFActionVendorGeneric other = (OFActionVendorGeneric) obj;
+        if (!Arrays.equals(vendorData, other.vendorData)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/action/OFActionVirtualLanIdentifier.java b/src/main/java/org/openflow/protocol/action/OFActionVirtualLanIdentifier.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bd0e0bda156cc34ac915ee29900e8a83b5cfbd0
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionVirtualLanIdentifier.java
@@ -0,0 +1,98 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_vlan_vid
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionVirtualLanIdentifier extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected short virtualLanIdentifier;
+
+    public OFActionVirtualLanIdentifier() {
+        super.setType(OFActionType.SET_VLAN_ID);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+    
+    public OFActionVirtualLanIdentifier(short vlanId) {
+        this();
+        this.virtualLanIdentifier = vlanId;
+    }
+
+    /**
+     * @return the virtualLanIdentifier
+     */
+    public short getVirtualLanIdentifier() {
+        return virtualLanIdentifier;
+    }
+
+    /**
+     * @param virtualLanIdentifier the virtualLanIdentifier to set
+     */
+    public void setVirtualLanIdentifier(short virtualLanIdentifier) {
+        this.virtualLanIdentifier = virtualLanIdentifier;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.virtualLanIdentifier = data.readShort();
+        data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.virtualLanIdentifier);
+        data.writeShort((short) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 383;
+        int result = super.hashCode();
+        result = prime * result + virtualLanIdentifier;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionVirtualLanIdentifier)) {
+            return false;
+        }
+        OFActionVirtualLanIdentifier other = (OFActionVirtualLanIdentifier) obj;
+        if (virtualLanIdentifier != other.virtualLanIdentifier) {
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/action/OFActionVirtualLanPriorityCodePoint.java b/src/main/java/org/openflow/protocol/action/OFActionVirtualLanPriorityCodePoint.java
new file mode 100644
index 0000000000000000000000000000000000000000..9202df33f82548c74919d7b34be5714aa9036256
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionVirtualLanPriorityCodePoint.java
@@ -0,0 +1,100 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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.
+**/
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+package org.openflow.protocol.action;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_action_vlan_pcp
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public class OFActionVirtualLanPriorityCodePoint extends OFAction {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected byte virtualLanPriorityCodePoint;
+
+    public OFActionVirtualLanPriorityCodePoint() {
+        super.setType(OFActionType.SET_VLAN_PCP);
+        super.setLength((short) MINIMUM_LENGTH);
+    }
+    
+    public OFActionVirtualLanPriorityCodePoint(byte priority) {
+        this();
+        this.virtualLanPriorityCodePoint = priority;
+    }
+
+    /**
+     * @return the virtualLanPriorityCodePoint
+     */
+    public byte getVirtualLanPriorityCodePoint() {
+        return virtualLanPriorityCodePoint;
+    }
+
+    /**
+     * @param virtualLanPriorityCodePoint the virtualLanPriorityCodePoint to set
+     */
+    public void setVirtualLanPriorityCodePoint(byte virtualLanPriorityCodePoint) {
+        this.virtualLanPriorityCodePoint = virtualLanPriorityCodePoint;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.virtualLanPriorityCodePoint = data.readByte();
+        data.readShort(); // pad
+        data.readByte(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeByte(this.virtualLanPriorityCodePoint);
+        data.writeShort((short) 0);
+        data.writeByte((byte) 0);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 389;
+        int result = super.hashCode();
+        result = prime * result + virtualLanPriorityCodePoint;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionVirtualLanPriorityCodePoint)) {
+            return false;
+        }
+        OFActionVirtualLanPriorityCodePoint other = (OFActionVirtualLanPriorityCodePoint) obj;
+        if (virtualLanPriorityCodePoint != other.virtualLanPriorityCodePoint) {
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/factory/BasicFactory.java b/src/main/java/org/openflow/protocol/factory/BasicFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..f484a167f5cd64f1eaec92dd366a4f0ff02a8ece
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/BasicFactory.java
@@ -0,0 +1,346 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.factory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionType;
+import org.openflow.protocol.action.OFActionVendor;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.protocol.statistics.OFVendorStatistics;
+import org.openflow.protocol.vendor.OFByteArrayVendorData;
+import org.openflow.protocol.vendor.OFVendorData;
+import org.openflow.protocol.vendor.OFVendorDataType;
+import org.openflow.protocol.vendor.OFVendorId;
+
+
+/**
+ * A basic OpenFlow factory that supports naive creation of both Messages and
+ * Actions.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ *
+ */
+public enum BasicFactory implements OFMessageFactory, OFActionFactory,
+        OFStatisticsFactory, OFVendorDataFactory {
+    SINGLETON_INSTANCE;
+
+
+    private final OFVendorActionRegistry vendorActionRegistry;
+
+    private BasicFactory() {
+        vendorActionRegistry = OFVendorActionRegistry.getInstance();
+    }
+
+    public static BasicFactory getInstance() {
+        return SINGLETON_INSTANCE;
+    }
+
+    /**
+     * create and return a new instance of a message for OFType t. Also injects
+     * factories for those message types that implement the *FactoryAware
+     * interfaces.
+     *
+     * @return a newly created instance that may be modified / used freely by
+     *         the caller
+     */
+    @Override
+    public OFMessage getMessage(OFType t) {
+        OFMessage message = t.newInstance();
+        injectFactories(message);
+        return message;
+    }
+
+    @Override
+    public List<OFMessage> parseMessage(ChannelBuffer data) throws MessageParseException {
+        List<OFMessage> msglist = new ArrayList<OFMessage>();
+        OFMessage msg = null;
+
+        while (data.readableBytes() >= OFMessage.MINIMUM_LENGTH) {
+            data.markReaderIndex();
+            msg = this.parseMessageOne(data);
+            if (msg == null) {
+                data.resetReaderIndex();
+                break;
+            }
+            else {
+                msglist.add(msg);
+            }
+        }
+
+        if (msglist.size() == 0) {
+            return null;
+        }
+        return msglist;
+
+    }
+
+    public OFMessage parseMessageOne(ChannelBuffer data) throws MessageParseException {
+        try {
+            OFMessage demux = new OFMessage();
+            OFMessage ofm = null;
+
+            if (data.readableBytes() < OFMessage.MINIMUM_LENGTH)
+                return ofm;
+
+            data.markReaderIndex();
+            demux.readFrom(data);
+            data.resetReaderIndex();
+
+            if (demux.getLengthU() > data.readableBytes())
+                return ofm;
+
+            ofm = getMessage(demux.getType());
+            if (ofm == null)
+                return null;
+
+            injectFactories(ofm);
+            ofm.readFrom(data);
+            if (OFMessage.class.equals(ofm.getClass())) {
+                // advance the position for un-implemented messages
+                data.readerIndex(data.readerIndex()+(ofm.getLengthU() -
+                        OFMessage.MINIMUM_LENGTH));
+            }
+
+            return ofm;
+        } catch (Exception e) {
+            /* Write the offending data along with the error message */
+            data.resetReaderIndex();
+            String msg =
+                    "Message Parse Error for packet:" +  dumpBuffer(data) +
+                    "\nException: " + e.toString();
+            data.resetReaderIndex();
+
+            throw new MessageParseException(msg, e);
+        }
+    }
+
+    private void injectFactories(OFMessage ofm) {
+        if (ofm instanceof OFActionFactoryAware) {
+            ((OFActionFactoryAware)ofm).setActionFactory(this);
+        }
+        if (ofm instanceof OFMessageFactoryAware) {
+            ((OFMessageFactoryAware)ofm).setMessageFactory(this);
+        }
+        if (ofm instanceof OFStatisticsFactoryAware) {
+            ((OFStatisticsFactoryAware)ofm).setStatisticsFactory(this);
+        }
+        if (ofm instanceof OFVendorDataFactoryAware) {
+            ((OFVendorDataFactoryAware)ofm).setVendorDataFactory(this);
+        }
+    }
+
+    @Override
+    public OFAction getAction(OFActionType t) {
+        return t.newInstance();
+    }
+
+    @Override
+    public List<OFAction> parseActions(ChannelBuffer data, int length) {
+        return parseActions(data, length, 0);
+    }
+
+    @Override
+    public List<OFAction> parseActions(ChannelBuffer data, int length, int limit) {
+        List<OFAction> results = new ArrayList<OFAction>();
+        OFAction demux = new OFAction();
+        OFAction ofa;
+        int end = data.readerIndex() + length;
+
+        while (limit == 0 || results.size() <= limit) {
+            if ((data.readableBytes() < OFAction.MINIMUM_LENGTH ||
+                (data.readerIndex() + OFAction.MINIMUM_LENGTH) > end))
+                return results;
+
+            data.markReaderIndex();
+            demux.readFrom(data);
+            data.resetReaderIndex();
+
+            if ((demux.getLengthU() > data.readableBytes() ||
+                (data.readerIndex() + demux.getLengthU()) > end))
+                return results;
+
+            ofa = parseActionOne(demux.getType(), data);
+            results.add(ofa);
+        }
+
+        return results;
+    }
+
+    private OFAction parseActionOne(OFActionType type, ChannelBuffer data) {
+        OFAction ofa;
+        data.markReaderIndex();
+        ofa = getAction(type);
+        ofa.readFrom(data);
+
+        if(type == OFActionType.VENDOR) {
+            OFActionVendor vendorAction = (OFActionVendor) ofa;
+
+            OFVendorActionFactory vendorActionFactory = vendorActionRegistry.get(vendorAction.getVendor());
+
+            if(vendorActionFactory != null) {
+                // if we have a specific vendorActionFactory for this vendor id,
+                // delegate to it for vendor-specific reparsing of the message
+                data.resetReaderIndex();
+                OFActionVendor newAction = vendorActionFactory.readFrom(data);
+                if(newAction != null)
+                    ofa = newAction;
+            }
+        }
+
+        if (OFAction.class.equals(ofa.getClass())) {
+            // advance the position for un-implemented messages
+            data.readerIndex(data.readerIndex()+(ofa.getLengthU() -
+                    OFAction.MINIMUM_LENGTH));
+        }
+        return ofa;
+    }
+
+    @Override
+    public OFActionFactory getActionFactory() {
+        return this;
+    }
+
+    @Override
+    public OFStatistics getStatistics(OFType t, OFStatisticsType st) {
+        return st.newInstance(t);
+    }
+
+    @Override
+    public List<OFStatistics> parseStatistics(OFType t, OFStatisticsType st,
+                                              ChannelBuffer data, int length) {
+        return parseStatistics(t, st, data, length, 0);
+    }
+
+    /**
+     * @param t
+     *            OFMessage type: should be one of stats_request or stats_reply
+     * @param st
+     *            statistics type of this message, e.g., DESC, TABLE
+     * @param data
+     *            buffer to read from
+     * @param length
+     *            length of statistics
+     * @param limit
+     *            number of statistics to grab; 0 == all
+     *
+     * @return list of statistics
+     */
+
+    @Override
+    public List<OFStatistics> parseStatistics(OFType t, OFStatisticsType st,
+            ChannelBuffer data, int length, int limit) {
+        List<OFStatistics> results = new ArrayList<OFStatistics>();
+        OFStatistics statistics = getStatistics(t, st);
+
+        int start = data.readerIndex();
+        int count = 0;
+
+        while (limit == 0 || results.size() <= limit) {
+            // TODO Create a separate MUX/DEMUX path for vendor stats
+            if (statistics instanceof OFVendorStatistics)
+                ((OFVendorStatistics)statistics).setLength(length);
+
+            /**
+             * can't use data.remaining() here, b/c there could be other data
+             * buffered past this message
+             */
+            if ((length - count) >= statistics.getLength()) {
+                if (statistics instanceof OFActionFactoryAware)
+                    ((OFActionFactoryAware)statistics).setActionFactory(this);
+                statistics.readFrom(data);
+                results.add(statistics);
+                count += statistics.getLength();
+                statistics = getStatistics(t, st);
+            } else {
+                if (count < length) {
+                    /**
+                     * Nasty case: partial/incomplete statistic found even
+                     * though we have a full message. Found when NOX sent
+                     * agg_stats request with wrong agg statistics length (52
+                     * instead of 56)
+                     *
+                     * just throw the rest away, or we will break framing
+                     */
+                    data.readerIndex(start + length);
+                }
+                return results;
+            }
+        }
+        return results; // empty; no statistics at all
+    }
+
+
+    @Override
+    public OFVendorData getVendorData(OFVendorId vendorId,
+                                      OFVendorDataType vendorDataType) {
+        if (vendorDataType == null)
+            return null;
+
+        return vendorDataType.newInstance();
+    }
+
+    /**
+     * Attempts to parse and return the OFVendorData contained in the given
+     * ChannelBuffer, beginning right after the vendor id.
+     * @param vendor the vendor id that was parsed from the OFVendor message.
+     * @param data the ChannelBuffer from which to parse the vendor data
+     * @param length the length to the end of the enclosing message.
+     * @return an OFVendorData instance
+     */
+    @Override
+    public OFVendorData parseVendorData(int vendor, ChannelBuffer data,
+            int length) {
+        OFVendorDataType vendorDataType = null;
+        OFVendorId vendorId = OFVendorId.lookupVendorId(vendor);
+        if (vendorId != null) {
+            data.markReaderIndex();
+            vendorDataType = vendorId.parseVendorDataType(data, length);
+            data.resetReaderIndex();
+        }
+
+        OFVendorData vendorData = getVendorData(vendorId, vendorDataType);
+        if (vendorData == null)
+            vendorData = new OFByteArrayVendorData();
+
+        vendorData.readFrom(data, length);
+
+        return vendorData;
+    }
+
+    public static String dumpBuffer(ChannelBuffer data) {
+        // NOTE: Reads all the bytes in buffer from current read offset.
+        // Set/Reset ReaderIndex if you want to read from a different location
+        int len = data.readableBytes();
+        StringBuffer sb = new StringBuffer();
+        for (int i=0 ; i<len; i++) {
+            if (i%32 == 0) sb.append("\n");
+            if (i%4 == 0) sb.append(" ");
+            sb.append(String.format("%02x", data.getUnsignedByte(i)));
+        }
+        return sb.toString();
+    }
+
+}
diff --git a/src/main/java/org/openflow/protocol/factory/MessageParseException.java b/src/main/java/org/openflow/protocol/factory/MessageParseException.java
new file mode 100644
index 0000000000000000000000000000000000000000..20f381ef8d095a22f98936640435b94a61f5c237
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/MessageParseException.java
@@ -0,0 +1,45 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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 org.openflow.protocol.factory;
+
+/**
+ * Exception thrown when an openflow message fails to parse properly
+ */
+public class MessageParseException extends Exception {
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -75893812926304726L;
+
+    public MessageParseException() {
+        super();
+    }
+
+    public MessageParseException(String message, Throwable cause) {
+        super(message, cause);
+        this.setStackTrace(cause.getStackTrace());
+    }
+
+    public MessageParseException(String message) {
+        super(message);
+    }
+
+    public MessageParseException(Throwable cause) {
+        super(cause);
+        this.setStackTrace(cause.getStackTrace());
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFActionFactory.java b/src/main/java/org/openflow/protocol/factory/OFActionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3cd06265bf9a7d0b832afabc5ff18ce0412eacb
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFActionFactory.java
@@ -0,0 +1,61 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.factory;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionType;
+
+
+/**
+ * The interface to factories used for retrieving OFAction instances. All
+ * methods are expected to be thread-safe.
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFActionFactory {
+    /**
+     * Retrieves an OFAction instance corresponding to the specified
+     * OFActionType
+     * @param t the type of the OFAction to be retrieved
+     * @return an OFAction instance
+     */
+    public OFAction getAction(OFActionType t);
+
+    /**
+     * Attempts to parse and return all OFActions contained in the given
+     * ByteBuffer, beginning at the ByteBuffer's position, and ending at
+     * position+length.
+     * @param data the ChannelBuffer to parse for OpenFlow actions
+     * @param length the number of Bytes to examine for OpenFlow actions
+     * @return a list of OFAction instances
+     */
+    public List<OFAction> parseActions(ChannelBuffer data, int length);
+
+    /**
+     * Attempts to parse and return all OFActions contained in the given
+     * ByteBuffer, beginning at the ByteBuffer's position, and ending at
+     * position+length.
+     * @param data the ChannelBuffer to parse for OpenFlow actions
+     * @param length the number of Bytes to examine for OpenFlow actions
+     * @param limit the maximum number of messages to return, 0 means no limit
+     * @return a list of OFAction instances
+     */
+    public List<OFAction> parseActions(ChannelBuffer data, int length, int limit);
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFActionFactoryAware.java b/src/main/java/org/openflow/protocol/factory/OFActionFactoryAware.java
new file mode 100644
index 0000000000000000000000000000000000000000..a97a95c0a6c666fc01112cb629ad750c0f4d8012
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFActionFactoryAware.java
@@ -0,0 +1,31 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.factory;
+
+/**
+ * Objects implementing this interface are expected to be instantiated with an
+ * instance of an OFActionFactory
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFActionFactoryAware {
+    /**
+     * Sets the OFActionFactory
+     * @param actionFactory
+     */
+    public void setActionFactory(OFActionFactory actionFactory);
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFMessageFactory.java b/src/main/java/org/openflow/protocol/factory/OFMessageFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..8bb7045463aee7cfc6d66a207f9737b8a7eabdf6
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFMessageFactory.java
@@ -0,0 +1,55 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.factory;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+
+
+/**
+ * The interface to factories used for retrieving OFMessage instances. All
+ * methods are expected to be thread-safe.
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFMessageFactory {
+    /**
+     * Retrieves an OFMessage instance corresponding to the specified OFType
+     * @param t the type of the OFMessage to be retrieved
+     * @return an OFMessage instance
+     */
+    public OFMessage getMessage(OFType t);
+
+    /**
+     * Attempts to parse and return a OFMessages contained in the given
+     * ChannelBuffer, beginning at the ChannelBuffer's position, and ending at the
+     * after the first parsed message
+     * @param data the ChannelBuffer to parse for an OpenFlow message
+     * @return a list of OFMessage instances
+     * @throws MessageParseException 
+     */
+    public List<OFMessage> parseMessage(ChannelBuffer data) throws MessageParseException;
+
+    /**
+     * Retrieves an OFActionFactory
+     * @return an OFActionFactory
+     */
+    public OFActionFactory getActionFactory();
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFMessageFactoryAware.java b/src/main/java/org/openflow/protocol/factory/OFMessageFactoryAware.java
new file mode 100644
index 0000000000000000000000000000000000000000..adb1421e13a7638b84f6aca7c9e320a4dc944e69
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFMessageFactoryAware.java
@@ -0,0 +1,35 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.factory;
+
+/**
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ *
+ */
+public interface OFMessageFactoryAware {
+
+       /**
+        * Sets the message factory for this object
+        * 
+        * @param factory
+        */
+       void setMessageFactory(OFMessageFactory factory);
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFStatisticsFactory.java b/src/main/java/org/openflow/protocol/factory/OFStatisticsFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..32eb3cbffa5fb1765439108c4691279981743240
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFStatisticsFactory.java
@@ -0,0 +1,72 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.factory;
+
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.protocol.statistics.OFStatisticsType;
+
+
+/**
+ * The interface to factories used for retrieving OFStatistics instances. All
+ * methods are expected to be thread-safe.
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFStatisticsFactory {
+    /**
+     * Retrieves an OFStatistics instance corresponding to the specified
+     * OFStatisticsType
+     * @param t the type of the containing OFMessage, only accepts statistics
+     *           request or reply
+     * @param st the type of the OFStatistics to be retrieved
+     * @return an OFStatistics instance
+     */
+    public OFStatistics getStatistics(OFType t, OFStatisticsType st);
+
+    /**
+     * Attempts to parse and return all OFStatistics contained in the given
+     * ByteBuffer, beginning at the ByteBuffer's position, and ending at
+     * position+length.
+     * @param t the type of the containing OFMessage, only accepts statistics
+     *           request or reply
+     * @param st the type of the OFStatistics to be retrieved
+     * @param data the ChannelBuffer to parse for OpenFlow Statistics
+     * @param length the number of Bytes to examine for OpenFlow Statistics
+     * @return a list of OFStatistics instances
+     */
+    public List<OFStatistics> parseStatistics(OFType t,
+            OFStatisticsType st, ChannelBuffer data, int length);
+
+    /**
+     * Attempts to parse and return all OFStatistics contained in the given
+     * ByteBuffer, beginning at the ByteBuffer's position, and ending at
+     * position+length.
+     * @param t the type of the containing OFMessage, only accepts statistics
+     *           request or reply
+     * @param st the type of the OFStatistics to be retrieved
+     * @param data the ChannelBuffer to parse for OpenFlow Statistics
+     * @param length the number of Bytes to examine for OpenFlow Statistics
+     * @param limit the maximum number of messages to return, 0 means no limit
+     * @return a list of OFStatistics instances
+     */
+    public List<OFStatistics> parseStatistics(OFType t,
+            OFStatisticsType st, ChannelBuffer data, int length, int limit);
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFStatisticsFactoryAware.java b/src/main/java/org/openflow/protocol/factory/OFStatisticsFactoryAware.java
new file mode 100644
index 0000000000000000000000000000000000000000..52ab09a9501ce05e358766d6d08056dd33997b07
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFStatisticsFactoryAware.java
@@ -0,0 +1,31 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.factory;
+
+/**
+ * Objects implementing this interface are expected to be instantiated with an
+ * instance of an OFStatisticsFactory
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public interface OFStatisticsFactoryAware {
+    /**
+     * Sets the OFStatisticsFactory
+     * @param statisticsFactory
+     */
+    public void setStatisticsFactory(OFStatisticsFactory statisticsFactory);
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFVendorActionFactory.java b/src/main/java/org/openflow/protocol/factory/OFVendorActionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb89810b78b9709b89b651731cd20d5615f6b80e
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFVendorActionFactory.java
@@ -0,0 +1,43 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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 org.openflow.protocol.factory;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.action.OFActionVendor;
+
+/** Interface contract for an actionfactory that creates vendor-specific actions.
+ *  VendorActionFactories are registered with the BasicFactory for a specific
+ *  vendor id.
+ *  <p>
+ *  <b>Note:</b> Implementations are expected to be thread-safe.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public interface OFVendorActionFactory {
+
+    /** parse the data from the wire, create and return a vendor-specific action.
+     *
+     * @param data contains a serialized vendor action at the current readerPosition.
+     *    The full message is guaranteed to be available in the buffer.
+     *
+     * @return upon success returns a newly allocated vendor-specific
+     *   action instance, and advances the readerPosition in data for the
+     *   entire length. Upon failure, returns null and leaves the readerPosition
+     *   in data unmodified.
+     */
+    OFActionVendor readFrom(ChannelBuffer data);
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFVendorActionRegistry.java b/src/main/java/org/openflow/protocol/factory/OFVendorActionRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f556812c65bde8dce9e7c17de2ac050a8c24160
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFVendorActionRegistry.java
@@ -0,0 +1,50 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    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 org.openflow.protocol.factory;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/** Singleton registry object that holds a mapping from vendor ids to vendor-specific
+ *  mapping factories. Threadsafe.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class OFVendorActionRegistry {
+    private static class InstanceHolder {
+        private final static OFVendorActionRegistry instance = new OFVendorActionRegistry();
+    }
+
+    public static OFVendorActionRegistry getInstance() {
+        return InstanceHolder.instance;
+    }
+    private final Map <Integer, OFVendorActionFactory> vendorActionFactories;
+
+    public OFVendorActionRegistry() {
+        vendorActionFactories = new ConcurrentHashMap<Integer, OFVendorActionFactory>();
+    }
+
+    public OFVendorActionFactory register(int vendorId, OFVendorActionFactory factory) {
+        return vendorActionFactories.put(vendorId, factory);
+    }
+
+    public OFVendorActionFactory get(int vendorId) {
+        return vendorActionFactories.get(vendorId);
+    }
+
+
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java b/src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..d754a4a31087cc309cc6ac8885d05c492c0da23a
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFVendorDataFactory.java
@@ -0,0 +1,69 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.factory;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.vendor.OFVendorData;
+import org.openflow.protocol.vendor.OFVendorDataType;
+import org.openflow.protocol.vendor.OFVendorId;
+
+/**
+ * The interface to factories used for parsing/creating OFVendorData instances.
+ * All methods are expected to be thread-safe.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public interface OFVendorDataFactory {
+    /**
+     * Retrieves an OFVendorData instance corresponding to the specified
+     * OFVendorId and OFVendorDataType. There are 3 possible cases for
+     * how this will be called:
+     * 
+     * 1) If the vendor id in the OFVendor message is an unknown value, 
+     *    then this method is called with both vendorId and vendorDataType
+     *    set to null. In this case typically the factory method should
+     *    return an instance of OFGenericVendorData that just contains
+     *    the raw byte array of the vendor data.
+     *    
+     * 2) If the vendor id is known but no vendor data type has been
+     *    registered for the data in the message, then vendorId is set to
+     *    the appropriate OFVendorId instance and OFVendorDataType is set
+     *    to null. This would typically be handled the same way as #1
+     *    
+     * 3) If both the vendor id and and vendor data type are known, then
+     *    typically you'd just call the method in OFVendorDataType to
+     *    instantiate the appropriate subclass of OFVendorData.
+     *    
+     * @param vendorId the vendorId of the containing OFVendor message
+     * @param vendorDataType the type of the OFVendorData to be retrieved
+     * @return an OFVendorData instance
+     */
+    public OFVendorData getVendorData(OFVendorId vendorId,
+            OFVendorDataType vendorDataType);
+    
+    /**
+     * Attempts to parse and return the OFVendorData contained in the given
+     * ChannelBuffer, beginning right after the vendor id.
+     * @param vendorId the vendor id that was parsed from the OFVendor message.
+     * @param data the ChannelBuffer from which to parse the vendor data
+     * @param length the length to the end of the enclosing message.
+     * @return an OFVendorData instance
+     */
+    public OFVendorData parseVendorData(int vendorId, ChannelBuffer data,
+            int length);
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java b/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java
new file mode 100644
index 0000000000000000000000000000000000000000..23614b0d0eccdfe23184973ddb57f790b7ff48c3
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFVendorDataFactoryAware.java
@@ -0,0 +1,28 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.factory;
+
+/**
+ * Classes implementing this interface are expected to be instantiated with an
+ * instance of an OFVendorDataFactory
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public interface OFVendorDataFactoryAware {
+    public void setVendorDataFactory(OFVendorDataFactory vendorDataFactory);
+}
diff --git a/src/main/java/org/openflow/protocol/serializers/OFFeaturesReplyJSONSerializer.java b/src/main/java/org/openflow/protocol/serializers/OFFeaturesReplyJSONSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..1102dc78653263a2e33a4967b8d4a3935f44df67
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/serializers/OFFeaturesReplyJSONSerializer.java
@@ -0,0 +1,57 @@
+/**
+*    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 org.openflow.protocol.serializers;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.util.HexString;
+
+public class OFFeaturesReplyJSONSerializer extends JsonSerializer<OFFeaturesReply> {
+    
+    /**
+     * Performs the serialization of a OFFeaturesReply object
+     */
+    @Override
+    public void serialize(OFFeaturesReply reply, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException {
+        jGen.writeStartObject();
+        jGen.writeNumberField("actions", reply.getActions());
+        jGen.writeNumberField("buffers", reply.getBuffers());
+        jGen.writeNumberField("capabilities", reply.getCapabilities());
+        jGen.writeStringField("datapathId", HexString.toHexString(reply.getDatapathId()));
+        jGen.writeNumberField("length", reply.getLength());
+        serializer.defaultSerializeField("ports", reply.getPorts(), jGen);
+        jGen.writeNumberField("tables", reply.getTables());
+        jGen.writeStringField("type", reply.getType().toString());
+        jGen.writeNumberField("version", reply.getVersion());
+        jGen.writeNumberField("xid", reply.getXid());
+        jGen.writeEndObject();
+    }
+
+    /**
+     * Tells SimpleModule that we are the serializer for OFFeaturesReply
+     */
+    @Override
+    public Class<OFFeaturesReply> handledType() {
+        return OFFeaturesReply.class;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/serializers/OFMatchJSONSerializer.java b/src/main/java/org/openflow/protocol/serializers/OFMatchJSONSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ae2d1c467d095491b88d8c78a15479ed04bdbae
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/serializers/OFMatchJSONSerializer.java
@@ -0,0 +1,91 @@
+/**
+*    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 org.openflow.protocol.serializers;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import org.openflow.protocol.OFMatch;
+import org.openflow.util.HexString;
+
+public class OFMatchJSONSerializer extends JsonSerializer<OFMatch> {
+
+    /**
+     * Converts an IP in a 32 bit integer to a dotted-decimal string
+     * @param i The IP address in a 32 bit integer
+     * @return An IP address string in dotted-decimal
+     */
+    private String intToIp(int i) {
+        return ((i >> 24 ) & 0xFF) + "." +
+               ((i >> 16 ) & 0xFF) + "." +
+               ((i >>  8 ) & 0xFF) + "." +
+               ( i        & 0xFF);
+    }
+
+    /**
+     * Performs the serialization of a OFMatch object
+     */
+    @Override
+    public void serialize(OFMatch match, JsonGenerator jGen, 
+                                SerializerProvider serializer) 
+                                throws IOException, JsonProcessingException {
+        jGen.writeStartObject();
+        jGen.writeStringField("dataLayerDestination", 
+                    HexString.toHexString(match.getDataLayerDestination()));
+        jGen.writeStringField("dataLayerSource", 
+                    HexString.toHexString(match.getDataLayerSource()));
+        String dataType = Integer.toHexString(match.getDataLayerType());
+        while (dataType.length() < 4) {
+            dataType = "0".concat(dataType);
+        }
+        jGen.writeStringField("dataLayerType", "0x" + dataType);
+        jGen.writeNumberField("dataLayerVirtualLan", 
+                    match.getDataLayerVirtualLan());
+        jGen.writeNumberField("dataLayerVirtualLanPriorityCodePoint", 
+                    match.getDataLayerVirtualLanPriorityCodePoint());
+        jGen.writeNumberField("inputPort", match.getInputPort());
+        jGen.writeStringField("networkDestination", 
+                    intToIp(match.getNetworkDestination()));
+        jGen.writeNumberField("networkDestinationMaskLen", 
+                    match.getNetworkDestinationMaskLen());
+        jGen.writeNumberField("networkProtocol", match.getNetworkProtocol());
+        jGen.writeStringField("networkSource", 
+                    intToIp(match.getNetworkSource()));
+        jGen.writeNumberField("networkSourceMaskLen", 
+                    match.getNetworkSourceMaskLen());
+        jGen.writeNumberField("networkTypeOfService", 
+                    match.getNetworkTypeOfService());
+        jGen.writeNumberField("transportDestination", 
+                    match.getTransportDestination());
+        jGen.writeNumberField("transportSource", 
+                    match.getTransportSource());
+        jGen.writeNumberField("wildcards", match.getWildcards());
+        jGen.writeEndObject();
+    }
+
+    /**
+     * Tells SimpleModule that we are the serializer for OFMatch
+     */
+    @Override
+    public Class<OFMatch> handledType() {
+        return OFMatch.class;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/serializers/StringDpidToLongJSONDeserializer.java b/src/main/java/org/openflow/protocol/serializers/StringDpidToLongJSONDeserializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..60c5a664e828508323c68657ec0663b6ab658152
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/serializers/StringDpidToLongJSONDeserializer.java
@@ -0,0 +1,23 @@
+package org.openflow.protocol.serializers;
+
+import java.io.IOException;
+
+import org.openflow.util.HexString;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
+public class StringDpidToLongJSONDeserializer extends
+    JsonDeserializer<Long> {
+
+    @Override
+    public Long deserialize(JsonParser jsonParser,
+                                       DeserializationContext cntx)
+                                       throws IOException,
+                                       JsonProcessingException {
+        return Long.valueOf(HexString.toLong(jsonParser.getText()));
+    }
+
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsReply.java b/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c86006b0919e1a87120ab96dec2caed96cd48da
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsReply.java
@@ -0,0 +1,130 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_aggregate_stats_reply structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFAggregateStatisticsReply implements OFStatistics {
+    protected long packetCount;
+    protected long byteCount;
+    protected int flowCount;
+
+    /**
+     * @return the packetCount
+     */
+    public long getPacketCount() {
+        return packetCount;
+    }
+
+    /**
+     * @param packetCount the packetCount to set
+     */
+    public void setPacketCount(long packetCount) {
+        this.packetCount = packetCount;
+    }
+
+    /**
+     * @return the byteCount
+     */
+    public long getByteCount() {
+        return byteCount;
+    }
+
+    /**
+     * @param byteCount the byteCount to set
+     */
+    public void setByteCount(long byteCount) {
+        this.byteCount = byteCount;
+    }
+
+    /**
+     * @return the flowCount
+     */
+    public int getFlowCount() {
+        return flowCount;
+    }
+
+    /**
+     * @param flowCount the flowCount to set
+     */
+    public void setFlowCount(int flowCount) {
+        this.flowCount = flowCount;
+    }
+
+    @Override
+    @JsonIgnore
+    public int getLength() {
+        return 24;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.packetCount = data.readLong();
+        this.byteCount = data.readLong();
+        this.flowCount = data.readInt();
+        data.readInt(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeLong(this.packetCount);
+        data.writeLong(this.byteCount);
+        data.writeInt(this.flowCount);
+        data.writeInt(0); // pad
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 397;
+        int result = 1;
+        result = prime * result + (int) (byteCount ^ (byteCount >>> 32));
+        result = prime * result + flowCount;
+        result = prime * result + (int) (packetCount ^ (packetCount >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFAggregateStatisticsReply)) {
+            return false;
+        }
+        OFAggregateStatisticsReply other = (OFAggregateStatisticsReply) obj;
+        if (byteCount != other.byteCount) {
+            return false;
+        }
+        if (flowCount != other.flowCount) {
+            return false;
+        }
+        if (packetCount != other.packetCount) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsRequest.java b/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f41a4f1d57c15a341aeb66f54cc0a87cf011ec61
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFAggregateStatisticsRequest.java
@@ -0,0 +1,135 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFMatch;
+
+/**
+ * Represents an ofp_aggregate_stats_request structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFAggregateStatisticsRequest implements OFStatistics {
+    protected OFMatch match;
+    protected byte tableId;
+    protected short outPort;
+
+    /**
+     * @return the match
+     */
+    public OFMatch getMatch() {
+        return match;
+    }
+
+    /**
+     * @param match the match to set
+     */
+    public void setMatch(OFMatch match) {
+        this.match = match;
+    }
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the outPort
+     */
+    public short getOutPort() {
+        return outPort;
+    }
+
+    /**
+     * @param outPort the outPort to set
+     */
+    public void setOutPort(short outPort) {
+        this.outPort = outPort;
+    }
+
+    @Override
+    public int getLength() {
+        return 44;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.tableId = data.readByte();
+        data.readByte(); // pad
+        this.outPort = data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        this.match.writeTo(data);
+        data.writeByte(this.tableId);
+        data.writeByte((byte) 0);
+        data.writeShort(this.outPort);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 401;
+        int result = 1;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + outPort;
+        result = prime * result + tableId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFAggregateStatisticsRequest)) {
+            return false;
+        }
+        OFAggregateStatisticsRequest other = (OFAggregateStatisticsRequest) obj;
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (outPort != other.outPort) {
+            return false;
+        }
+        if (tableId != other.tableId) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java b/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e6586f0dfd00d71ac89aee183e9cc8e0d299ba8
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java
@@ -0,0 +1,246 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.StringByteSerializer;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * Represents an ofp_desc_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFDescriptionStatistics implements OFStatistics {
+    public static int DESCRIPTION_STRING_LENGTH = 256;
+    public static int SERIAL_NUMBER_LENGTH = 32;
+
+    protected String manufacturerDescription;
+    protected String hardwareDescription;
+    protected String softwareDescription;
+    protected String serialNumber;
+    protected String datapathDescription;
+
+
+    /**
+     *
+     */
+    public OFDescriptionStatistics() {
+    }
+
+    /**
+     * Copy constructor
+     */
+    public OFDescriptionStatistics(OFDescriptionStatistics other) {
+        manufacturerDescription = other.manufacturerDescription;
+        hardwareDescription = other.hardwareDescription;
+        softwareDescription = other.softwareDescription;
+        serialNumber = other.serialNumber;
+        datapathDescription = other.datapathDescription;
+    }
+
+    /**
+     * @return the manufacturerDescription
+     */
+    public String getManufacturerDescription() {
+        return manufacturerDescription;
+    }
+
+    /**
+     * @param manufacturerDescription the manufacturerDescription to set
+     */
+    public void setManufacturerDescription(String manufacturerDescription) {
+        this.manufacturerDescription = manufacturerDescription;
+    }
+
+    /**
+     * @return the hardwareDescription
+     */
+    public String getHardwareDescription() {
+        return hardwareDescription;
+    }
+
+    /**
+     * @param hardwareDescription the hardwareDescription to set
+     */
+    public void setHardwareDescription(String hardwareDescription) {
+        this.hardwareDescription = hardwareDescription;
+    }
+
+    /**
+     * @return the softwareDescription
+     */
+    public String getSoftwareDescription() {
+        return softwareDescription;
+    }
+
+    /**
+     * @param softwareDescription the softwareDescription to set
+     */
+    public void setSoftwareDescription(String softwareDescription) {
+        this.softwareDescription = softwareDescription;
+    }
+
+    /**
+     * @return the serialNumber
+     */
+    public String getSerialNumber() {
+        return serialNumber;
+    }
+
+    /**
+     * @param serialNumber the serialNumber to set
+     */
+    public void setSerialNumber(String serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
+    /**
+     * @return the datapathDescription
+     */
+    public String getDatapathDescription() {
+        return datapathDescription;
+    }
+
+    /**
+     * @param datapathDescription the datapathDescription to set
+     */
+    public void setDatapathDescription(String datapathDescription) {
+        this.datapathDescription = datapathDescription;
+    }
+
+    @Override
+    @JsonIgnore
+    public int getLength() {
+        return 1056;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.manufacturerDescription = StringByteSerializer.readFrom(data,
+                DESCRIPTION_STRING_LENGTH);
+        this.hardwareDescription = StringByteSerializer.readFrom(data,
+                DESCRIPTION_STRING_LENGTH);
+        this.softwareDescription = StringByteSerializer.readFrom(data,
+                DESCRIPTION_STRING_LENGTH);
+        this.serialNumber = StringByteSerializer.readFrom(data,
+                SERIAL_NUMBER_LENGTH);
+        this.datapathDescription = StringByteSerializer.readFrom(data,
+                DESCRIPTION_STRING_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH,
+                this.manufacturerDescription);
+        StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH,
+                this.hardwareDescription);
+        StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH,
+                this.softwareDescription);
+        StringByteSerializer.writeTo(data, SERIAL_NUMBER_LENGTH,
+                this.serialNumber);
+        StringByteSerializer.writeTo(data, DESCRIPTION_STRING_LENGTH,
+                this.datapathDescription);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 409;
+        int result = 1;
+        result = prime
+                * result
+                + ((datapathDescription == null) ? 0 : datapathDescription
+                        .hashCode());
+        result = prime
+                * result
+                + ((hardwareDescription == null) ? 0 : hardwareDescription
+                        .hashCode());
+        result = prime
+                * result
+                + ((manufacturerDescription == null) ? 0
+                        : manufacturerDescription.hashCode());
+        result = prime * result
+                + ((serialNumber == null) ? 0 : serialNumber.hashCode());
+        result = prime
+                * result
+                + ((softwareDescription == null) ? 0 : softwareDescription
+                        .hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFDescriptionStatistics)) {
+            return false;
+        }
+        OFDescriptionStatistics other = (OFDescriptionStatistics) obj;
+        if (datapathDescription == null) {
+            if (other.datapathDescription != null) {
+                return false;
+            }
+        } else if (!datapathDescription.equals(other.datapathDescription)) {
+            return false;
+        }
+        if (hardwareDescription == null) {
+            if (other.hardwareDescription != null) {
+                return false;
+            }
+        } else if (!hardwareDescription.equals(other.hardwareDescription)) {
+            return false;
+        }
+        if (manufacturerDescription == null) {
+            if (other.manufacturerDescription != null) {
+                return false;
+            }
+        } else if (!manufacturerDescription
+                .equals(other.manufacturerDescription)) {
+            return false;
+        }
+        if (serialNumber == null) {
+            if (other.serialNumber != null) {
+                return false;
+            }
+        } else if (!serialNumber.equals(other.serialNumber)) {
+            return false;
+        }
+        if (softwareDescription == null) {
+            if (other.softwareDescription != null) {
+                return false;
+            }
+        } else if (!softwareDescription.equals(other.softwareDescription)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "Switch Desc - Vendor: " +  manufacturerDescription +
+                "  Model: " + hardwareDescription +
+                "  Make: " + datapathDescription +
+                "  Version: " + softwareDescription +
+                "  S/N: " + serialNumber;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java b/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..0aad88df7af5355aabe44df5278cba8fe42f019a
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java
@@ -0,0 +1,359 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.factory.OFActionFactory;
+import org.openflow.protocol.factory.OFActionFactoryAware;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_flow_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFFlowStatisticsReply implements OFStatistics, OFActionFactoryAware {
+    public static int MINIMUM_LENGTH = 88;
+
+    protected OFActionFactory actionFactory;
+    protected short length = (short) MINIMUM_LENGTH;
+    protected byte tableId;
+    protected OFMatch match;
+    protected int durationSeconds;
+    protected int durationNanoseconds;
+    protected short priority;
+    protected short idleTimeout;
+    protected short hardTimeout;
+    protected long cookie;
+    protected long packetCount;
+    protected long byteCount;
+    protected List<OFAction> actions;
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the match
+     */
+    public OFMatch getMatch() {
+        return match;
+    }
+
+    /**
+     * @param match the match to set
+     */
+    public void setMatch(OFMatch match) {
+        this.match = match;
+    }
+
+    /**
+     * @return the durationSeconds
+     */
+    public int getDurationSeconds() {
+        return durationSeconds;
+    }
+
+    /**
+     * @param durationSeconds the durationSeconds to set
+     */
+    public void setDurationSeconds(int durationSeconds) {
+        this.durationSeconds = durationSeconds;
+    }
+
+    /**
+     * @return the durationNanoseconds
+     */
+    public int getDurationNanoseconds() {
+        return durationNanoseconds;
+    }
+
+    /**
+     * @param durationNanoseconds the durationNanoseconds to set
+     */
+    public void setDurationNanoseconds(int durationNanoseconds) {
+        this.durationNanoseconds = durationNanoseconds;
+    }
+
+    /**
+     * @return the priority
+     */
+    public short getPriority() {
+        return priority;
+    }
+
+    /**
+     * @param priority the priority to set
+     */
+    public void setPriority(short priority) {
+        this.priority = priority;
+    }
+
+    /**
+     * @return the idleTimeout
+     */
+    public short getIdleTimeout() {
+        return idleTimeout;
+    }
+
+    /**
+     * @param idleTimeout the idleTimeout to set
+     */
+    public void setIdleTimeout(short idleTimeout) {
+        this.idleTimeout = idleTimeout;
+    }
+
+    /**
+     * @return the hardTimeout
+     */
+    public short getHardTimeout() {
+        return hardTimeout;
+    }
+
+    /**
+     * @param hardTimeout the hardTimeout to set
+     */
+    public void setHardTimeout(short hardTimeout) {
+        this.hardTimeout = hardTimeout;
+    }
+
+    /**
+     * @return the cookie
+     */
+    public long getCookie() {
+        return cookie;
+    }
+
+    /**
+     * @param cookie the cookie to set
+     */
+    public void setCookie(long cookie) {
+        this.cookie = cookie;
+    }
+
+    /**
+     * @return the packetCount
+     */
+    public long getPacketCount() {
+        return packetCount;
+    }
+
+    /**
+     * @param packetCount the packetCount to set
+     */
+    public void setPacketCount(long packetCount) {
+        this.packetCount = packetCount;
+    }
+
+    /**
+     * @return the byteCount
+     */
+    public long getByteCount() {
+        return byteCount;
+    }
+
+    /**
+     * @param byteCount the byteCount to set
+     */
+    public void setByteCount(long byteCount) {
+        this.byteCount = byteCount;
+    }
+
+    /**
+     * @param length the length to set
+     */
+    public void setLength(short length) {
+        this.length = length;
+    }
+
+    @Override
+    @JsonIgnore
+    public int getLength() {
+        return U16.f(length);
+    }
+
+    /**
+     * @param actionFactory the actionFactory to set
+     */
+    @Override
+    public void setActionFactory(OFActionFactory actionFactory) {
+        this.actionFactory = actionFactory;
+    }
+
+    /**
+     * @return the actions
+     */
+    public List<OFAction> getActions() {
+        return actions;
+    }
+
+    /**
+     * @param actions the actions to set
+     */
+    public void setActions(List<OFAction> actions) {
+        this.actions = actions;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.length = data.readShort();
+        this.tableId = data.readByte();
+        data.readByte(); // pad
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.durationSeconds = data.readInt();
+        this.durationNanoseconds = data.readInt();
+        this.priority = data.readShort();
+        this.idleTimeout = data.readShort();
+        this.hardTimeout = data.readShort();
+        data.readInt(); // pad
+        data.readShort(); // pad
+        this.cookie = data.readLong();
+        this.packetCount = data.readLong();
+        this.byteCount = data.readLong();
+        if (this.actionFactory == null)
+            throw new RuntimeException("OFActionFactory not set");
+        this.actions = this.actionFactory.parseActions(data, getLength() -
+                MINIMUM_LENGTH);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.length);
+        data.writeByte(this.tableId);
+        data.writeByte((byte) 0);
+        this.match.writeTo(data);
+        data.writeInt(this.durationSeconds);
+        data.writeInt(this.durationNanoseconds);
+        data.writeShort(this.priority);
+        data.writeShort(this.idleTimeout);
+        data.writeShort(this.hardTimeout);
+        data.writeInt(0); // pad
+        data.writeShort((short)0); // pad
+        data.writeLong(this.cookie);
+        data.writeLong(this.packetCount);
+        data.writeLong(this.byteCount);
+        if (actions != null) {
+            for (OFAction action : actions) {
+                action.writeTo(data);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+    	String str = "match=" + this.match;
+    	str += " tableId=" + this.tableId;
+    	str += " durationSeconds=" + this.durationSeconds;
+    	str += " durationNanoseconds=" + this.durationNanoseconds;
+    	str += " priority=" + this.priority;
+    	str += " idleTimeout=" + this.idleTimeout;
+    	str += " hardTimeout=" + this.hardTimeout;
+        str += " cookie=" + Long.toHexString(this.cookie);
+    	str += " packetCount=" + this.packetCount;
+    	str += " byteCount=" + this.byteCount;
+    	str += " action=" + this.actions;
+    	
+    	return str;
+    }
+    
+    @Override
+    public int hashCode() {
+        final int prime = 419;
+        int result = 1;
+        result = prime * result + (int) (byteCount ^ (byteCount >>> 32));
+        result = prime * result + (int) (cookie ^ (cookie >>> 32));
+        result = prime * result + durationNanoseconds;
+        result = prime * result + durationSeconds;
+        result = prime * result + hardTimeout;
+        result = prime * result + idleTimeout;
+        result = prime * result + length;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + (int) (packetCount ^ (packetCount >>> 32));
+        result = prime * result + priority;
+        result = prime * result + tableId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFFlowStatisticsReply)) {
+            return false;
+        }
+        OFFlowStatisticsReply other = (OFFlowStatisticsReply) obj;
+        if (byteCount != other.byteCount) {
+            return false;
+        }
+        if (cookie != other.cookie) {
+            return false;
+        }
+        if (durationNanoseconds != other.durationNanoseconds) {
+            return false;
+        }
+        if (durationSeconds != other.durationSeconds) {
+            return false;
+        }
+        if (hardTimeout != other.hardTimeout) {
+            return false;
+        }
+        if (idleTimeout != other.idleTimeout) {
+            return false;
+        }
+        if (length != other.length) {
+            return false;
+        }
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (packetCount != other.packetCount) {
+            return false;
+        }
+        if (priority != other.priority) {
+            return false;
+        }
+        if (tableId != other.tableId) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsRequest.java b/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b21de0c7f158298533b3bd8605954ae408282184
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsRequest.java
@@ -0,0 +1,135 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFMatch;
+
+/**
+ * Represents an ofp_flow_stats_request structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFFlowStatisticsRequest implements OFStatistics {
+    protected OFMatch match;
+    protected byte tableId;
+    protected short outPort;
+
+    /**
+     * @return the match
+     */
+    public OFMatch getMatch() {
+        return match;
+    }
+
+    /**
+     * @param match the match to set
+     */
+    public void setMatch(OFMatch match) {
+        this.match = match;
+    }
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the outPort
+     */
+    public short getOutPort() {
+        return outPort;
+    }
+
+    /**
+     * @param outPort the outPort to set
+     */
+    public void setOutPort(short outPort) {
+        this.outPort = outPort;
+    }
+
+    @Override
+    public int getLength() {
+        return 44;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        if (this.match == null)
+            this.match = new OFMatch();
+        this.match.readFrom(data);
+        this.tableId = data.readByte();
+        data.readByte(); // pad
+        this.outPort = data.readShort();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        this.match.writeTo(data);
+        data.writeByte(this.tableId);
+        data.writeByte((byte) 0);
+        data.writeShort(this.outPort);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 421;
+        int result = 1;
+        result = prime * result + ((match == null) ? 0 : match.hashCode());
+        result = prime * result + outPort;
+        result = prime * result + tableId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFFlowStatisticsRequest)) {
+            return false;
+        }
+        OFFlowStatisticsRequest other = (OFFlowStatisticsRequest) obj;
+        if (match == null) {
+            if (other.match != null) {
+                return false;
+            }
+        } else if (!match.equals(other.match)) {
+            return false;
+        }
+        if (outPort != other.outPort) {
+            return false;
+        }
+        if (tableId != other.tableId) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsReply.java b/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..15192bbc4d495fa4fd1f8f064adf0058f348d581
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsReply.java
@@ -0,0 +1,356 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import net.floodlightcontroller.core.web.serializers.UShortSerializer;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_port_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFPortStatisticsReply implements OFStatistics {
+    protected short portNumber;
+    protected long receivePackets;
+    protected long transmitPackets;
+    protected long receiveBytes;
+    protected long transmitBytes;
+    protected long receiveDropped;
+    protected long transmitDropped;
+    protected long receiveErrors;
+    protected long transmitErrors;
+    protected long receiveFrameErrors;
+    protected long receiveOverrunErrors;
+    protected long receiveCRCErrors;
+    protected long collisions;
+
+    /**
+     * @return the portNumber
+     */
+    @JsonSerialize(using=UShortSerializer.class)
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the receivePackets
+     */
+    public long getreceivePackets() {
+        return receivePackets;
+    }
+
+    /**
+     * @param receivePackets the receivePackets to set
+     */
+    public void setreceivePackets(long receivePackets) {
+        this.receivePackets = receivePackets;
+    }
+
+    /**
+     * @return the transmitPackets
+     */
+    public long getTransmitPackets() {
+        return transmitPackets;
+    }
+
+    /**
+     * @param transmitPackets the transmitPackets to set
+     */
+    public void setTransmitPackets(long transmitPackets) {
+        this.transmitPackets = transmitPackets;
+    }
+
+    /**
+     * @return the receiveBytes
+     */
+    public long getReceiveBytes() {
+        return receiveBytes;
+    }
+
+    /**
+     * @param receiveBytes the receiveBytes to set
+     */
+    public void setReceiveBytes(long receiveBytes) {
+        this.receiveBytes = receiveBytes;
+    }
+
+    /**
+     * @return the transmitBytes
+     */
+    public long getTransmitBytes() {
+        return transmitBytes;
+    }
+
+    /**
+     * @param transmitBytes the transmitBytes to set
+     */
+    public void setTransmitBytes(long transmitBytes) {
+        this.transmitBytes = transmitBytes;
+    }
+
+    /**
+     * @return the receiveDropped
+     */
+    public long getReceiveDropped() {
+        return receiveDropped;
+    }
+
+    /**
+     * @param receiveDropped the receiveDropped to set
+     */
+    public void setReceiveDropped(long receiveDropped) {
+        this.receiveDropped = receiveDropped;
+    }
+
+    /**
+     * @return the transmitDropped
+     */
+    public long getTransmitDropped() {
+        return transmitDropped;
+    }
+
+    /**
+     * @param transmitDropped the transmitDropped to set
+     */
+    public void setTransmitDropped(long transmitDropped) {
+        this.transmitDropped = transmitDropped;
+    }
+
+    /**
+     * @return the receiveErrors
+     */
+    public long getreceiveErrors() {
+        return receiveErrors;
+    }
+
+    /**
+     * @param receiveErrors the receiveErrors to set
+     */
+    public void setreceiveErrors(long receiveErrors) {
+        this.receiveErrors = receiveErrors;
+    }
+
+    /**
+     * @return the transmitErrors
+     */
+    public long getTransmitErrors() {
+        return transmitErrors;
+    }
+
+    /**
+     * @param transmitErrors the transmitErrors to set
+     */
+    public void setTransmitErrors(long transmitErrors) {
+        this.transmitErrors = transmitErrors;
+    }
+
+    /**
+     * @return the receiveFrameErrors
+     */
+    public long getReceiveFrameErrors() {
+        return receiveFrameErrors;
+    }
+
+    /**
+     * @param receiveFrameErrors the receiveFrameErrors to set
+     */
+    public void setReceiveFrameErrors(long receiveFrameErrors) {
+        this.receiveFrameErrors = receiveFrameErrors;
+    }
+
+    /**
+     * @return the receiveOverrunErrors
+     */
+    public long getReceiveOverrunErrors() {
+        return receiveOverrunErrors;
+    }
+
+    /**
+     * @param receiveOverrunErrors the receiveOverrunErrors to set
+     */
+    public void setReceiveOverrunErrors(long receiveOverrunErrors) {
+        this.receiveOverrunErrors = receiveOverrunErrors;
+    }
+
+    /**
+     * @return the receiveCRCErrors
+     */
+    public long getReceiveCRCErrors() {
+        return receiveCRCErrors;
+    }
+
+    /**
+     * @param receiveCRCErrors the receiveCRCErrors to set
+     */
+    public void setReceiveCRCErrors(long receiveCRCErrors) {
+        this.receiveCRCErrors = receiveCRCErrors;
+    }
+
+    /**
+     * @return the collisions
+     */
+    public long getCollisions() {
+        return collisions;
+    }
+
+    /**
+     * @param collisions the collisions to set
+     */
+    public void setCollisions(long collisions) {
+        this.collisions = collisions;
+    }
+
+    @Override
+    @JsonIgnore
+    public int getLength() {
+        return 104;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+        data.readInt(); // pad
+        this.receivePackets = data.readLong();
+        this.transmitPackets = data.readLong();
+        this.receiveBytes = data.readLong();
+        this.transmitBytes = data.readLong();
+        this.receiveDropped = data.readLong();
+        this.transmitDropped = data.readLong();
+        this.receiveErrors = data.readLong();
+        this.transmitErrors = data.readLong();
+        this.receiveFrameErrors = data.readLong();
+        this.receiveOverrunErrors = data.readLong();
+        this.receiveCRCErrors = data.readLong();
+        this.collisions = data.readLong();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeShort((short) 0); // pad
+        data.writeInt(0); // pad
+        data.writeLong(this.receivePackets);
+        data.writeLong(this.transmitPackets);
+        data.writeLong(this.receiveBytes);
+        data.writeLong(this.transmitBytes);
+        data.writeLong(this.receiveDropped);
+        data.writeLong(this.transmitDropped);
+        data.writeLong(this.receiveErrors);
+        data.writeLong(this.transmitErrors);
+        data.writeLong(this.receiveFrameErrors);
+        data.writeLong(this.receiveOverrunErrors);
+        data.writeLong(this.receiveCRCErrors);
+        data.writeLong(this.collisions);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 431;
+        int result = 1;
+        result = prime * result + (int) (collisions ^ (collisions >>> 32));
+        result = prime * result + portNumber;
+        result = prime * result
+                + (int) (receivePackets ^ (receivePackets >>> 32));
+        result = prime * result + (int) (receiveBytes ^ (receiveBytes >>> 32));
+        result = prime * result
+                + (int) (receiveCRCErrors ^ (receiveCRCErrors >>> 32));
+        result = prime * result
+                + (int) (receiveDropped ^ (receiveDropped >>> 32));
+        result = prime * result
+                + (int) (receiveFrameErrors ^ (receiveFrameErrors >>> 32));
+        result = prime * result
+                + (int) (receiveOverrunErrors ^ (receiveOverrunErrors >>> 32));
+        result = prime * result
+                + (int) (receiveErrors ^ (receiveErrors >>> 32));
+        result = prime * result
+                + (int) (transmitBytes ^ (transmitBytes >>> 32));
+        result = prime * result
+                + (int) (transmitDropped ^ (transmitDropped >>> 32));
+        result = prime * result
+                + (int) (transmitErrors ^ (transmitErrors >>> 32));
+        result = prime * result
+                + (int) (transmitPackets ^ (transmitPackets >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFPortStatisticsReply)) {
+            return false;
+        }
+        OFPortStatisticsReply other = (OFPortStatisticsReply) obj;
+        if (collisions != other.collisions) {
+            return false;
+        }
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        if (receivePackets != other.receivePackets) {
+            return false;
+        }
+        if (receiveBytes != other.receiveBytes) {
+            return false;
+        }
+        if (receiveCRCErrors != other.receiveCRCErrors) {
+            return false;
+        }
+        if (receiveDropped != other.receiveDropped) {
+            return false;
+        }
+        if (receiveFrameErrors != other.receiveFrameErrors) {
+            return false;
+        }
+        if (receiveOverrunErrors != other.receiveOverrunErrors) {
+            return false;
+        }
+        if (receiveErrors != other.receiveErrors) {
+            return false;
+        }
+        if (transmitBytes != other.transmitBytes) {
+            return false;
+        }
+        if (transmitDropped != other.transmitDropped) {
+            return false;
+        }
+        if (transmitErrors != other.transmitErrors) {
+            return false;
+        }
+        if (transmitPackets != other.transmitPackets) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsRequest.java b/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c07a895afeb355678db7bf7251e12054369c1c92
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFPortStatisticsRequest.java
@@ -0,0 +1,88 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_port_stats_request structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFPortStatisticsRequest implements OFStatistics {
+    protected short portNumber;
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    @Override
+    public int getLength() {
+        return 8;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+        data.readInt(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeShort((short) 0); // pad
+        data.writeInt(0); // pad
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 433;
+        int result = 1;
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFPortStatisticsRequest)) {
+            return false;
+        }
+        OFPortStatisticsRequest other = (OFPortStatisticsRequest) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsReply.java b/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..34a9e18200bc73ff5a7d628c671bb641cd243068
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsReply.java
@@ -0,0 +1,175 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_queue_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFQueueStatisticsReply implements OFStatistics {
+    protected short portNumber;
+    protected int queueId;
+    protected long transmitBytes;
+    protected long transmitPackets;
+    protected long transmitErrors;
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the queueId
+     */
+    public int getQueueId() {
+        return queueId;
+    }
+
+    /**
+     * @param queueId the queueId to set
+     */
+    public void setQueueId(int queueId) {
+        this.queueId = queueId;
+    }
+
+    /**
+     * @return the transmitBytes
+     */
+    public long getTransmitBytes() {
+        return transmitBytes;
+    }
+
+    /**
+     * @param transmitBytes the transmitBytes to set
+     */
+    public void setTransmitBytes(long transmitBytes) {
+        this.transmitBytes = transmitBytes;
+    }
+
+    /**
+     * @return the transmitPackets
+     */
+    public long getTransmitPackets() {
+        return transmitPackets;
+    }
+
+    /**
+     * @param transmitPackets the transmitPackets to set
+     */
+    public void setTransmitPackets(long transmitPackets) {
+        this.transmitPackets = transmitPackets;
+    }
+
+    /**
+     * @return the transmitErrors
+     */
+    public long getTransmitErrors() {
+        return transmitErrors;
+    }
+
+    /**
+     * @param transmitErrors the transmitErrors to set
+     */
+    public void setTransmitErrors(long transmitErrors) {
+        this.transmitErrors = transmitErrors;
+    }
+
+    @Override
+    @JsonIgnore
+    public int getLength() {
+        return 32;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+        this.queueId = data.readInt();
+        this.transmitBytes = data.readLong();
+        this.transmitPackets = data.readLong();
+        this.transmitErrors = data.readLong();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeShort((short) 0); // pad
+        data.writeInt(this.queueId);
+        data.writeLong(this.transmitBytes);
+        data.writeLong(this.transmitPackets);
+        data.writeLong(this.transmitErrors);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 439;
+        int result = 1;
+        result = prime * result + portNumber;
+        result = prime * result + queueId;
+        result = prime * result
+                + (int) (transmitBytes ^ (transmitBytes >>> 32));
+        result = prime * result
+                + (int) (transmitErrors ^ (transmitErrors >>> 32));
+        result = prime * result
+                + (int) (transmitPackets ^ (transmitPackets >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueStatisticsReply)) {
+            return false;
+        }
+        OFQueueStatisticsReply other = (OFQueueStatisticsReply) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        if (queueId != other.queueId) {
+            return false;
+        }
+        if (transmitBytes != other.transmitBytes) {
+            return false;
+        }
+        if (transmitErrors != other.transmitErrors) {
+            return false;
+        }
+        if (transmitPackets != other.transmitPackets) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsRequest.java b/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..33314539f62b1bbb21e59a92c07712e653b2584e
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFQueueStatisticsRequest.java
@@ -0,0 +1,107 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Represents an ofp_queue_stats_request structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFQueueStatisticsRequest implements OFStatistics {
+    protected short portNumber;
+    protected int queueId;
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the queueId
+     */
+    public int getQueueId() {
+        return queueId;
+    }
+
+    /**
+     * @param queueId the queueId to set
+     */
+    public void setQueueId(int queueId) {
+        this.queueId = queueId;
+    }
+
+    @Override
+    public int getLength() {
+        return 8;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+        this.queueId = data.readInt();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.portNumber);
+        data.writeShort((short) 0); // pad
+        data.writeInt(this.queueId);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 443;
+        int result = 1;
+        result = prime * result + portNumber;
+        result = prime * result + queueId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueStatisticsRequest)) {
+            return false;
+        }
+        OFQueueStatisticsRequest other = (OFQueueStatisticsRequest) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        if (queueId != other.queueId) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFStatistics.java b/src/main/java/org/openflow/protocol/statistics/OFStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e8f4dd3f84949b602f977d3c983a81af0e04383
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFStatistics.java
@@ -0,0 +1,45 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * The base class for all OpenFlow statistics.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu) - Mar 11, 2010
+ */
+public interface OFStatistics {
+    /**
+     * Returns the wire length of this message in bytes
+     * @return the length
+     */
+    public int getLength();
+
+    /**
+     * Read this message off the wire from the specified ByteBuffer
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data);
+
+    /**
+     * Write this message's binary format to the specified ByteBuffer
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data);
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFStatisticsType.java b/src/main/java/org/openflow/protocol/statistics/OFStatisticsType.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2b9e3015263345a44bac8c9ffbc88c1a6d4fe5b
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFStatisticsType.java
@@ -0,0 +1,317 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+import java.lang.reflect.Constructor;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.OFType;
+
+public enum OFStatisticsType {
+    DESC        (0, OFDescriptionStatistics.class, OFDescriptionStatistics.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFDescriptionStatistics();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFDescriptionStatistics();
+                        }
+                    }),
+    FLOW       (1, OFFlowStatisticsRequest.class, OFFlowStatisticsReply.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFFlowStatisticsRequest();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFFlowStatisticsReply();
+                        }
+                    }),
+    AGGREGATE  (2, OFAggregateStatisticsRequest.class, OFAggregateStatisticsReply.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFAggregateStatisticsRequest();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFAggregateStatisticsReply();
+                        }
+                    }),
+    TABLE      (3, OFTableStatistics.class, OFTableStatistics.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFTableStatistics();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFTableStatistics();
+                        }
+                    }),
+    PORT       (4, OFPortStatisticsRequest.class, OFPortStatisticsReply.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFPortStatisticsRequest();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFPortStatisticsReply();
+                        }
+                    }),
+    QUEUE      (5, OFQueueStatisticsRequest.class, OFQueueStatisticsReply.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFQueueStatisticsRequest();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFQueueStatisticsReply();
+                        }
+                    }),
+    VENDOR     (0xffff, OFVendorStatistics.class, OFVendorStatistics.class,
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFVendorStatistics();
+                        }
+                    },
+                    new Instantiable<OFStatistics>() {
+                        @Override
+                        public OFStatistics instantiate() {
+                            return new OFVendorStatistics();
+                        }
+                    });
+
+    static OFStatisticsType[] requestMapping;
+    static OFStatisticsType[] replyMapping;
+
+    protected Class<? extends OFStatistics> requestClass;
+    protected Constructor<? extends OFStatistics> requestConstructor;
+    protected Instantiable<OFStatistics> requestInstantiable;
+    protected Class<? extends OFStatistics> replyClass;
+    protected Constructor<? extends OFStatistics> replyConstructor;
+    protected Instantiable<OFStatistics> replyInstantiable;
+    protected short type;
+
+    /**
+     * Store some information about the OpenFlow Statistic type, including wire
+     * protocol type number, and derived class
+     *
+     * @param type Wire protocol number associated with this OFStatisticsType
+     * @param requestClass The Statistics Java class to return when the
+     *                     containing OFType is STATS_REQUEST
+     * @param replyClass   The Statistics Java class to return when the
+     *                     containing OFType is STATS_REPLY
+     */
+    OFStatisticsType(int type, Class<? extends OFStatistics> requestClass,
+            Class<? extends OFStatistics> replyClass,
+            Instantiable<OFStatistics> requestInstantiable,
+            Instantiable<OFStatistics> replyInstantiable) {
+        this.type = (short) type;
+        this.requestClass = requestClass;
+        try {
+            this.requestConstructor = requestClass.getConstructor(new Class[]{});
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Failure getting constructor for class: " + requestClass, e);
+        }
+
+        this.replyClass = replyClass;
+        try {
+            this.replyConstructor = replyClass.getConstructor(new Class[]{});
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Failure getting constructor for class: " + replyClass, e);
+        }
+        this.requestInstantiable = requestInstantiable;
+        this.replyInstantiable = replyInstantiable;
+        OFStatisticsType.addMapping(this.type, OFType.STATS_REQUEST, this);
+        OFStatisticsType.addMapping(this.type, OFType.STATS_REPLY, this);
+    }
+
+    /**
+     * Adds a mapping from type value to OFStatisticsType enum
+     *
+     * @param i OpenFlow wire protocol type
+     * @param t type of containing OFMessage, only accepts STATS_REQUEST or
+     *          STATS_REPLY
+     * @param st type
+     */
+    static public void addMapping(short i, OFType t, OFStatisticsType st) {
+        if (i < 0)
+            i = (short) (16+i);
+        if (t == OFType.STATS_REQUEST) {
+            if (requestMapping == null)
+                requestMapping = new OFStatisticsType[16];
+            OFStatisticsType.requestMapping[i] = st;
+        } else if (t == OFType.STATS_REPLY){
+            if (replyMapping == null)
+                replyMapping = new OFStatisticsType[16];
+            OFStatisticsType.replyMapping[i] = st;
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * Remove a mapping from type value to OFStatisticsType enum
+     *
+     * @param i OpenFlow wire protocol type
+     * @param t type of containing OFMessage, only accepts STATS_REQUEST or
+     *          STATS_REPLY
+     */
+    static public void removeMapping(short i, OFType t) {
+        if (i < 0)
+            i = (short) (16+i);
+        if (t == OFType.STATS_REQUEST) {
+            requestMapping[i] = null;
+        } else if (t == OFType.STATS_REPLY){
+            replyMapping[i] = null;
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * Given a wire protocol OpenFlow type number, return the OFStatisticsType
+     * associated with it
+     *
+     * @param i wire protocol number
+     * @param t type of containing OFMessage, only accepts STATS_REQUEST or
+     *          STATS_REPLY
+     * @return OFStatisticsType enum type
+     */
+    static public OFStatisticsType valueOf(short i, OFType t) {
+        if (i < 0)
+            i = (short) (16+i);
+        if (t == OFType.STATS_REQUEST) {
+            return requestMapping[i];
+        } else if (t == OFType.STATS_REPLY){
+            return replyMapping[i];
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * @return Returns the wire protocol value corresponding to this
+     * OFStatisticsType
+     */
+    public short getTypeValue() {
+        return this.type;
+    }
+
+    /**
+     * @param t type of containing OFMessage, only accepts STATS_REQUEST or
+     *          STATS_REPLY
+     * @return return the OFMessage subclass corresponding to this
+     *                OFStatisticsType
+     */
+    public Class<? extends OFStatistics> toClass(OFType t) {
+        if (t == OFType.STATS_REQUEST) {
+            return requestClass;
+        } else if (t == OFType.STATS_REPLY){
+            return replyClass;
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * Returns the no-argument Constructor of the implementation class for
+     * this OFStatisticsType, either request or reply based on the supplied
+     * OFType
+     *
+     * @param t
+     * @return
+     */
+    public Constructor<? extends OFStatistics> getConstructor(OFType t) {
+        if (t == OFType.STATS_REQUEST) {
+            return requestConstructor;
+        } else if (t == OFType.STATS_REPLY) {
+            return replyConstructor;
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+
+    /**
+     * @return the requestInstantiable
+     */
+    public Instantiable<OFStatistics> getRequestInstantiable() {
+        return requestInstantiable;
+    }
+
+    /**
+     * @param requestInstantiable the requestInstantiable to set
+     */
+    public void setRequestInstantiable(
+            Instantiable<OFStatistics> requestInstantiable) {
+        this.requestInstantiable = requestInstantiable;
+    }
+
+    /**
+     * @return the replyInstantiable
+     */
+    public Instantiable<OFStatistics> getReplyInstantiable() {
+        return replyInstantiable;
+    }
+
+    /**
+     * @param replyInstantiable the replyInstantiable to set
+     */
+    public void setReplyInstantiable(Instantiable<OFStatistics> replyInstantiable) {
+        this.replyInstantiable = replyInstantiable;
+    }
+
+    /**
+     * Returns a new instance of the implementation class for
+     * this OFStatisticsType, either request or reply based on the supplied
+     * OFType
+     *
+     * @param t
+     * @return
+     */
+    public OFStatistics newInstance(OFType t) {
+        if (t == OFType.STATS_REQUEST) {
+            return requestInstantiable.instantiate();
+        } else if (t == OFType.STATS_REPLY) {
+            return replyInstantiable.instantiate();
+        } else {
+            throw new RuntimeException(t.toString() + " is an invalid OFType");
+        }
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFTableStatistics.java b/src/main/java/org/openflow/protocol/statistics/OFTableStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e6d34e10bdfa16cf7f75be64d03eab22f86b26e
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFTableStatistics.java
@@ -0,0 +1,223 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.StringByteSerializer;
+
+/**
+ * Represents an ofp_table_stats structure
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFTableStatistics implements OFStatistics {
+    public static int MAX_TABLE_NAME_LEN = 32;
+
+    protected byte tableId;
+    protected String name;
+    protected int wildcards;
+    protected int maximumEntries;
+    protected int activeCount;
+    protected long lookupCount;
+    protected long matchedCount;
+
+    /**
+     * @return the tableId
+     */
+    public byte getTableId() {
+        return tableId;
+    }
+
+    /**
+     * @param tableId the tableId to set
+     */
+    public void setTableId(byte tableId) {
+        this.tableId = tableId;
+    }
+
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the wildcards
+     */
+    public int getWildcards() {
+        return wildcards;
+    }
+
+    /**
+     * @param wildcards the wildcards to set
+     */
+    public void setWildcards(int wildcards) {
+        this.wildcards = wildcards;
+    }
+
+    /**
+     * @return the maximumEntries
+     */
+    public int getMaximumEntries() {
+        return maximumEntries;
+    }
+
+    /**
+     * @param maximumEntries the maximumEntries to set
+     */
+    public void setMaximumEntries(int maximumEntries) {
+        this.maximumEntries = maximumEntries;
+    }
+
+    /**
+     * @return the activeCount
+     */
+    public int getActiveCount() {
+        return activeCount;
+    }
+
+    /**
+     * @param activeCount the activeCount to set
+     */
+    public void setActiveCount(int activeCount) {
+        this.activeCount = activeCount;
+    }
+
+    /**
+     * @return the lookupCount
+     */
+    public long getLookupCount() {
+        return lookupCount;
+    }
+
+    /**
+     * @param lookupCount the lookupCount to set
+     */
+    public void setLookupCount(long lookupCount) {
+        this.lookupCount = lookupCount;
+    }
+
+    /**
+     * @return the matchedCount
+     */
+    public long getMatchedCount() {
+        return matchedCount;
+    }
+
+    /**
+     * @param matchedCount the matchedCount to set
+     */
+    public void setMatchedCount(long matchedCount) {
+        this.matchedCount = matchedCount;
+    }
+
+    @Override
+    public int getLength() {
+        return 64;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.tableId = data.readByte();
+        data.readByte(); // pad
+        data.readByte(); // pad
+        data.readByte(); // pad
+        this.name = StringByteSerializer.readFrom(data, MAX_TABLE_NAME_LEN);
+        this.wildcards = data.readInt();
+        this.maximumEntries = data.readInt();
+        this.activeCount = data.readInt();
+        this.lookupCount = data.readLong();
+        this.matchedCount = data.readLong();
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeByte(this.tableId);
+        data.writeByte((byte) 0); // pad
+        data.writeByte((byte) 0); // pad
+        data.writeByte((byte) 0); // pad
+        StringByteSerializer.writeTo(data, MAX_TABLE_NAME_LEN, this.name);
+        data.writeInt(this.wildcards);
+        data.writeInt(this.maximumEntries);
+        data.writeInt(this.activeCount);
+        data.writeLong(this.lookupCount);
+        data.writeLong(this.matchedCount);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 449;
+        int result = 1;
+        result = prime * result + activeCount;
+        result = prime * result + (int) (lookupCount ^ (lookupCount >>> 32));
+        result = prime * result + (int) (matchedCount ^ (matchedCount >>> 32));
+        result = prime * result + maximumEntries;
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + tableId;
+        result = prime * result + wildcards;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFTableStatistics)) {
+            return false;
+        }
+        OFTableStatistics other = (OFTableStatistics) obj;
+        if (activeCount != other.activeCount) {
+            return false;
+        }
+        if (lookupCount != other.lookupCount) {
+            return false;
+        }
+        if (matchedCount != other.matchedCount) {
+            return false;
+        }
+        if (maximumEntries != other.maximumEntries) {
+            return false;
+        }
+        if (name == null) {
+            if (other.name != null) {
+                return false;
+            }
+        } else if (!name.equals(other.name)) {
+            return false;
+        }
+        if (tableId != other.tableId) {
+            return false;
+        }
+        if (wildcards != other.wildcards) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/statistics/OFVendorStatistics.java b/src/main/java/org/openflow/protocol/statistics/OFVendorStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..0257a6aab024ef55ab6b8b7d0f80a473b806ebfc
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/statistics/OFVendorStatistics.java
@@ -0,0 +1,83 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol.statistics;
+
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * The base class for vendor implemented statistics
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFVendorStatistics implements OFStatistics {
+    protected int vendor;
+    protected byte[] body;
+
+    // non-message fields
+    protected int length = 0;
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        this.vendor = data.readInt();
+        if (body == null)
+            body = new byte[length - 4];
+        data.readBytes(body);
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(this.vendor);
+        if (body != null)
+            data.writeBytes(body);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 457;
+        int result = 1;
+        result = prime * result + vendor;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof OFVendorStatistics)) {
+            return false;
+        }
+        OFVendorStatistics other = (OFVendorStatistics) obj;
+        if (vendor != other.vendor) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int getLength() {
+        return length;
+    }
+
+    public void setLength(int length) {
+        this.length = length;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java b/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f0e14b2dd4b6dac9f5dadc5d5c9e6a0b4a1a4a5
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/vendor/OFBasicVendorDataType.java
@@ -0,0 +1,71 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import org.openflow.protocol.Instantiable;
+
+/**
+ * Subclass of OFVendorDataType that works with any vendor data format that
+ * begins with a integral value to indicate the format of the remaining data.
+ * It maps from the per-vendor-id integral data type code to the object
+ * used to instantiate the class associated with that vendor data type.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFBasicVendorDataType extends OFVendorDataType {
+    
+    /**
+     * The data type value at the beginning of the vendor data.
+     */
+    protected long type;
+    
+    /**
+     * Construct an empty (i.e. no specified data type value) vendor data type.
+     */
+    public OFBasicVendorDataType() {
+        super();
+        this.type = 0;
+    }
+    
+    /**
+     * Store some information about the vendor data type, including wire protocol
+     * type number, derived class and instantiator.
+     *
+     * @param type Wire protocol number associated with this vendor data type
+     * @param instantiator An Instantiator<OFVendorData> implementation that
+     *              creates an instance of an appropriate subclass of OFVendorData.
+     */
+    public OFBasicVendorDataType(long type, Instantiable<OFVendorData> instantiator) {
+        super(instantiator);
+        this.type = type;
+    }
+
+    /**
+     * @return Returns the wire protocol value corresponding to this OFVendorDataType
+     */
+    public long getTypeValue() {
+        return this.type;
+    }
+    
+    /**
+     * @param type the wire protocol value for this data type
+     */
+    public void setTypeValue(long type) {
+        this.type = type;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java b/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f789dc3f9a661c8dc84d74904b209e004bef215
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/vendor/OFBasicVendorId.java
@@ -0,0 +1,162 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.Instantiable;
+
+/**
+ * Basic subclass of OFVendorId that works with any vendor data format where
+ * the data begins with an integral data type value.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFBasicVendorId extends OFVendorId {
+    
+    /**
+     * The size of the data type value at the beginning of all vendor
+     * data associated with this vendor id. The data type size must be
+     * either 1, 2, 4 or 8.
+     */
+    protected int dataTypeSize;
+    
+    /**
+     * Map of the vendor data types that have been registered for this
+     * vendor id.
+     */
+    protected Map<Long, OFBasicVendorDataType> dataTypeMap =
+            new HashMap<Long, OFBasicVendorDataType>();
+    
+    /**
+     * Construct an OFVendorId that where the vendor data begins
+     * with a data type value whose size is dataTypeSize.
+     * @param id the id of the vendor, typically the OUI of a vendor
+     *     prefixed with 0.
+     * @param dataTypeSize the size of the integral data type value
+     *     at the beginning of the vendor data. The value must be the
+     *     size of an integeral data type (i.e. either 1,2,4 or 8).
+     */
+    public OFBasicVendorId(int id, int dataTypeSize) {
+        super(id);
+        assert (dataTypeSize == 1) || (dataTypeSize == 2) ||
+               (dataTypeSize == 4) || (dataTypeSize == 8);
+        this.dataTypeSize = dataTypeSize;
+    }
+
+    /**
+     * Get the size of the data type value at the beginning of the vendor
+     * data. OFBasicVendorId assumes that this value is common across all of
+     * the vendor data formats associated with a given vendor id.
+     * @return
+     */
+    public int getDataTypeSize() {
+        return dataTypeSize;
+    }
+    
+    /**
+     * Register a vendor data type with this vendor id.
+     * @param vendorDataType
+     */
+    public void registerVendorDataType(OFBasicVendorDataType vendorDataType) {
+        dataTypeMap.put(vendorDataType.getTypeValue(), vendorDataType);
+    }
+    
+    /**
+     * Lookup the OFVendorDataType instance that has been registered with
+     * this vendor id.
+     * 
+     * @param vendorDataType the integer code that was parsed from the 
+     * @return
+     */
+    public OFVendorDataType lookupVendorDataType(int vendorDataType) {
+        return dataTypeMap.get(Long.valueOf(vendorDataType));
+    }
+
+    /**
+     * This function parses enough of the data from the buffer to be able
+     * to determine the appropriate OFVendorDataType for the data. It is meant
+     * to be a reasonably generic implementation that will work for most
+     * formats of vendor extensions. If the vendor data doesn't fit the
+     * assumptions listed below, then this method will need to be overridden
+     * to implement custom parsing.
+     * 
+     * This implementation assumes that the vendor data begins with a data
+     * type code that is used to distinguish different formats of vendor
+     * data associated with a particular vendor ID.
+     * The exact format of the data is vendor-defined, so we don't know how
+     * how big the code is (or really even if there is a code). This code
+     * assumes that the common case will be that the data does include
+     * an initial type code (i.e. so that the vendor can have multiple
+     * message/data types) and that the size is either 1, 2 or 4 bytes.
+     * The size of the initial type code is configured by the subclass of
+     * OFVendorId.
+     * 
+     * @param data the channel buffer containing the vendor data.
+     * @param length the length to the end of the enclosing message
+     * @return the OFVendorDataType that can be used to instantiate the
+     *         appropriate subclass of OFVendorData.
+     */
+    public OFVendorDataType parseVendorDataType(ChannelBuffer data, int length) {
+        OFVendorDataType vendorDataType = null;
+        
+        // Parse out the type code from the vendor data.
+        long dataTypeValue = 0;
+        if ((length == 0) || (length >= dataTypeSize)) {
+            switch (dataTypeSize) {
+                case 1:
+                    dataTypeValue = data.readByte();
+                    break;
+                case 2:
+                    dataTypeValue = data.readShort();
+                    break;
+                case 4:
+                    dataTypeValue = data.readInt();
+                    break;
+                case 8:
+                    dataTypeValue = data.readLong();
+                    break;
+                default:
+                    // This would be indicative of a coding error where the
+                    // dataTypeSize was specified incorrectly. This should have been
+                    // caught in the constructor for OFVendorId.
+                    assert false;
+            }
+            
+            vendorDataType = dataTypeMap.get(dataTypeValue);
+        }
+        
+        // If we weren't able to parse/map the data to a known OFVendorDataType,
+        // then map it to a generic vendor data type.
+        if (vendorDataType == null) {
+            vendorDataType = new OFBasicVendorDataType(dataTypeValue,
+                new Instantiable<OFVendorData>() {
+                    @Override
+                    public OFVendorData instantiate() {
+                        return new OFByteArrayVendorData();
+                    }
+                }
+            );
+        }
+        
+        return vendorDataType;
+    }
+
+}
diff --git a/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java b/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..08fa003172312af1569daf4eb83700fca177df2e
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/vendor/OFByteArrayVendorData.java
@@ -0,0 +1,94 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Basic implementation of OFVendorData that just treats the data as a
+ * byte array. This is used if there's an OFVendor message where there's
+ * no registered OFVendorId or no specific OFVendorDataType that can be
+ * determined from the data.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFByteArrayVendorData implements OFVendorData {
+
+    protected byte[] bytes;
+    
+    /**
+     * Construct vendor data with an empty byte array.
+     */
+    public OFByteArrayVendorData() {
+    }
+    
+    /**
+     * Construct vendor data with the specified byte array.
+     * @param bytes
+     */
+    public OFByteArrayVendorData(byte[] bytes) {
+        this.bytes = bytes;
+    }
+    
+    /**
+     * Get the associated byte array for this vendor data.
+     * @return the byte array containing the raw vendor data.
+     */
+    public byte[] getBytes() {
+        return bytes;
+    }
+    
+    /**
+     * Set the byte array for the vendor data.
+     * @param bytes the raw byte array containing the vendor data.
+     */
+    public void setBytes(byte[] bytes) {
+        this.bytes = bytes;
+    }
+    
+    /**
+     * Get the length of the vendor data. In this case it's just then length
+     * of the underlying byte array.
+     * @return the length of the vendor data
+     */
+    @Override
+    public int getLength() {
+        return (bytes != null) ? bytes.length : 0;
+    }
+
+    /**
+     * Read the vendor data from the ChannelBuffer into the byte array.
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    @Override
+    public void readFrom(ChannelBuffer data, int length) {
+        bytes = new byte[length];
+        data.readBytes(bytes);
+    }
+
+    /**
+     * Write the vendor data bytes to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        if (bytes != null)
+            data.writeBytes(bytes);
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/vendor/OFVendorData.java b/src/main/java/org/openflow/protocol/vendor/OFVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..6dfb4e6cb62b170e83b28678ac5c0669f3d6610a
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/vendor/OFVendorData.java
@@ -0,0 +1,44 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * The base class for all vendor data.
+ *
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public interface OFVendorData {
+    /**
+     * @return length of the data
+     */
+    public int getLength();
+    
+    /**
+     * Read the vendor data from the specified ChannelBuffer
+     * @param data
+     */
+    public void readFrom(ChannelBuffer data, int length);
+
+    /**
+     * Write the vendor data to the specified ChannelBuffer
+     * @param data
+     */
+    public void writeTo(ChannelBuffer data);
+}
diff --git a/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java b/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java
new file mode 100644
index 0000000000000000000000000000000000000000..ecae4823925750fc8e4f6becb9d4249b1c567f85
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/vendor/OFVendorDataType.java
@@ -0,0 +1,79 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import org.openflow.protocol.Instantiable;
+
+/**
+ * Class that represents a specific vendor data type format in an
+ * OFVendor message. Typically the vendor data will begin with an integer
+ * code that determines the format of the rest of the data, but this
+ * class does not assume that. It's basically just a holder for an
+ * instantiator of the appropriate subclass of OFVendorData.
+ *
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFVendorDataType {
+
+    /**
+     * Object that instantiates the subclass of OFVendorData 
+     * associated with this data type.
+     */
+    protected Instantiable<OFVendorData> instantiable;
+
+    /**
+     * Construct an empty vendor data type.
+     */
+    public OFVendorDataType() {
+        super();
+    }
+
+    /**
+     * Construct a vendor data type with the specified instantiable.
+     * @param instantiable object that creates the subclass of OFVendorData
+     *     associated with this data type.
+     */
+    public OFVendorDataType(Instantiable<OFVendorData> instantiable) {
+        this.instantiable = instantiable;
+    }
+    
+    /**
+     * Returns a new instance of a subclass of OFVendorData associated with
+     * this OFVendorDataType.
+     * 
+     * @return the new object
+     */
+    public OFVendorData newInstance() {
+        return instantiable.instantiate();
+    }
+
+    /**
+     * @return the instantiable
+     */
+    public Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * @param instantiable the instantiable to set
+     */
+    public void setInstantiable(Instantiable<OFVendorData> instantiable) {
+        this.instantiable = instantiable;
+    }
+
+}
diff --git a/src/main/java/org/openflow/protocol/vendor/OFVendorId.java b/src/main/java/org/openflow/protocol/vendor/OFVendorId.java
new file mode 100644
index 0000000000000000000000000000000000000000..f0af8a7635088c21bd889dc0632c481fb61350ab
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/vendor/OFVendorId.java
@@ -0,0 +1,85 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.protocol.vendor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Base class for the vendor ID corresponding to vendor extensions from a
+ * given vendor. It is responsible for knowing how to parse out some sort of
+ * data type value from the vendor data in an OFVendor message so that we can
+ * dispatch to the different subclasses of OFVendorData corresponding to the
+ * different formats of data for the vendor extensions.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public abstract class OFVendorId {
+    static Map<Integer, OFVendorId> mapping = new HashMap<Integer, OFVendorId>();
+
+    /**
+     * The vendor id value, typically the OUI of the vendor prefixed with 0.
+     */
+    protected int id;
+    
+    /**
+     * Register a new vendor id.
+     * @param vendorId the vendor id to register
+     */
+    public static void registerVendorId(OFVendorId vendorId) {
+        mapping.put(vendorId.getId(), vendorId);
+    }
+    
+    /**
+     * Lookup the OFVendorId instance corresponding to the given id value.
+     * @param id the integer vendor id value
+     * @return the corresponding OFVendorId that's been registered for the
+     *     given value, or null if there id has not been registered.
+     */
+    public static OFVendorId lookupVendorId(int id) {
+        return mapping.get(id);
+    }
+    
+    /**
+     * Create an OFVendorId with the give vendor id value
+     * @param id
+     */
+    public OFVendorId(int id) {
+        this.id = id;
+    }
+    
+    /**
+     * @return the vendor id value
+     */
+    public int getId() {
+        return id;
+    }
+    
+    /**
+     * This function parses enough of the data from the channel buffer to be
+     * able to determine the appropriate OFVendorDataType for the data.
+     * 
+     * @param data the channel buffer containing the vendor data.
+     * @param length the length to the end of the enclosing message
+     * @return the OFVendorDataType that can be used to instantiate the
+     *         appropriate subclass of OFVendorData.
+     */
+    public abstract OFVendorDataType parseVendorDataType(ChannelBuffer data, int length);
+}
diff --git a/src/main/java/org/openflow/util/HexString.java b/src/main/java/org/openflow/util/HexString.java
new file mode 100644
index 0000000000000000000000000000000000000000..b5628242dadcbc7a12ccd8568f9c00b319439783
--- /dev/null
+++ b/src/main/java/org/openflow/util/HexString.java
@@ -0,0 +1,93 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import java.math.BigInteger;
+
+public class HexString {
+    /**
+     * Convert a string of bytes to a ':' separated hex string
+     * @param bytes
+     * @return "0f:ca:fe:de:ad:be:ef"
+     */
+    public static String toHexString(byte[] bytes) {
+        if (bytes == null) return "";
+        int i;
+        String ret = "";
+        String tmp;
+        for(i=0; i< bytes.length; i++) {
+            if(i> 0)
+                ret += ":";
+            tmp = Integer.toHexString(U8.f(bytes[i]));
+            if (tmp.length() == 1)
+                ret += "0";
+            ret += tmp; 
+        }
+        return ret;
+    }
+    
+    public static String toHexString(long val, int padTo) {
+        char arr[] = Long.toHexString(val).toCharArray();
+        String ret = "";
+        // prepend the right number of leading zeros
+        int i = 0;
+        for (; i < (padTo * 2 - arr.length); i++) {
+            ret += "0";
+            if ((i % 2) != 0)
+                ret += ":";
+        }
+        for (int j = 0; j < arr.length; j++) {
+            ret += arr[j];
+            if ((((i + j) % 2) != 0) && (j < (arr.length - 1)))
+                ret += ":";
+        }
+        return ret;        
+    }
+   
+    public static String toHexString(long val) {
+        return toHexString(val, 8);
+    }
+    
+    
+    /**
+     * Convert a string of hex values into a string of bytes
+     * @param values "0f:ca:fe:de:ad:be:ef"
+     * @return [15, 5 ,2, 5, 17] 
+     * @throws NumberFormatException If the string can not be parsed
+     */ 
+    public static byte[] fromHexString(String values) throws NumberFormatException {
+        String[] octets = values.split(":");
+        byte[] ret = new byte[octets.length];
+        
+        for(int i = 0; i < octets.length; i++) {
+            if (octets[i].length() > 2)
+                throw new NumberFormatException("Invalid octet length");
+            ret[i] = Integer.valueOf(octets[i], 16).byteValue();
+        }
+        return ret;
+    }
+    
+    public static long toLong(String values) throws NumberFormatException {
+        // Long.parseLong() can't handle HexStrings with MSB set. Sigh. 
+        BigInteger bi = new BigInteger(values.replaceAll(":", ""),16);
+        if (bi.bitLength() > 64) 
+            throw new NumberFormatException("Input string too big to fit in long: " + values);
+        return bi.longValue();
+    }
+
+}
diff --git a/src/main/java/org/openflow/util/IProducer.java b/src/main/java/org/openflow/util/IProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..52ae79a52b5dc47af63f71d0aceeb3ee26105727
--- /dev/null
+++ b/src/main/java/org/openflow/util/IProducer.java
@@ -0,0 +1,9 @@
+package org.openflow.util;
+
+public interface IProducer {
+
+    public void registerConsumer(Class<?> iface, Object anObj);
+
+    public void deregisterConsumer(Class<?> iface, Object anObj);
+
+}
diff --git a/src/main/java/org/openflow/util/LRULinkedHashMap.java b/src/main/java/org/openflow/util/LRULinkedHashMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f05381c20bbe04760714cd8a45f3d50907c1558
--- /dev/null
+++ b/src/main/java/org/openflow/util/LRULinkedHashMap.java
@@ -0,0 +1,42 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import java.util.LinkedHashMap;
+
+public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
+    private static final long serialVersionUID = -2964986094089626647L;
+    protected int maximumCapacity;
+
+    public LRULinkedHashMap(int initialCapacity, int maximumCapacity) {
+        super(initialCapacity, 0.75f, true);
+        this.maximumCapacity = maximumCapacity;
+    }
+
+    public LRULinkedHashMap(int maximumCapacity) {
+        super(16, 0.75f, true);
+        this.maximumCapacity = maximumCapacity;
+    }
+
+    @Override
+    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
+        if (this.size() > maximumCapacity)
+            return true;
+        return false;
+    }
+}
diff --git a/src/main/java/org/openflow/util/ProducerConsumer.java b/src/main/java/org/openflow/util/ProducerConsumer.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2244ef3524483b0a2fc70e8f2ba433efd363c01
--- /dev/null
+++ b/src/main/java/org/openflow/util/ProducerConsumer.java
@@ -0,0 +1,223 @@
+package org.openflow.util;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The following implement a producer/consumer design pattern in which both
+ * producers and consumers explicitly employ a centralized registration
+ * mechanism, and java Interfaces are used as contracts.<br>
+ */
+public class ProducerConsumer {
+
+    /*
+     * Class variables
+     */
+    protected static ProducerConsumer singleton;
+
+    /*
+     * Default constructor
+     */
+    protected ProducerConsumer() {
+        producerMap = new Hashtable<Class<?>, Set<IProducer>>();
+    }
+
+    /*
+     * Instance variables
+     */
+
+    // Interface/IProducer map
+    protected Map<Class<?>, Set<IProducer>> producerMap;
+
+    /*
+     * Protected methods
+     */
+
+    protected void _registerConsumer(Object consumer, Class<?>[] interfaces,
+                                     Set<Class<?>> iSet,
+                                     Set<Class<?>> iUniqueSet) {
+        // *...Process all interfaces...*/
+        for (Class<?> iface : interfaces) {
+
+            // *...Protect against repeated interfaces...*/
+            if (!iUniqueSet.contains(iface)) {
+                iUniqueSet.add(iface);
+
+                Set<IProducer> producers = producerMap.get(iface);
+
+                if (producers != null) {
+                    for (IProducer producer : producers)
+                        producer.registerConsumer(iface, consumer);
+                    iSet.add(iface);
+                }
+
+                // *...Recurse...*/
+                _registerConsumer(consumer, iface.getInterfaces(), iSet,
+                                  iUniqueSet);
+            }
+        }
+    }
+
+    protected void _registerConsumer(Object consumer, Class<?> clazz,
+                                     Set<Class<?>> iSet,
+                                     Set<Class<?>> iUniqueSet) {
+        if (clazz != null) {
+            // *...Process all interfaces...*/
+            _registerConsumer(consumer, clazz.getInterfaces(), iSet,
+                              iUniqueSet);
+
+            // *...Recurse the class hierarchy...*/
+            _registerConsumer(consumer, clazz.getSuperclass(), iSet,
+                              iUniqueSet);
+        }
+    }
+
+    protected int _deregisterConsumer(Object consumer,
+                                      Class<?>[] interfaces,
+                                      Set<Class<?>> iUniqueSet) {
+        int count = 0;
+
+        // *...Process all interfaces...*/
+        for (Class<?> iface : interfaces) {
+
+            // *...Protect against repeated interfaces...*/
+            if (!iUniqueSet.contains(iface)) {
+                iUniqueSet.add(iface);
+
+                Set<IProducer> producers = producerMap.get(iface);
+
+                if (producers != null) {
+                    for (IProducer producer : producers)
+                        producer.deregisterConsumer(iface, consumer);
+
+                    count++;
+                }
+
+                // *...Recurse...*/
+                count += _deregisterConsumer(consumer,
+                                             iface.getInterfaces(),
+                                             iUniqueSet);
+            }
+        }
+
+        return count;
+    }
+
+    protected int _deregisterConsumer(Object consumer, Class<?> clazz,
+                                      Set<Class<?>> iUniqueSet) {
+        int count = 0;
+
+        if (clazz != null) {
+            // *...Process all interfaces...*/
+            count += _deregisterConsumer(consumer, clazz.getInterfaces(),
+                                         iUniqueSet);
+
+            // *...Recurse the class hierarchy...*/
+            count += _deregisterConsumer(consumer, clazz.getSuperclass(),
+                                         iUniqueSet);
+        }
+
+        return count;
+    }
+
+    /*
+     * Singleton API
+     */
+
+    /**
+     * @return singleton ProducerConsumer
+     */
+    public static synchronized ProducerConsumer getSingleton() {
+        if (singleton == null) singleton = new ProducerConsumer();
+
+        return singleton;
+    }
+
+    /*
+     * Producer APIs
+     */
+
+    /**
+     * Producer registration
+     * 
+     * @param producer
+     *            object that implements IProducer
+     * @param iface
+     *            interface supported by the producer
+     * @return whether there was a previously registered producer, or true if
+     *         one or more the arguments were invalid
+     */
+    public boolean registerProducer(IProducer producer, Class<?> iface) {
+        if (producer != null && iface != null && iface.isInterface()) {
+            Set<IProducer> producers = producerMap.get(iface);
+
+            if (producers == null) {
+                producers = new HashSet<IProducer>();
+                producerMap.put(iface, producers);
+            }
+
+            return producers.add(producer);
+        } else
+            return true;
+    }
+
+    /**
+     * Producer deregistration
+     * 
+     * @param producer
+     *            object that implements IProducer
+     * @param iface
+     *            interface supported by the producer
+     * @return whether the interface/producer pair was removed, or false if one
+     *         or more the arguments were invalid
+     */
+    public boolean deregisterProducer(IProducer producer, Class<?> iface) {
+        if (producer != null && iface != null && iface.isInterface()) {
+            Set<IProducer> producers = producerMap.get(iface);
+
+            if (producers != null) return producers.remove(producer);
+        }
+
+        return false;
+    }
+
+    /*
+     * Consumer APIs
+     */
+
+    /**
+     * Consumer registration
+     * 
+     * @param consumer
+     *            object that implements producer-specific interfaces
+     * @return set of supported interfaces
+     */
+    public Set<Class<?>> registerConsumer(Object consumer) {
+        Set<Class<?>> iSet = new HashSet<Class<?>>();
+
+        if (consumer != null)
+                             _registerConsumer(consumer,
+                                               consumer.getClass(), iSet,
+                                               new HashSet<Class<?>>());
+
+        return iSet;
+    }
+
+    /**
+     * Consumer deregistration
+     * 
+     * @param consumer
+     *            object to deregister
+     * @return number of unregistered interfaces
+     */
+    public int deregisterConsumer(Object consumer) {
+        if (consumer != null)
+            return _deregisterConsumer(consumer, consumer.getClass(),
+                                       new HashSet<Class<?>>());
+        else
+            return 0;
+    }
+
+}
diff --git a/src/main/java/org/openflow/util/StringByteSerializer.java b/src/main/java/org/openflow/util/StringByteSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..9287fd20a73464d2483e42a6a4cc60781c45f5bb
--- /dev/null
+++ b/src/main/java/org/openflow/util/StringByteSerializer.java
@@ -0,0 +1,58 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+public class StringByteSerializer {
+    public static String readFrom(ChannelBuffer data, int length) {
+        byte[] stringBytes = new byte[length];
+        data.readBytes(stringBytes);
+        // find the first index of 0
+        int index = 0;
+        for (byte b : stringBytes) {
+            if (0 == b)
+                break;
+            ++index;
+        }
+        return new String(Arrays.copyOf(stringBytes, index),
+                Charset.forName("ascii"));
+    }
+
+    public static void writeTo(ChannelBuffer data, int length, String value) {
+        try {
+            byte[] name = value.getBytes("ASCII");
+            if (name.length < length) {
+                data.writeBytes(name);
+                for (int i = name.length; i < length; ++i) {
+                    data.writeByte((byte) 0);
+                }
+            } else {
+                data.writeBytes(name, 0, length-1);
+                data.writeByte((byte) 0);
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+}
diff --git a/src/main/java/org/openflow/util/U16.java b/src/main/java/org/openflow/util/U16.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d8917da5fd1c0f18e287d5506904102be196161
--- /dev/null
+++ b/src/main/java/org/openflow/util/U16.java
@@ -0,0 +1,28 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+public class U16 {
+    public static int f(short i) {
+        return (int)i & 0xffff;
+    }
+
+    public static short t(int l) {
+        return (short) l;
+    }
+}
diff --git a/src/main/java/org/openflow/util/U32.java b/src/main/java/org/openflow/util/U32.java
new file mode 100644
index 0000000000000000000000000000000000000000..3aab400ebf128079673ad1e98f7b1a1b484bd4aa
--- /dev/null
+++ b/src/main/java/org/openflow/util/U32.java
@@ -0,0 +1,28 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+public class U32 {
+    public static long f(int i) {
+        return (long)i & 0xffffffffL;
+    }
+
+    public static int t(long l) {
+        return (int) l;
+    }
+}
diff --git a/src/main/java/org/openflow/util/U64.java b/src/main/java/org/openflow/util/U64.java
new file mode 100644
index 0000000000000000000000000000000000000000..c6ae0f7b5c4e7f31521b03c84254502c43542e5d
--- /dev/null
+++ b/src/main/java/org/openflow/util/U64.java
@@ -0,0 +1,30 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import java.math.BigInteger;
+
+public class U64 {
+    public static BigInteger f(long i) {
+        return new BigInteger(Long.toBinaryString(i), 2);
+    }
+
+    public static long t(BigInteger l) {
+        return l.longValue();
+    }
+}
diff --git a/src/main/java/org/openflow/util/U8.java b/src/main/java/org/openflow/util/U8.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b575ad24e4d0d0abe433ae49f8725bd96c5fa39
--- /dev/null
+++ b/src/main/java/org/openflow/util/U8.java
@@ -0,0 +1,28 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+public class U8 {
+    public static short f(byte i) {
+        return (short) ((short)i & 0xff);
+    }
+
+    public static byte t(short l) {
+        return (byte) l;
+    }
+}
diff --git a/src/main/java/org/openflow/util/Unsigned.java b/src/main/java/org/openflow/util/Unsigned.java
new file mode 100644
index 0000000000000000000000000000000000000000..0754a3f73d751e0296ecd95d6671ec2db7c78dff
--- /dev/null
+++ b/src/main/java/org/openflow/util/Unsigned.java
@@ -0,0 +1,212 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+/*****
+ * A util library class for dealing with the lack of unsigned datatypes in Java
+ *
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+
+public class Unsigned {
+    /**
+     * Get an unsigned byte from the current position of the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the byte from
+     * @return an unsigned byte contained in a short
+     */
+    public static short getUnsignedByte(ByteBuffer bb) {
+        return ((short) (bb.get() & (short) 0xff));
+    }
+
+    /**
+     * Get an unsigned byte from the specified offset in the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the byte from
+     * @param offset the offset to get the byte from
+     * @return an unsigned byte contained in a short
+     */
+    public static short getUnsignedByte(ByteBuffer bb, int offset) {
+        return ((short) (bb.get(offset) & (short) 0xff));
+    }
+
+    /**
+     * Put an unsigned byte into the specified ByteBuffer at the current
+     * position
+     *
+     * @param bb ByteBuffer to put the byte into
+     * @param v the short containing the unsigned byte
+     */
+    public static void putUnsignedByte(ByteBuffer bb, short v) {
+        bb.put((byte) (v & 0xff));
+    }
+
+    /**
+     * Put an unsigned byte into the specified ByteBuffer at the specified
+     * offset
+     *
+     * @param bb ByteBuffer to put the byte into
+     * @param v the short containing the unsigned byte
+     * @param offset the offset to insert the unsigned byte at
+     */
+    public static void putUnsignedByte(ByteBuffer bb, short v, int offset) {
+        bb.put(offset, (byte) (v & 0xff));
+    }
+
+    /**
+     * Get an unsigned short from the current position of the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the byte from
+     * @return an unsigned short contained in a int
+     */
+    public static int getUnsignedShort(ByteBuffer bb) {
+        return (bb.getShort() & 0xffff);
+    }
+
+    /**
+     * Get an unsigned short from the specified offset in the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the short from
+     * @param offset the offset to get the short from
+     * @return an unsigned short contained in a int
+     */
+    public static int getUnsignedShort(ByteBuffer bb, int offset) {
+        return (bb.getShort(offset) & 0xffff);
+    }
+
+    /**
+     * Put an unsigned short into the specified ByteBuffer at the current
+     * position
+     *
+     * @param bb ByteBuffer to put the short into
+     * @param v the int containing the unsigned short
+     */
+    public static void putUnsignedShort(ByteBuffer bb, int v) {
+        bb.putShort((short) (v & 0xffff));
+    }
+
+    /**
+     * Put an unsigned short into the specified ByteBuffer at the specified
+     * offset
+     *
+     * @param bb ByteBuffer to put the short into
+     * @param v the int containing the unsigned short
+     * @param offset the offset to insert the unsigned short at
+     */
+    public static void putUnsignedShort(ByteBuffer bb, int v, int offset) {
+        bb.putShort(offset, (short) (v & 0xffff));
+    }
+
+    /**
+     * Get an unsigned int from the current position of the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the int from
+     * @return an unsigned int contained in a long
+     */
+    public static long getUnsignedInt(ByteBuffer bb) {
+        return ((long) bb.getInt() & 0xffffffffL);
+    }
+
+    /**
+     * Get an unsigned int from the specified offset in the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the int from
+     * @param offset the offset to get the int from
+     * @return an unsigned int contained in a long
+     */
+    public static long getUnsignedInt(ByteBuffer bb, int offset) {
+        return ((long) bb.getInt(offset) & 0xffffffffL);
+    }
+
+    /**
+     * Put an unsigned int into the specified ByteBuffer at the current position
+     *
+     * @param bb ByteBuffer to put the int into
+     * @param v the long containing the unsigned int
+     */
+    public static void putUnsignedInt(ByteBuffer bb, long v) {
+        bb.putInt((int) (v & 0xffffffffL));
+    }
+
+    /**
+     * Put an unsigned int into the specified ByteBuffer at the specified offset
+     *
+     * @param bb ByteBuffer to put the int into
+     * @param v the long containing the unsigned int
+     * @param offset the offset to insert the unsigned int at
+     */
+    public static void putUnsignedInt(ByteBuffer bb, long v, int offset) {
+        bb.putInt(offset, (int) (v & 0xffffffffL));
+    }
+
+    /**
+     * Get an unsigned long from the current position of the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the long from
+     * @return an unsigned long contained in a BigInteger
+     */
+    public static BigInteger getUnsignedLong(ByteBuffer bb) {
+        byte[] v = new byte[8];
+        for (int i = 0; i < 8; ++i) {
+            v[i] = bb.get(i);
+        }
+        return new BigInteger(1, v);
+    }
+
+    /**
+     * Get an unsigned long from the specified offset in the ByteBuffer
+     *
+     * @param bb ByteBuffer to get the long from
+     * @param offset the offset to get the long from
+     * @return an unsigned long contained in a BigInteger
+     */
+    public static BigInteger getUnsignedLong(ByteBuffer bb, int offset) {
+        byte[] v = new byte[8];
+        for (int i = 0; i < 8; ++i) {
+            v[i] = bb.get(offset+i);
+        }
+        return new BigInteger(1, v);
+    }
+
+    /**
+     * Put an unsigned long into the specified ByteBuffer at the current
+     * position
+     *
+     * @param bb ByteBuffer to put the long into
+     * @param v the BigInteger containing the unsigned long
+     */
+    public static void putUnsignedLong(ByteBuffer bb, BigInteger v) {
+        bb.putLong(v.longValue());
+    }
+
+    /**
+     * Put an unsigned long into the specified ByteBuffer at the specified
+     * offset
+     *
+     * @param bb  ByteBuffer to put the long into
+     * @param v the BigInteger containing the unsigned long
+     * @param offset the offset to insert the unsigned long at
+     */
+    public static void putUnsignedLong(ByteBuffer bb, BigInteger v, int offset) {
+        bb.putLong(offset, v.longValue());
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java b/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..687d5449f2dfdce8a4200f4c70c0f28ac72b67fe
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorData.java
@@ -0,0 +1,98 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.vendor.nicira;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Base class for vendor data corresponding to a Nicira vendor extension.
+ * Nicira vendor data always starts with a 4-byte integer data type value.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFNiciraVendorData implements OFVendorData {
+
+    public static final int NX_VENDOR_ID = 0x00002320;
+    /**
+     * The value of the integer data type at the beginning of the vendor data
+     */
+    protected int dataType;
+    
+    /**
+     * Construct empty (i.e. unspecified data type) Nicira vendor data.
+     */
+    public OFNiciraVendorData() {
+    }
+    
+    /**
+     * Contruct Nicira vendor data with the specified data type
+     * @param dataType the data type value at the beginning of the vendor data.
+     */
+    public OFNiciraVendorData(int dataType) {
+        this.dataType = dataType;
+    }
+    
+    /**
+     * Get the data type value at the beginning of the vendor data
+     * @return the integer data type value
+     */
+    public int getDataType() {
+        return dataType;
+    }
+    
+    /**
+     * Set the data type value
+     * @param dataType the integer data type value at the beginning of the
+     *     vendor data.
+     */
+    public void setDataType(int dataType) {
+        this.dataType = dataType;
+    }
+    
+    /**
+     * Get the length of the vendor data. This implementation will normally
+     * be the superclass for another class that will override this to return
+     * the overall vendor data length. This implementation just returns the 
+     * length of the part that includes the 4-byte integer data type value
+     * at the beginning of the vendor data.
+     */
+    @Override
+    public int getLength() {
+        return 4;
+    }
+
+    /**
+     * Read the vendor data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    @Override
+    public void readFrom(ChannelBuffer data, int length) {
+        dataType = data.readInt();
+    }
+
+    /**
+     * Write the vendor data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(dataType);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorExtensions.java b/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorExtensions.java
new file mode 100644
index 0000000000000000000000000000000000000000..98f88b242f62a34a3ff4e45b9197f8da58ecc9ec
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorExtensions.java
@@ -0,0 +1,30 @@
+package org.openflow.vendor.nicira;
+
+import org.openflow.protocol.vendor.OFBasicVendorDataType;
+import org.openflow.protocol.vendor.OFBasicVendorId;
+import org.openflow.protocol.vendor.OFVendorId;
+
+public class OFNiciraVendorExtensions {
+    private static boolean initialized = false;
+
+    public static synchronized void initialize() {
+        if (initialized)
+            return;
+
+        // Configure openflowj to be able to parse the role request/reply
+        // vendor messages.
+        OFBasicVendorId niciraVendorId =
+                new OFBasicVendorId(OFNiciraVendorData.NX_VENDOR_ID, 4);
+        OFVendorId.registerVendorId(niciraVendorId);
+        OFBasicVendorDataType roleRequestVendorData =
+                new OFBasicVendorDataType(OFRoleRequestVendorData.NXT_ROLE_REQUEST,
+                        OFRoleRequestVendorData.getInstantiable());
+        niciraVendorId.registerVendorDataType(roleRequestVendorData);
+        OFBasicVendorDataType roleReplyVendorData =
+                new OFBasicVendorDataType(OFRoleReplyVendorData.NXT_ROLE_REPLY,
+                        OFRoleReplyVendorData.getInstantiable());
+        niciraVendorId.registerVendorDataType(roleReplyVendorData);
+
+        initialized = true;
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java b/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..fa28c71fb5df6b9a083439f01cec911a1c5f0e69
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/nicira/OFRoleReplyVendorData.java
@@ -0,0 +1,66 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.vendor.nicira;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Subclass of OFVendorData representing the vendor data associated with
+ * a role reply vendor extension.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFRoleReplyVendorData extends OFRoleVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFRoleReplyVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFRoleReplyVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a role reply
+     */
+    public static final int NXT_ROLE_REPLY = 11;
+
+    /**
+     * Construct a role reply vendor data with an unspecified role value.
+     */
+    public OFRoleReplyVendorData() {
+        super(NXT_ROLE_REPLY);
+    }
+    
+    /**
+     * Construct a role reply vendor data with the specified role value.
+     * @param role the role value for the role reply. Should be one of
+     *      NX_ROLE_OTHER, NX_ROLE_MASTER or NX_ROLE_SLAVE.
+     */
+    public OFRoleReplyVendorData(int role) {
+        super(NXT_ROLE_REPLY, role);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java b/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7dbe71bda712da557d18678032e9267ba80d308
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/nicira/OFRoleRequestVendorData.java
@@ -0,0 +1,66 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.vendor.nicira;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Subclass of OFVendorData representing the vendor data associated with
+ * a role request vendor extension.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFRoleRequestVendorData extends OFRoleVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFRoleRequestVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFRoleRequestVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a role request
+     */
+    public static final int NXT_ROLE_REQUEST = 10;
+
+    /**
+     * Construct a role request vendor data with an unspecified role value.
+     */
+    public OFRoleRequestVendorData() {
+        super(NXT_ROLE_REQUEST);
+    }
+    
+    /**
+     * Construct a role request vendor data with the specified role value.
+     * @param role the role value for the role request. Should be one of
+     *      NX_ROLE_OTHER, NX_ROLE_MASTER or NX_ROLE_SLAVE.
+     */
+    public OFRoleRequestVendorData(int role) {
+        super(NXT_ROLE_REQUEST, role);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java b/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7c8bf2135b875a74bd14c0ad5393529a3e6e53b
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/nicira/OFRoleVendorData.java
@@ -0,0 +1,113 @@
+/**
+*    Copyright 2011, Big Switch Networks, Inc. 
+*    Originally created by David Erickson & Rob Sherwood, 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 org.openflow.vendor.nicira;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/**
+ * Class that represents the vendor data in the role request
+ * extension implemented by Open vSwitch to support high availability.
+ * 
+ * @author Rob Vaterlaus (rob.vaterlaus@bigswitch.com)
+ */
+public class OFRoleVendorData extends OFNiciraVendorData {
+    
+    /**
+     * Role value indicating that the controller is in the OTHER role.
+     */
+    public static final int NX_ROLE_OTHER = 0;
+    
+    /**
+     * Role value indicating that the controller is in the MASTER role.
+     */
+    public static final int NX_ROLE_MASTER = 1;
+    
+    /**
+     * Role value indicating that the controller is in the SLAVE role.
+     */
+    public static final int NX_ROLE_SLAVE = 2;
+
+    protected int role;
+
+    /** 
+     * Construct an uninitialized OFRoleVendorData
+     */
+    public OFRoleVendorData() {
+        super();
+    }
+    
+    /**
+     * Construct an OFRoleVendorData with the specified data type
+     * (i.e. either request or reply) and an unspecified role.
+     * @param dataType
+     */
+    public OFRoleVendorData(int dataType) {
+        super(dataType);
+    }
+    
+    /**
+     * Construct an OFRoleVendorData with the specified data type
+     * (i.e. either request or reply) and role (i.e. one of of
+     * master, slave, or other).
+     * @param dataType either role request or role reply data type
+     */
+    public OFRoleVendorData(int dataType, int role) {
+        super(dataType);
+        this.role = role;
+    }
+    /**
+     * @return the role value of the role vendor data
+     */
+    public int getRole() {
+        return role;
+    }
+    
+    /**
+     * @param role the role value of the role vendor data
+     */
+    public void setRole(int role) {
+        this.role = role;
+    }
+
+    /**
+     * @return the total length of the role vendor data
+     */
+    @Override
+    public int getLength() {
+        return super.getLength() + 4;
+    }
+    
+    /**
+     * Read the role vendor data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    public void readFrom(ChannelBuffer data, int length) {
+        super.readFrom(data, length);
+        role = data.readInt();
+    }
+
+    /**
+     * Write the role vendor data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(role);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorData.java b/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..9be821f2ace4fb624a0a2314e0b997ec9d086f14
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorData.java
@@ -0,0 +1,98 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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 org.openflow.vendor.openflow;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Base class for vendor data corresponding to extensions to OpenFlow 1.0.
+ * Based on org.openflow.vendor.nicira
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFOpenFlowVendorData implements OFVendorData {
+
+    public static final int OF_VENDOR_ID = 0x000026e1;
+
+    /**
+     * The value of the integer data type at the beginning of the vendor data
+     */
+    protected int dataType;
+
+    /**
+     * Construct empty (i.e. unspecified data type) OpenFlow vendor data.
+     */
+    public OFOpenFlowVendorData() {
+    }
+
+    /**
+     * Construct OpenFlow vendor data with the specified data type
+     * @param dataType the data type value at the beginning of the vendor data.
+     */
+    public OFOpenFlowVendorData(int dataType) {
+        this.dataType = dataType;
+    }
+
+    /**
+     * Get the data type value at the beginning of the vendor data
+     * @return the integer data type value
+     */
+    public int getDataType() {
+        return dataType;
+    }
+
+    /**
+     * Set the data type value
+     * @param dataType the integer data type value at the beginning of the
+     *     vendor data.
+     */
+    public void setDataType(int dataType) {
+        this.dataType = dataType;
+    }
+
+    /**
+     * Get the length of the vendor data. This implementation will normally
+     * be the superclass for another class that will override this to return
+     * the overall vendor data length. This implementation just returns the
+     * length of the part that includes the 4-byte integer data type value
+     * at the beginning of the vendor data.
+     */
+    @Override
+    public int getLength() {
+        return 4;
+    }
+
+    /**
+     * Read the vendor data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    @Override
+    public void readFrom(ChannelBuffer data, int length) {
+        dataType = data.readInt();
+    }
+
+    /**
+     * Write the vendor data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(dataType);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorExtensions.java b/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorExtensions.java
new file mode 100644
index 0000000000000000000000000000000000000000..3fa10298cbc0ad4307368983cd157e51116e20ef
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorExtensions.java
@@ -0,0 +1,47 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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 org.openflow.vendor.openflow;
+
+import org.openflow.protocol.vendor.OFBasicVendorDataType;
+import org.openflow.protocol.vendor.OFBasicVendorId;
+import org.openflow.protocol.vendor.OFVendorId;
+
+public class OFOpenFlowVendorExtensions {
+    private static boolean initialized = false;
+
+    public static synchronized void initialize() {
+        if (initialized)
+            return;
+
+        // Configure openflowj to be able to parse the OpenFlow extensions.
+        OFBasicVendorId openflowVendorId =
+                new OFBasicVendorId(OFOpenFlowVendorData.OF_VENDOR_ID, 4);
+        OFVendorId.registerVendorId(openflowVendorId);
+
+        OFBasicVendorDataType queueModifyVendorData =
+                new OFBasicVendorDataType(OFQueueModifyVendorData.OFP_EXT_QUEUE_MODIFY,
+                        OFQueueModifyVendorData.getInstantiable());
+        openflowVendorId.registerVendorDataType(queueModifyVendorData);
+
+        OFBasicVendorDataType queueDeleteVendorData =
+                new OFBasicVendorDataType(OFQueueDeleteVendorData.OFP_EXT_QUEUE_DELETE,
+                        OFQueueModifyVendorData.getInstantiable());
+        openflowVendorId.registerVendorDataType(queueDeleteVendorData);
+
+        initialized = true;
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/openflow/OFQueueDeleteVendorData.java b/src/main/java/org/openflow/vendor/openflow/OFQueueDeleteVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fc52bacb337733d19647ab89f3ee04f553ef018
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFQueueDeleteVendorData.java
@@ -0,0 +1,52 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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 org.openflow.vendor.openflow;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Class that represents the vendor data in the queue delete request
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueDeleteVendorData extends OFQueueVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFQueueDeleteVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFQueueDeleteVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a queue delete request
+     */
+    public static final int OFP_EXT_QUEUE_DELETE = 1;
+
+    public OFQueueDeleteVendorData() {
+        super(OFP_EXT_QUEUE_DELETE);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/openflow/OFQueueModifyVendorData.java b/src/main/java/org/openflow/vendor/openflow/OFQueueModifyVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d2f31b524c22f2e1152735eb5db26d8ae210914
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFQueueModifyVendorData.java
@@ -0,0 +1,52 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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 org.openflow.vendor.openflow;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Class that represents the vendor data in the queue modify request
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueModifyVendorData extends OFQueueVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFQueueModifyVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFQueueModifyVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a queue modify request
+     */
+    public static final int OFP_EXT_QUEUE_MODIFY = 0;
+
+    public OFQueueModifyVendorData() {
+        super(OFP_EXT_QUEUE_MODIFY);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/openflow/OFQueueVendorData.java b/src/main/java/org/openflow/vendor/openflow/OFQueueVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..eeae9aace6436f42de2c26151aba1f125e26d83b
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFQueueVendorData.java
@@ -0,0 +1,119 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown 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 org.openflow.vendor.openflow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFPacketQueue;
+
+/**
+ * Class that represents the vendor data in a queue modify or delete request
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueVendorData extends OFOpenFlowVendorData {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected short portNumber;
+    protected List<OFPacketQueue> queues = new ArrayList<OFPacketQueue>();
+
+    public OFQueueVendorData(int dataType) {
+        super(dataType);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param port the port on which the queue is
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+
+    /**
+     * @return the queues
+     */
+    public List<OFPacketQueue> getQueues() {
+        return queues;
+    }
+
+    /**
+     * @param queues the queues to modify or delete
+     */
+    public void setQueues(List<OFPacketQueue> queues) {
+        this.queues = queues;
+    }
+
+    /**
+     * @return the total length of the queue modify or delete msg
+     */
+    @Override
+    public int getLength() {
+        int queuesLength = 0;
+
+        for (OFPacketQueue queue : queues) {
+            queuesLength += queue.getLength();
+        }
+
+        return super.getLength() + MINIMUM_LENGTH + queuesLength;
+    }
+
+    /**
+     * Read the queue message data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    public void readFrom(ChannelBuffer data, int length) {
+        super.readFrom(data, length);
+        portNumber = data.readShort();
+        data.readInt();   // pad
+        data.readShort(); // pad
+
+        int availLength = (length - MINIMUM_LENGTH);
+        this.queues.clear();
+
+        while (availLength > 0) {
+            OFPacketQueue queue = new OFPacketQueue();
+            queue.readFrom(data);
+            queues.add(queue);
+            availLength -= queue.getLength();
+        }
+    }
+
+    /**
+     * Write the queue message data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeInt(0);   // pad
+        data.writeShort(0); // pad
+
+        for (OFPacketQueue queue : queues) {
+            queue.writeTo(data);
+        }
+    }
+}
diff --git a/src/main/java/org/sdnplatform/sync/ISyncService.java b/src/main/java/org/sdnplatform/sync/ISyncService.java
index 48feead4a3c378e61147292203db3ccaa6435900..75f3948a8e7b20d669492573b3dc616f8d9c54a7 100644
--- a/src/main/java/org/sdnplatform/sync/ISyncService.java
+++ b/src/main/java/org/sdnplatform/sync/ISyncService.java
@@ -40,8 +40,6 @@ public interface ISyncService extends IFloodlightService {
          */
         UNSYNCHRONIZED
     }
-    
-    public short getLocalNodeId();
 
     /**
      * Create a store with the given store name and scope
diff --git a/src/main/java/org/sdnplatform/sync/internal/SyncTorture.java b/src/main/java/org/sdnplatform/sync/internal/SyncTorture.java
new file mode 100644
index 0000000000000000000000000000000000000000..74e4ae96648089a28dd38758b817886a01f57f63
--- /dev/null
+++ b/src/main/java/org/sdnplatform/sync/internal/SyncTorture.java
@@ -0,0 +1,196 @@
+package org.sdnplatform.sync.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.sdnplatform.sync.IStoreClient;
+import org.sdnplatform.sync.ISyncService;
+import org.sdnplatform.sync.Versioned;
+import org.sdnplatform.sync.ISyncService.Scope;
+import org.sdnplatform.sync.error.SyncException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+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.debugcounter.IDebugCounterService;
+
+/**
+ * A floodlight module that will start up and start doing horrible,
+ * horrible things to the sync service.
+ * @author readams
+ */
+public class SyncTorture implements IFloodlightModule {
+    protected static final Logger logger =
+            LoggerFactory.getLogger(SyncTorture.class);
+
+    private static final String SYNC_STORE_NAME =
+            SyncTorture.class.getCanonicalName() + ".torture";
+    
+    ISyncService syncService;
+    IDebugCounterService debugCounter;
+
+    int numWorkers = 2;
+    int keysPerWorker = 1024*1024;
+    int iterations = 0;
+    int delay = 0;
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleServices() {
+        return null;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService>
+            getServiceImpls() {
+        return null;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleDependencies() {
+        Collection<Class<? extends IFloodlightService>> l = 
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(ISyncService.class);
+        l.add(IDebugCounterService.class);
+
+        return l;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+        syncService = context.getServiceImpl(ISyncService.class);
+        debugCounter = context.getServiceImpl(IDebugCounterService.class);
+
+        try {
+            syncService.registerStore(SYNC_STORE_NAME, Scope.GLOBAL);
+        } catch (SyncException e) {
+            throw new FloodlightModuleException(e);
+        }
+        
+        Map<String,String> config = context.getConfigParams(this);
+        if (config.containsKey("numWorkers")) {
+            numWorkers = Integer.parseInt(config.get("numWorkers"));
+        }
+        if (config.containsKey("keysPerWorker")) {
+            keysPerWorker = Integer.parseInt(config.get("keysPerWorker"));
+        }
+        if (config.containsKey("iterations")) {
+            iterations = Integer.parseInt(config.get("iterations"));
+        }
+        if (config.containsKey("delay")) {
+            delay = Integer.parseInt(config.get("delay"));
+        }
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+        try {
+            final IStoreClient<String, TortureValue> storeClient = 
+                    syncService.getStoreClient(SYNC_STORE_NAME, 
+                                               String.class, 
+                                               TortureValue.class);
+            for (int i = 0; i < numWorkers; i++) {
+                Thread thread = new Thread(new TortureWorker(storeClient, i),
+                                           "Torture-" + i);
+                thread.setPriority(Thread.MIN_PRIORITY);
+                thread.start();
+            }
+        } catch (Exception e) {
+            throw new FloodlightModuleException(e);
+        }
+    }
+
+    protected static class TortureValue {
+        private String string;
+        private int integer;
+        private boolean bool;
+
+        public TortureValue() {
+            super();
+        }
+
+        public TortureValue(String string, int integer, boolean bool) {
+            super();
+            this.string = string;
+            this.integer = integer;
+            this.bool = bool;
+        }
+        
+        public String getString() {
+            return string;
+        }
+        public void setString(String string) {
+            this.string = string;
+        }
+        public int getInteger() {
+            return integer;
+        }
+        public void setInteger(int integer) {
+            this.integer = integer;
+        }
+        public boolean isBool() {
+            return bool;
+        }
+        public void setBool(boolean bool) {
+            this.bool = bool;
+        }
+    }
+    
+    protected class TortureWorker implements Runnable {
+        final IStoreClient<String, TortureValue> storeClient;
+        final int workerId;
+        final List<TortureValue> values;
+
+        public TortureWorker(IStoreClient<String, TortureValue> storeClient,
+                             int workerId) {
+            super();
+            this.storeClient = storeClient;
+            this.workerId = workerId;
+            values = new ArrayList<TortureValue>();
+            for (int i = 0; i < keysPerWorker; i++) {
+                values.add(new TortureValue(workerId+":"+i, 0, true));
+            }
+        }
+
+        @Override
+        public void run() {
+            if (delay > 0) {
+                try {
+                    Thread.sleep(delay);
+                } catch (InterruptedException e) { }
+            }
+            int i = 0;
+            while (iterations == 0 || i++ < iterations) {
+                long start = System.currentTimeMillis();
+                try {
+                    for (TortureValue v : values) {
+                        Versioned<TortureValue> vv =
+                                storeClient.get(v.getString());
+                        v.setInteger(v.getInteger() + 1);
+                        v.setBool(!v.isBool());
+                        vv.setValue(v);
+                        storeClient.put(v.getString(), vv);
+                    }
+                } catch (Exception e) {
+                    logger.error("Error in worker: ", e);
+                }
+                long iterend = System.currentTimeMillis();
+                debugCounter.flushCounters();
+                logger.info("Completed iteration of {} values in {}ms" + 
+                            " ({}/s)", 
+                            new Object[]{values.size(), (iterend-start),
+                            1000*values.size()/(iterend-start)});
+            }
+            
+        }
+    }
+}
diff --git a/src/main/java/org/sdnplatform/sync/internal/config/ClusterConfig.java b/src/main/java/org/sdnplatform/sync/internal/config/ClusterConfig.java
index 416f4ebaacddf5455a40e404ceefe251526a2617..27addf7fe1ff448d154af8222d561604a31e86b3 100644
--- a/src/main/java/org/sdnplatform/sync/internal/config/ClusterConfig.java
+++ b/src/main/java/org/sdnplatform/sync/internal/config/ClusterConfig.java
@@ -15,7 +15,6 @@ import org.sdnplatform.sync.error.SyncException;
  * @author readams
  */
 public class ClusterConfig {
-    public static final short NODE_ID_UNCONFIGURED = Short.MAX_VALUE;
 
     private HashMap<Short, Node> allNodes =
             new HashMap<Short, Node>();
diff --git a/src/main/java/org/sdnplatform/sync/internal/util/ByteArray.java b/src/main/java/org/sdnplatform/sync/internal/util/ByteArray.java
index 733f03af894c09f3e310ed84f7d5feada55a41b0..5a9473562e4d226fb7e8f5f22e805074bcd90129 100644
--- a/src/main/java/org/sdnplatform/sync/internal/util/ByteArray.java
+++ b/src/main/java/org/sdnplatform/sync/internal/util/ByteArray.java
@@ -4,7 +4,7 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
 
-import org.projectfloodlight.openflow.util.HexString;
+import org.openflow.util.HexString;
 
 /**
  * A byte array container that provides an equals and hashCode pair based on the
diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
index e5b3347805af7289e2e8abe90234f38df54b0ee8..b06589a30a6493bd22d7da347a7bab7e6d4fd642 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
@@ -95,7 +95,7 @@ import org.sdnplatform.sync.test.MockSyncService;
 
 public class ControllerTest extends FloodlightTestCase {
 
-    private OLD__Controller controller;
+    private Controller controller;
     private MockThreadPoolService tp;
     private MockSyncService syncService;
     private IStoreClient<Long, SwitchSyncRepresentation> storeClient;
@@ -115,7 +115,7 @@ public class ControllerTest extends FloodlightTestCase {
 
         FloodlightProvider cm = new FloodlightProvider();
         fmc.addConfigParam(cm, "role", role.toString());
-        controller = (OLD__Controller)cm.getServiceImpls().get(IFloodlightProviderService.class);
+        controller = (Controller)cm.getServiceImpls().get(IFloodlightProviderService.class);
         fmc.addService(IFloodlightProviderService.class, controller);
 
         MemoryStorageSource memstorage = new MemoryStorageSource();
@@ -165,7 +165,7 @@ public class ControllerTest extends FloodlightTestCase {
         cm.startUp(fmc);
 
         storeClient =
-                syncService.getStoreClient(OLD__Controller.SWITCH_SYNC_STORE_NAME,
+                syncService.getStoreClient(Controller.SWITCH_SYNC_STORE_NAME,
                                            Long.class,
                                            SwitchSyncRepresentation.class);
 
@@ -204,7 +204,7 @@ public class ControllerTest extends FloodlightTestCase {
                    controller.isUpdateQueueEmptyForTesting());
     }
 
-    public OLD__Controller getController() {
+    public Controller getController() {
         return controller;
     }
 
@@ -2048,11 +2048,11 @@ public class ControllerTest extends FloodlightTestCase {
     private Map<String,Object> getFakeControllerIPRow(String id, String controllerId,
             String type, int number, String discoveredIP ) {
         HashMap<String, Object> row = new HashMap<String,Object>();
-        row.put(OLD__Controller.CONTROLLER_INTERFACE_ID, id);
-        row.put(OLD__Controller.CONTROLLER_INTERFACE_CONTROLLER_ID, controllerId);
-        row.put(OLD__Controller.CONTROLLER_INTERFACE_TYPE, type);
-        row.put(OLD__Controller.CONTROLLER_INTERFACE_NUMBER, number);
-        row.put(OLD__Controller.CONTROLLER_INTERFACE_DISCOVERED_IP, discoveredIP);
+        row.put(Controller.CONTROLLER_INTERFACE_ID, id);
+        row.put(Controller.CONTROLLER_INTERFACE_CONTROLLER_ID, controllerId);
+        row.put(Controller.CONTROLLER_INTERFACE_TYPE, type);
+        row.put(Controller.CONTROLLER_INTERFACE_NUMBER, number);
+        row.put(Controller.CONTROLLER_INTERFACE_DISCOVERED_IP, discoveredIP);
         return row;
     }
 
@@ -2139,7 +2139,7 @@ public class ControllerTest extends FloodlightTestCase {
         synchronized(listener) {
             // Insert a first entry
             controller.getStorageSourceService()
-                .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME,
+                .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
                     getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1"));
             expectedCurMap.clear();
             expectedAddedMap.clear();
@@ -2151,7 +2151,7 @@ public class ControllerTest extends FloodlightTestCase {
 
             // Add an interface that we want to ignore.
             controller.getStorageSourceService()
-                .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME,
+                .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
                     getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2"));
             // TODO: do a different check. This call will have to wait for the timeout
             controller.processUpdateQueueForTesting();
@@ -2160,7 +2160,7 @@ public class ControllerTest extends FloodlightTestCase {
 
             // Add another entry
             controller.getStorageSourceService()
-                .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME,
+                .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
                     getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2"));
             expectedCurMap.clear();
             expectedAddedMap.clear();
@@ -2174,7 +2174,7 @@ public class ControllerTest extends FloodlightTestCase {
 
             // Update an entry
             controller.getStorageSourceService()
-                .updateRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME,
+                .updateRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
                     "row3", getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.3"));
             expectedCurMap.clear();
             expectedAddedMap.clear();
@@ -2188,7 +2188,7 @@ public class ControllerTest extends FloodlightTestCase {
 
             // Delete an entry
             controller.getStorageSourceService()
-                .deleteRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME, "row3");
+                .deleteRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, "row3");
             expectedCurMap.clear();
             expectedAddedMap.clear();
             expectedRemovedMap.clear();
@@ -2204,13 +2204,13 @@ public class ControllerTest extends FloodlightTestCase {
         HashMap<String,String> expectedCurMap = new HashMap<String, String>();
 
         controller.getStorageSourceService()
-            .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME,
+            .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
                 getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1"));
         controller.getStorageSourceService()
-            .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME,
+            .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
                 getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2"));
         controller.getStorageSourceService()
-            .insertRow(OLD__Controller.CONTROLLER_INTERFACE_TABLE_NAME,
+            .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
                 getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2"));
         expectedCurMap.put("c1", "1.1.1.1");
         expectedCurMap.put("c2", "2.2.2.2");
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java
index bc4490e73aa34e96c0dc716783999a8e8f59a54d..ed01868b0035eeae062f8f8f17afa2930a3c5ed2 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java
@@ -66,7 +66,7 @@ import static org.junit.Assert.*;
 public class OFChannelHandlerTest {
     private static final short CORE_PRIORITY = 4242;
     private static final short ACCESS_PRIORITY = 42;
-    private OLD__Controller controller;
+    private Controller controller;
     private IThreadPoolService threadPool;
     private IDebugCounterService debugCounterService;
     private OFChannelHandler handler;
@@ -110,7 +110,7 @@ public class OFChannelHandlerTest {
 
     @Before
     public void setUp() throws Exception {
-        controller = createMock(OLD__Controller.class);
+        controller = createMock(Controller.class);
         threadPool = createMock(IThreadPoolService.class);
         ctx = createMock(ChannelHandlerContext.class);
         channelStateEvent = createMock(ChannelStateEvent.class);
@@ -125,8 +125,8 @@ public class OFChannelHandlerTest {
         // TODO: should mock IDebugCounterService and make sure
         // the expected counters are updated.
         debugCounterService = new DebugCounter();
-        OLD__Controller.Counters counters =
-                new OLD__Controller.Counters();
+        Controller.Counters counters =
+                new Controller.Counters();
         counters.createCounters(debugCounterService);
         expect(controller.getCounters()).andReturn(counters).anyTimes();
         replay(controller);
@@ -442,7 +442,7 @@ public class OFChannelHandlerTest {
         Iterator<IResultSet> it = null;
 
         if (cfg.isPresent) {
-            storageResultSet.getBoolean(OLD__Controller.SWITCH_CONFIG_CORE_SWITCH);
+            storageResultSet.getBoolean(Controller.SWITCH_CONFIG_CORE_SWITCH);
             expectLastCall().andReturn(cfg.isCoreSwitch).atLeastOnce();
             it = Collections.singletonList(storageResultSet).iterator();
         } else {
@@ -452,7 +452,7 @@ public class OFChannelHandlerTest {
         storageResultSet.close();
         expectLastCall().atLeastOnce();
         expect(storageResultSet.iterator()).andReturn(it).atLeastOnce();
-        storageSource.getRow(OLD__Controller.SWITCH_CONFIG_TABLE_NAME, cfg.dpid);
+        storageSource.getRow(Controller.SWITCH_CONFIG_TABLE_NAME, cfg.dpid);
         expectLastCall().andReturn(storageResultSet).atLeastOnce();
         replay(storageResultSet, storageSource);
     }
diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
index 1e5e4643e894e868ebffff36c7cdad986d5e41c4..c3cc59ed3c6cb5d50b2abbf047bd54d5a221c883 100644
--- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
+++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
@@ -30,7 +30,7 @@ import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
 import net.floodlightcontroller.core.ImmutablePort;
-import net.floodlightcontroller.core.internal.OLD__Controller;
+import net.floodlightcontroller.core.internal.Controller;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 
@@ -357,7 +357,7 @@ public class OFMessageDamperMockSwitch implements IOFSwitch {
     }
 
     @Override
-    public void setFloodlightProvider(OLD__Controller controller) {
+    public void setFloodlightProvider(Controller controller) {
         fail("Unexpected method call");
         // TODO Auto-generated method stub
 
diff --git a/src/test/java/org/openflow/protocol/BasicFactoryTest.java b/src/test/java/org/openflow/protocol/BasicFactoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..350d4be39c3f1148c7a6c4191085bbe8bb9132a5
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/BasicFactoryTest.java
@@ -0,0 +1,134 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.action.MockVendorAction;
+import org.openflow.protocol.action.MockVendorActionFactory;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionVendorGeneric;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.MessageParseException;
+import org.openflow.protocol.factory.OFVendorActionRegistry;
+import org.openflow.util.U16;
+
+public class BasicFactoryTest extends TestCase {
+
+    public void testCreateAndParse() throws MessageParseException {
+        BasicFactory factory = BasicFactory.getInstance();
+        OFMessage m = factory.getMessage(OFType.HELLO);
+        m.setVersion((byte) 1);
+        m.setType(OFType.ECHO_REQUEST);
+        m.setLength(U16.t(8));
+        m.setXid(0xdeadbeef);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        ChannelBuffer bb2 = ChannelBuffers.dynamicBuffer();
+        m.writeTo(bb);
+        bb2.writeBytes(bb, bb.readableBytes()-1);
+        TestCase.assertNull(factory.parseMessage(bb2));
+        bb2.writeByte(bb.readByte());
+        List<OFMessage> message = factory.parseMessage(bb2);
+        TestCase.assertNotNull(message);
+        TestCase.assertEquals(message.size(), 1);
+        TestCase.assertTrue(message.get(0).getType() == OFType.ECHO_REQUEST);
+    }
+
+    public void testInvalidMsgParse() throws MessageParseException {
+        BasicFactory factory = BasicFactory.getInstance();
+        OFMessage m = factory.getMessage(OFType.HELLO);
+        m.setVersion((byte) 1);
+        m.setType(OFType.ECHO_REQUEST);
+        m.setLength(U16.t(16));
+        m.setXid(0xdeadbeef);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        m.writeTo(bb);
+        List<OFMessage> message = factory.parseMessage(bb);
+        TestCase.assertNull(message);
+    }
+
+    public void testCurrouptedMsgParse() throws MessageParseException {
+        BasicFactory factory = BasicFactory.getInstance();
+        OFMessage m = factory.getMessage(OFType.HELLO);
+        m.setVersion((byte) 1);
+        m.setType(OFType.ERROR);
+        m.setLength(U16.t(8));
+        m.setXid(0xdeadbeef);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        m.writeTo(bb);
+        try {
+                factory.parseMessage(bb);
+        }
+        catch(Exception e) {
+            TestCase.assertEquals(MessageParseException.class, e.getClass());
+        }
+    }
+
+    public void testCustomVendorAction() throws MessageParseException {
+        BasicFactory factory = BasicFactory.getInstance();
+        OFVendorActionRegistry.getInstance().register(
+                MockVendorAction.VENDOR_ID, new MockVendorActionFactory());
+
+
+        byte[] deadBeefMessage = {
+            (byte) 0xff, (byte) 0xff,          // action vendor
+            0x00, 0x10,                        // length
+            (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte)0xef,            // deadbeaf
+            0x01, 0x02, 0x03, 0x04,
+            0x05, 0x06, 0x07, 0x08               // pad
+        };
+
+        ChannelBuffer buf = ChannelBuffers.copiedBuffer(deadBeefMessage);
+
+        List<OFAction> actions = factory.parseActions(buf,deadBeefMessage.length);
+        assertEquals(1, actions.size());
+        OFAction ofAction = actions.get(0);
+        assertTrue("Action should be MockVendorAction, but is "+ofAction.getClass(), ofAction instanceof MockVendorAction);
+        assertArrayEquals( new byte[]  { 1,2,3,4,5,6,7,8}, ((MockVendorAction)ofAction).getMockData());
+
+
+    }
+
+    public void testGenericVendorAction() throws MessageParseException {
+        byte[] nonDeadBeefMessage = {
+                (byte) 0xff, (byte) 0xff,          // action vendor
+                0x00, 0x10,                        // length
+                (byte) 0x7e, (byte) 0xe7, (byte) 0xbe, (byte)0xef,            // deadbeaf
+                0x01, 0x02, 0x03, 0x04,
+                0x05, 0x06, 0x07, 0x08               // pad
+            };
+
+        BasicFactory factory = BasicFactory.getInstance();
+        OFVendorActionRegistry.getInstance().register(
+                MockVendorAction.VENDOR_ID, new MockVendorActionFactory());
+
+        ChannelBuffer buf = ChannelBuffers.copiedBuffer(nonDeadBeefMessage);
+
+        List<OFAction> actions = factory.parseActions(buf,nonDeadBeefMessage.length);
+        assertEquals(1, actions.size());
+        OFAction ofAction = actions.get(0);
+        assertTrue("Action should be OFActionVendorGeneric, but is "+ofAction.getClass(), ofAction instanceof OFActionVendorGeneric);
+    }
+
+}
diff --git a/src/test/java/org/openflow/protocol/OFActionTypeTest.java b/src/test/java/org/openflow/protocol/OFActionTypeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed8386cd745dd7db691e334d6bd64fec81e67745
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFActionTypeTest.java
@@ -0,0 +1,37 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+
+import org.junit.Test;
+import org.openflow.protocol.action.OFActionType;
+
+import junit.framework.TestCase;
+
+
+public class OFActionTypeTest extends TestCase {
+    @Test
+    public void testMapping() throws Exception {
+        TestCase.assertEquals(OFActionType.OUTPUT,
+                OFActionType.valueOf((short) 0));
+        TestCase.assertEquals(OFActionType.OPAQUE_ENQUEUE,
+                OFActionType.valueOf((short) 11));
+        TestCase.assertEquals(OFActionType.VENDOR,
+                OFActionType.valueOf((short) 0xffff));
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFBarrierReplyTest.java b/src/test/java/org/openflow/protocol/OFBarrierReplyTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e447bb071bf477448823d085db1d6a9e7e72701
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFBarrierReplyTest.java
@@ -0,0 +1,36 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFBarrierReplyTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFBarrierReply msg = (OFBarrierReply) messageFactory
+                .getMessage(OFType.BARRIER_REPLY);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.BARRIER_REPLY, msg.getType());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFBarrierRequestTest.java b/src/test/java/org/openflow/protocol/OFBarrierRequestTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3aa9cb4a789f6ea2202878a6d92da898d76a4490
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFBarrierRequestTest.java
@@ -0,0 +1,36 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFBarrierRequestTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFBarrierRequest msg = (OFBarrierRequest) messageFactory
+                .getMessage(OFType.BARRIER_REQUEST);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.BARRIER_REQUEST, msg.getType());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFErrorTest.java b/src/test/java/org/openflow/protocol/OFErrorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4a57269826d81cf17b47b547e4b7588afeb873f
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFErrorTest.java
@@ -0,0 +1,88 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.OFError.OFErrorType;
+import org.openflow.protocol.OFError.OFHelloFailedCode;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.MessageParseException;
+import org.openflow.protocol.factory.OFMessageFactory;
+import org.openflow.util.OFTestCase;
+
+public class OFErrorTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFError msg = (OFError) messageFactory.getMessage(OFType.ERROR);
+        msg.setMessageFactory(messageFactory);
+        msg.setErrorType(OFErrorType.OFPET_HELLO_FAILED.getValue());
+        msg.setErrorCode((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE
+                .ordinal());
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFErrorType.OFPET_HELLO_FAILED.getValue(),
+                msg.getErrorType());
+        TestCase.assertEquals((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE
+                .ordinal(), msg.getErrorType());
+        TestCase.assertNull(msg.getOffendingMsg());
+
+        msg.setOffendingMsg(new OFHello());
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFErrorType.OFPET_HELLO_FAILED.getValue(),
+                msg.getErrorType());
+        TestCase.assertEquals((short) OFHelloFailedCode.OFPHFC_INCOMPATIBLE
+                .ordinal(), msg.getErrorType());
+        TestCase.assertNotNull(msg.getOffendingMsg());
+        TestCase.assertEquals(OFHello.MINIMUM_LENGTH,
+                msg.getOffendingMsg().length);
+    }
+
+    public void testGarbageAtEnd() throws MessageParseException {
+        // This is a OFError msg (12 bytes), that encaps a OFVendor msg (24
+        // bytes)
+        // AND some zeros at the end (40 bytes) for a total of 76 bytes
+        // THIS is what an NEC sends in reply to Nox's VENDOR request
+        byte[] oferrorRaw = { 0x01, 0x01, 0x00, 0x4c, 0x00, 0x00, 0x10,
+                (byte) 0xcc, 0x00, 0x01, 0x00, 0x01, 0x01, 0x04, 0x00, 0x18,
+                0x00, 0x00, 0x10, (byte) 0xcc, 0x00, 0x00, 0x23, 0x20, 0x00,
+                0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00 };
+        OFMessageFactory factory = BasicFactory.getInstance();
+        ChannelBuffer oferrorBuf = 
+                ChannelBuffers.wrappedBuffer(oferrorRaw);
+        List<OFMessage> msg = factory.parseMessage(oferrorBuf);
+        TestCase.assertNotNull(msg);
+        TestCase.assertEquals(msg.size(), 1);
+        TestCase.assertEquals(76, msg.get(0).getLengthU());
+        ChannelBuffer out = ChannelBuffers.dynamicBuffer();
+        msg.get(0).writeTo(out);
+        TestCase.assertEquals(76, out.readableBytes());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFFeaturesReplyTest.java b/src/test/java/org/openflow/protocol/OFFeaturesReplyTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..62e491a995a3f232be6027043144f6544d70e1d8
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFFeaturesReplyTest.java
@@ -0,0 +1,62 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+
+public class OFFeaturesReplyTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFFeaturesReply ofr = (OFFeaturesReply) messageFactory
+                .getMessage(OFType.FEATURES_REPLY);
+        List<OFPhysicalPort> ports = new ArrayList<OFPhysicalPort>();
+        OFPhysicalPort port = new OFPhysicalPort();
+        port.setHardwareAddress(new byte[6]);
+        port.setName("eth0");
+        ports.add(port);
+        ofr.setPorts(ports);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        ofr.writeTo(bb);
+        ofr.readFrom(bb);
+        TestCase.assertEquals(1, ofr.getPorts().size());
+        TestCase.assertEquals("eth0", ofr.getPorts().get(0).getName());
+
+        // test a 15 character name
+        ofr.getPorts().get(0).setName("012345678901234");
+        bb.clear();
+        ofr.writeTo(bb);
+        ofr.readFrom(bb);
+        TestCase.assertEquals("012345678901234", ofr.getPorts().get(0).getName());
+
+        // test a 16 character name getting truncated
+        ofr.getPorts().get(0).setName("0123456789012345");
+        bb.clear();
+        ofr.writeTo(bb);
+        ofr.readFrom(bb);
+        TestCase.assertEquals("012345678901234", ofr.getPorts().get(0).getName());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFFlowRemovedTest.java b/src/test/java/org/openflow/protocol/OFFlowRemovedTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..11746e72411a663170e7ebbf4a8571fb68f8b13f
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFFlowRemovedTest.java
@@ -0,0 +1,43 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.OFFlowRemoved.OFFlowRemovedReason;
+import org.openflow.util.OFTestCase;
+
+public class OFFlowRemovedTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFFlowRemoved msg = (OFFlowRemoved) messageFactory
+                .getMessage(OFType.FLOW_REMOVED);
+        msg.setMatch(new OFMatch());
+        byte[] hwAddr = new byte[6];
+        msg.getMatch().setDataLayerDestination(hwAddr);
+        msg.getMatch().setDataLayerSource(hwAddr);
+        msg.setReason(OFFlowRemovedReason.OFPRR_DELETE);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.FLOW_REMOVED, msg.getType());
+        TestCase.assertEquals(OFFlowRemovedReason.OFPRR_DELETE, msg.getReason());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFGetConfigReplyTest.java b/src/test/java/org/openflow/protocol/OFGetConfigReplyTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1f1f671a6767bb11dc3993c65fc21845d0820ab
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFGetConfigReplyTest.java
@@ -0,0 +1,38 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFGetConfigReplyTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFSetConfig msg = (OFSetConfig) messageFactory
+                .getMessage(OFType.SET_CONFIG);
+        msg.setFlags((short) 1);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.SET_CONFIG, msg.getType());
+        TestCase.assertEquals((short)1, msg.getFlags());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFGetConfigRequestTest.java b/src/test/java/org/openflow/protocol/OFGetConfigRequestTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..94d9036e68dd1e0b6573148e068fb4380f9946ef
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFGetConfigRequestTest.java
@@ -0,0 +1,36 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFGetConfigRequestTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFGetConfigRequest msg = (OFGetConfigRequest) messageFactory
+                .getMessage(OFType.GET_CONFIG_REQUEST);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.GET_CONFIG_REQUEST, msg.getType());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFMatchTest.java b/src/test/java/org/openflow/protocol/OFMatchTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd7863acc12d49e89054ced08111def1c5559b6d
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFMatchTest.java
@@ -0,0 +1,92 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+public class OFMatchTest extends TestCase {
+    public void testFromString() {
+        OFMatch correct = new OFMatch();
+        OFMatch tester = new OFMatch();
+
+        // Various combinations of "all"/"any"
+        tester.fromString("OFMatch[]");
+        // correct is already wildcarded
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("all");
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("ANY");
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("");
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("[]");
+        TestCase.assertEquals(correct, tester);
+
+        // ip_src
+        correct.setWildcards(~OFMatch.OFPFW_NW_SRC_MASK);
+        correct.setNetworkSource(0x01010203);
+        tester.fromString("nw_src=1.1.2.3");
+        TestCase.assertEquals(correct.getNetworkSourceMaskLen(), tester
+                .getNetworkSourceMaskLen());
+        TestCase.assertEquals(correct, tester);
+        tester.fromString("IP_sRc=1.1.2.3");
+        TestCase.assertEquals(correct.getNetworkSourceMaskLen(), tester
+                .getNetworkSourceMaskLen());
+        TestCase.assertEquals(correct, tester);
+        
+        // 0xVlan
+        correct = new OFMatch();
+        correct.setDataLayerVirtualLan((short)65535);
+        correct.setWildcards(~OFMatch.OFPFW_DL_VLAN);
+        tester = new OFMatch();
+        tester.fromString("dl_vlan=0xffff");
+        TestCase.assertEquals(correct, tester);
+        }
+
+    public void testToString() {
+        OFMatch match = new OFMatch();
+        match.fromString("nw_dst=3.4.5.6/8");
+        TestCase.assertEquals(8, match.getNetworkDestinationMaskLen());
+        String correct = "OFMatch[nw_dst=3.0.0.0/8]";
+        String tester = match.toString();
+
+        TestCase.assertEquals(correct, tester);
+        tester = "OFMatch[dl_type=35020]";
+        correct = "OFMatch[dl_type=0x88cc]";
+        match = new OFMatch();
+        match.fromString(tester);
+        TestCase.assertEquals(correct, match.toString());
+        OFMatch match2 = new OFMatch();
+        match2.fromString(correct);
+        TestCase.assertEquals(match, match2);
+    }
+
+    public void testClone() {
+        OFMatch match1 = new OFMatch();
+        OFMatch match2 = match1.clone();
+        TestCase.assertEquals(match1, match2);
+        match2.setNetworkProtocol((byte) 4);
+        match2.setWildcards(match2.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
+        TestCase.assertNotSame(match1, match2);
+    }
+
+    public void testIpToString() {
+        String test = OFMatch.ipToString(-1);
+        TestCase.assertEquals("255.255.255.255", test);
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFMessageContextStoreTest.java b/src/test/java/org/openflow/protocol/OFMessageContextStoreTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..60a9e732b05ba2d03ccbf1c4b9793634cafdeb8a
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFMessageContextStoreTest.java
@@ -0,0 +1,31 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+public class OFMessageContextStoreTest extends TestCase {
+    public void testStoreAndGet() {
+        OFMessage msg = new OFMessage();
+        OFMessageContextStore<String> store = new OFMessageContextStore<String>(msg, this.getName());
+        String key = "mykey";
+        String value = "myvalue";
+        store.put(key, value);
+        TestCase.assertEquals(value, store.get(key));
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFPacketOutTest.java b/src/test/java/org/openflow/protocol/OFPacketOutTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..55b54552fe03b279f20f076dd8857994dded0e09
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFPacketOutTest.java
@@ -0,0 +1,45 @@
+package org.openflow.protocol;
+
+import org.junit.Test;
+
+public class OFPacketOutTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBothBufferIdAndPayloadSet() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.setBufferId(12);
+        packetOut.setPacketData(new byte[] { 1, 2, 3 });
+    }
+
+    @Test
+    public void testOnlyBufferIdSet() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.setBufferId(12);
+        packetOut.setPacketData(null);
+        packetOut.setPacketData(new byte[] {});
+        packetOut.validate();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testNeitherBufferIdNorPayloadSet() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.setBufferId(OFPacketOut.BUFFER_ID_NONE);
+        packetOut.setPacketData(null);
+        packetOut.validate();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testNeitherBufferIdNorPayloadSet2() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.setBufferId(OFPacketOut.BUFFER_ID_NONE);
+        packetOut.setPacketData(new byte[] {});
+        packetOut.validate();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testNeitherBufferIdNorPayloadSet3() {
+        OFPacketOut packetOut = new OFPacketOut();
+        packetOut.validate();
+    }
+
+}
diff --git a/src/test/java/org/openflow/protocol/OFPortConfigTest.java b/src/test/java/org/openflow/protocol/OFPortConfigTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b115ebc40027a15bfe2f1589d39855bc1051ba2
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFPortConfigTest.java
@@ -0,0 +1,39 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFPortConfigTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFPortMod msg = (OFPortMod) messageFactory
+                .getMessage(OFType.PORT_MOD);
+        msg.setHardwareAddress(new byte[6]);
+        msg.portNumber = 1;
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.PORT_MOD, msg.getType());
+        TestCase.assertEquals(1, msg.getPortNumber());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFPortStatusTest.java b/src/test/java/org/openflow/protocol/OFPortStatusTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fab64e03568194784f6b7eaf4518ece9a5017c0
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFPortStatusTest.java
@@ -0,0 +1,44 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.OFPortStatus.OFPortReason;
+import org.openflow.util.OFTestCase;
+
+public class OFPortStatusTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFPortStatus msg = (OFPortStatus) messageFactory
+                .getMessage(OFType.PORT_STATUS);
+        msg.setDesc(new OFPhysicalPort());
+        msg.getDesc().setHardwareAddress(new byte[6]);
+        msg.getDesc().setName("eth0");
+        msg.setReason((byte) OFPortReason.OFPPR_ADD.ordinal());
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.PORT_STATUS, msg.getType());
+        TestCase.assertEquals((byte) OFPortReason.OFPPR_ADD.ordinal(), msg
+                .getReason());
+        TestCase.assertNotNull(msg.getDesc());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFSetConfigTest.java b/src/test/java/org/openflow/protocol/OFSetConfigTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2a9e86f7720fb44baf87acaf487d901a2218e026
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFSetConfigTest.java
@@ -0,0 +1,38 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.util.OFTestCase;
+
+public class OFSetConfigTest extends OFTestCase {
+    public void testWriteRead() throws Exception {
+        OFGetConfigReply msg = (OFGetConfigReply) messageFactory
+                .getMessage(OFType.GET_CONFIG_REPLY);
+        msg.setFlags((short) 1);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(OFType.GET_CONFIG_REPLY, msg.getType());
+        TestCase.assertEquals((short)1, msg.getFlags());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFStatisticsReplyTest.java b/src/test/java/org/openflow/protocol/OFStatisticsReplyTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1885cae7b3d4731ccae5bfbe4fdb295951b1a760
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFStatisticsReplyTest.java
@@ -0,0 +1,77 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.OFMessageFactory;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.util.OFTestCase;
+
+public class OFStatisticsReplyTest extends OFTestCase {
+    public void testOFFlowStatisticsReply() throws Exception {
+        byte[] packet = new byte[] { 0x01, 0x11, 0x01, 0x2c, 0x00, 0x00, 0x00,
+                0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, (byte) 0xff,
+                (byte) 0xff, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00,
+                0x0a, 0x00, 0x00, 0x03, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, (byte) 0xa6,
+                (byte) 0xa6, 0x00, (byte) 0xff, (byte) 0xff, 0x00, 0x05, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                (byte) 0xc4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00,
+                0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x02, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x08, 0x06,
+                0x00, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x03, 0x0a, 0x00,
+                0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x3b, 0x2f, (byte) 0xfa, 0x40, (byte) 0xff, (byte) 0xff, 0x00,
+                0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+                0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x03, (byte) 0xff, (byte) 0xff, 0x00, 0x62, 0x08,
+                0x00, 0x00, 0x01, 0x62, 0x37, 0x0a, 0x00, 0x00, 0x02, 0x0a,
+                0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x3a, (byte) 0xc5, 0x2a, (byte) 0x80, (byte) 0xff,
+                (byte) 0xff, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xc4, 0x00, 0x00, 0x00,
+                0x08, 0x00, 0x02, 0x00, 0x00 };
+
+        OFMessageFactory factory = BasicFactory.getInstance();
+        ChannelBuffer packetBuf = ChannelBuffers.wrappedBuffer(packet);
+        List<OFMessage> msg = factory.parseMessage(packetBuf);
+        TestCase.assertNotNull(msg);
+        TestCase.assertEquals(msg.size(), 1);
+        TestCase.assertTrue(msg.get(0) instanceof OFStatisticsReply);
+        OFStatisticsReply sr = (OFStatisticsReply) msg.get(0);
+        TestCase.assertEquals(OFStatisticsType.FLOW, sr.getStatisticType());
+        TestCase.assertEquals(3, sr.getStatistics().size());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFStatisticsRequestTest.java b/src/test/java/org/openflow/protocol/OFStatisticsRequestTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fceb8955eb755a12bb03c68bd1102513874b06ab
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFStatisticsRequestTest.java
@@ -0,0 +1,79 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.OFMessageFactory;
+import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
+import org.openflow.protocol.statistics.OFStatisticsType;
+import org.openflow.protocol.statistics.OFVendorStatistics;
+import org.openflow.util.OFTestCase;
+
+public class OFStatisticsRequestTest extends OFTestCase {
+    public void testOFFlowStatisticsRequest() throws Exception {
+        byte[] packet = new byte[] { 0x01, 0x10, 0x00, 0x38, 0x00, 0x00, 0x00,
+                0x16, 0x00, 0x01, 0x00, 0x00, (byte) 0xff, (byte) 0xff,
+                (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                (byte) 0xff, 0x00, (byte) 0xff, (byte) 0xff };
+
+        OFMessageFactory factory = BasicFactory.getInstance();
+        ChannelBuffer packetBuf = ChannelBuffers.wrappedBuffer(packet);
+        List<OFMessage> msg = factory.parseMessage(packetBuf);
+        TestCase.assertNotNull(msg);
+        TestCase.assertEquals(msg.size(), 1);
+        TestCase.assertTrue(msg.get(0) instanceof OFStatisticsRequest);
+        OFStatisticsRequest sr = (OFStatisticsRequest) msg.get(0);
+        TestCase.assertEquals(OFStatisticsType.FLOW, sr.getStatisticType());
+        TestCase.assertEquals(1, sr.getStatistics().size());
+        TestCase.assertTrue(sr.getStatistics().get(0) instanceof OFFlowStatisticsRequest);
+    }
+
+    public void testOFStatisticsRequestVendor() throws Exception {
+        byte[] packet = new byte[] { 0x01, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00,
+                0x63, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x4c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x01, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x20,
+                (byte) 0xe0, 0x00, 0x11, 0x00, 0x0c, 0x29, (byte) 0xc5,
+                (byte) 0x95, 0x57, 0x02, 0x25, 0x5c, (byte) 0xca, 0x00, 0x02,
+                (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x50, 0x04,
+                0x00, 0x00, 0x00, 0x00, (byte) 0xff, 0x00, 0x00, 0x00,
+                (byte) 0xff, (byte) 0xff, 0x4e, 0x20 };
+
+        OFMessageFactory factory = BasicFactory.getInstance();
+        ChannelBuffer packetBuf = ChannelBuffers.wrappedBuffer(packet);
+        List<OFMessage> msg = factory.parseMessage(packetBuf);
+        TestCase.assertNotNull(msg);
+        TestCase.assertEquals(msg.size(), 1);
+        TestCase.assertTrue(msg.get(0) instanceof OFStatisticsRequest);
+        OFStatisticsRequest sr = (OFStatisticsRequest) msg.get(0);
+        TestCase.assertEquals(OFStatisticsType.VENDOR, sr.getStatisticType());
+        TestCase.assertEquals(1, sr.getStatistics().size());
+        TestCase.assertTrue(sr.getStatistics().get(0) instanceof OFVendorStatistics);
+        TestCase.assertEquals(68, ((OFVendorStatistics)sr.getStatistics().get(0)).getLength());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFStatisticsTypeTest.java b/src/test/java/org/openflow/protocol/OFStatisticsTypeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d44ef7f8e4553f3556efb0bb52ad193578c07bbf
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFStatisticsTypeTest.java
@@ -0,0 +1,37 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+import org.openflow.protocol.statistics.OFStatisticsType;
+
+
+public class OFStatisticsTypeTest extends TestCase {
+    @Test
+    public void testMapping() throws Exception {
+        TestCase.assertEquals(OFStatisticsType.DESC,
+                OFStatisticsType.valueOf((short) 0, OFType.STATS_REQUEST));
+        TestCase.assertEquals(OFStatisticsType.QUEUE,
+                OFStatisticsType.valueOf((short) 5, OFType.STATS_REQUEST));
+        TestCase.assertEquals(OFStatisticsType.VENDOR,
+                OFStatisticsType.valueOf((short) 0xffff, OFType.STATS_REQUEST));
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFTypeTest.java b/src/test/java/org/openflow/protocol/OFTypeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c6bf0a347454064d99f0f4ec1064d17cca23da9a
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFTypeTest.java
@@ -0,0 +1,39 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+
+public class OFTypeTest extends TestCase {
+
+    public void testOFTypeCreate() throws Exception {
+        OFType foo = OFType.HELLO;
+        Class<? extends OFMessage> c = foo.toClass();
+        TestCase.assertEquals(c, OFHello.class);
+    }
+
+    @Test
+    public void testMapping() throws Exception {
+        TestCase.assertEquals(OFType.HELLO, OFType.valueOf((byte) 0));
+        TestCase.assertEquals(OFType.BARRIER_REPLY, OFType.valueOf((byte) 19));
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/OFVendorTest.java b/src/test/java/org/openflow/protocol/OFVendorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0385f4415824d1c79408e93ac31de4be40f3e52
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/OFVendorTest.java
@@ -0,0 +1,226 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.protocol;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.vendor.OFByteArrayVendorData;
+import org.openflow.protocol.vendor.OFBasicVendorDataType;
+import org.openflow.protocol.vendor.OFBasicVendorId;
+import org.openflow.protocol.vendor.OFVendorData;
+import org.openflow.protocol.vendor.OFVendorId;
+import org.openflow.util.OFTestCase;
+
+public class OFVendorTest extends OFTestCase {
+
+    public static int ACME_VENDOR_ID = 0x00112233;
+    
+    static class AcmeVendorData implements OFVendorData {
+        protected int dataType;
+        
+        @Override
+        public int getLength() {
+            return 4;
+        }
+        
+        @Override
+        public void readFrom(ChannelBuffer data, int length) {
+            dataType = data.readInt();
+        }
+        
+        @Override
+        public void writeTo(ChannelBuffer data) {
+            data.writeInt(dataType);
+        }
+    }
+    
+    static class AcmeVendorData1 extends AcmeVendorData {
+        public short flags;
+        public short value;
+        
+        public static int DATA_TYPE = 1;
+        
+        public AcmeVendorData1() {
+        }
+        
+        public AcmeVendorData1(short flags, short value) {
+            this.dataType = DATA_TYPE;
+            this.flags = flags;
+            this.value = value;
+        }
+        
+        public short getFlags() {
+            return flags;
+        }
+        
+        public short getValue() {
+            return value;
+        }
+        
+        @Override
+        public int getLength() {
+            return 8;
+        }
+        
+        @Override
+        public void readFrom(ChannelBuffer data, int length) {
+            super.readFrom(data, length);
+            flags = data.readShort();
+            value = data.readShort();
+
+        }
+        @Override
+        public void writeTo(ChannelBuffer data) {
+            super.writeTo(data);
+            data.writeShort(flags);
+            data.writeShort(value);
+        }
+        
+        public static Instantiable<OFVendorData> getInstantiable() {
+            return new Instantiable<OFVendorData>() {
+                @Override
+                public OFVendorData instantiate() {
+                    return new AcmeVendorData1();
+                }
+            };
+        }
+    }
+    
+    static class AcmeVendorData2 extends AcmeVendorData {
+        public int type;
+        public int subtype;
+
+        public static int DATA_TYPE = 2;
+
+        public AcmeVendorData2() {
+        }
+        
+        public AcmeVendorData2(int type, int subtype) {
+            this.dataType = DATA_TYPE;
+            this.type = type;
+            this.subtype = subtype;
+        }
+        
+        public int getType() {
+            return type;
+        }
+        
+        public int getSubtype() {
+            return subtype;
+        }
+        
+        @Override
+        public int getLength() {
+            return 12;
+        }
+        
+        @Override
+        public void readFrom(ChannelBuffer data, int length) {
+            super.readFrom(data, length);
+            type = data.readShort();
+            subtype = data.readShort();
+
+        }
+        @Override
+        public void writeTo(ChannelBuffer data) {
+            super.writeTo(data);
+            data.writeShort(type);
+            data.writeShort(subtype);
+        }
+        
+        public static Instantiable<OFVendorData> getInstantiable() {
+            return new Instantiable<OFVendorData>() {
+                @Override
+                public OFVendorData instantiate() {
+                    return new AcmeVendorData2();
+                }
+            };
+        }
+    }
+    
+    {
+        OFBasicVendorId acmeVendorId = new OFBasicVendorId(ACME_VENDOR_ID, 4);
+        OFVendorId.registerVendorId(acmeVendorId);
+        OFBasicVendorDataType acmeVendorData1 = new OFBasicVendorDataType(
+            AcmeVendorData1.DATA_TYPE, AcmeVendorData1.getInstantiable());
+        acmeVendorId.registerVendorDataType(acmeVendorData1);
+        OFBasicVendorDataType acmeVendorData2 = new OFBasicVendorDataType(
+            AcmeVendorData2.DATA_TYPE, AcmeVendorData2.getInstantiable());
+        acmeVendorId.registerVendorDataType(acmeVendorData2);
+    }
+    
+    private OFVendor makeVendorMessage(int vendor) {
+        OFVendor msg = (OFVendor) messageFactory.getMessage(OFType.VENDOR);
+        msg.setVendorDataFactory(BasicFactory.getInstance());
+        msg.setVendor(vendor);
+        return msg;
+    }
+    
+    public void testWriteRead() throws Exception {
+        OFVendor msg = makeVendorMessage(1);
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        TestCase.assertEquals(1, msg.getVendor());
+    }
+    
+    public void testVendorData() throws Exception {
+        OFVendor msg = makeVendorMessage(ACME_VENDOR_ID);
+        OFVendorData vendorData = new AcmeVendorData1((short)11, (short)22);
+        msg.setVendorData(vendorData);
+        msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength());
+        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        assertEquals(ACME_VENDOR_ID, msg.getVendor());
+        AcmeVendorData1 vendorData1 = (AcmeVendorData1) msg.getVendorData();
+        assertEquals(11, vendorData1.getFlags());
+        assertEquals(22, vendorData1.getValue());
+        
+        vendorData = new AcmeVendorData2(33, 44);
+        msg.setVendorData(vendorData);
+        msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength());
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        assertEquals(ACME_VENDOR_ID, msg.getVendor());
+        AcmeVendorData2 vendorData2 = (AcmeVendorData2) msg.getVendorData();
+        assertEquals(33, vendorData2.getType());
+        assertEquals(44, vendorData2.getSubtype());
+        
+        final int DUMMY_VENDOR_ID = 55;
+        msg.setVendor(DUMMY_VENDOR_ID);
+        byte[] genericVendorDataBytes = new byte[] {0x55, 0x66};
+        vendorData = new OFByteArrayVendorData(genericVendorDataBytes);
+        msg.setVendorData(vendorData);
+        msg.setLengthU(OFVendor.MINIMUM_LENGTH + vendorData.getLength());
+        bb.clear();
+        msg.writeTo(bb);
+        msg.readFrom(bb);
+        assertEquals(DUMMY_VENDOR_ID, msg.getVendor());
+        OFByteArrayVendorData genericVendorData = (OFByteArrayVendorData) msg.getVendorData();
+        assertTrue(Arrays.equals(genericVendorDataBytes, genericVendorData.getBytes()));
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/WildcardsTest.java b/src/test/java/org/openflow/protocol/WildcardsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bf8d12314a070bc301a8ffda6a36ad02ff7d6a0
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/WildcardsTest.java
@@ -0,0 +1,162 @@
+package org.openflow.protocol;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.EnumSet;
+
+import org.junit.Test;
+import org.openflow.protocol.Wildcards.Flag;
+
+public class WildcardsTest {
+
+    @Test
+    public void testBasic() {
+        int[] intMasks = { 0, 0x3820e0, OFMatch.OFPFW_ALL_SANITIZED };
+        for (int i : intMasks) {
+            Wildcards w = Wildcards.of(i);
+            assertEquals(i, w.getInt());
+        }
+    }
+
+    @Test
+    public void testAllSanitize() {
+        Wildcards w = Wildcards.of(OFMatch.OFPFW_ALL);
+        assertEquals(OFMatch.OFPFW_ALL_SANITIZED, w.getInt());
+        assertTrue(w.isFull());
+        assertFalse(w.isExact());
+    }
+
+    @Test
+    public void testAll() {
+        Wildcards all = Wildcards.FULL;
+        assertTrue(all.isFull());
+        assertFalse(all.isExact());
+        assertEquals(0, all.getNwDstMask());
+        assertEquals(0, all.getNwSrcMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards stillAll = all.wildcard(Flag.IN_PORT);
+        assertTrue(stillAll.isFull());
+        assertEquals(all, stillAll);
+
+        // so is setting a >= 32 netmask
+
+        stillAll = all.withNwSrcMask(0);
+        assertTrue(stillAll.isFull());
+        assertEquals(all, stillAll);
+
+        stillAll = all.withNwDstMask(0);
+        assertTrue(stillAll.isFull());
+        assertEquals(all, stillAll);
+    }
+
+    @Test
+    public void testNone() {
+        Wildcards none = Wildcards.EXACT;
+        assertTrue(none.isExact());
+        assertEquals(32, none.getNwDstMask());
+        assertEquals(32, none.getNwSrcMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards stillNone = none.matchOn(Flag.IN_PORT);
+        assertTrue(stillNone.isExact());
+        assertEquals(none, stillNone);
+
+        // so is setting a >= 32 netmask
+        stillNone = none.withNwSrcMask(32);
+        assertTrue(stillNone.isExact());
+        assertEquals(none, stillNone);
+
+        stillNone = none.withNwDstMask(32);
+        assertTrue(stillNone.isExact());
+        assertEquals(none, stillNone);
+    }
+
+    @Test
+    public void testSetOneFlag() {
+        Wildcards none = Wildcards.EXACT;
+        assertTrue(none.isExact());
+        assertFalse(none.isWildcarded(Flag.DL_SRC));
+        Wildcards one = none.wildcard(Flag.DL_SRC);
+        assertFalse(one.isExact());
+        assertTrue(one.isWildcarded(Flag.DL_SRC));
+        assertEquals(OFMatch.OFPFW_DL_SRC, one.getInt());
+        assertEquals(EnumSet.of(Flag.DL_SRC), one.getWildcardedFlags());
+    }
+
+    @Test
+    public void testSetTwoFlags() {
+        Wildcards none = Wildcards.EXACT;
+
+        // set two flags
+        Wildcards two = none.wildcard(Flag.DL_SRC, Flag.DL_DST);
+        assertFalse(two.isExact());
+        assertTrue(two.isWildcarded(Flag.DL_SRC));
+        assertTrue(two.isWildcarded(Flag.DL_DST));
+        assertEquals(OFMatch.OFPFW_DL_SRC | OFMatch.OFPFW_DL_DST, two.getInt());
+        assertEquals(EnumSet.of(Flag.DL_SRC, Flag.DL_DST), two.getWildcardedFlags());
+
+        // unset dl_dst
+        Wildcards gone = two.matchOn(Flag.DL_DST);
+        assertFalse(gone.isExact());
+        assertTrue(gone.isWildcarded(Flag.DL_SRC));
+        assertFalse(gone.isWildcarded(Flag.DL_DST));
+        assertEquals(OFMatch.OFPFW_DL_SRC, gone.getInt());
+        assertEquals(EnumSet.of(Flag.DL_SRC), gone.getWildcardedFlags());
+    }
+
+    @Test
+    public void testSetNwSrc() {
+        Wildcards none = Wildcards.EXACT;
+        assertEquals(32, none.getNwSrcMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards nwSet = none.withNwSrcMask(8);
+        assertFalse(nwSet.isExact());
+        assertEquals(EnumSet.noneOf(Flag.class), nwSet.getWildcardedFlags());
+        assertEquals(8, nwSet.getNwSrcMask());
+        assertEquals((32 - 8) << OFMatch.OFPFW_NW_SRC_SHIFT, nwSet.getInt());
+    }
+
+    @Test
+    public void testSetNwDst() {
+        Wildcards none = Wildcards.EXACT;
+        assertEquals(32, none.getNwDstMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards nwSet = none.withNwDstMask(8);
+        assertFalse(nwSet.isExact());
+        assertEquals(EnumSet.noneOf(Flag.class), nwSet.getWildcardedFlags());
+        assertEquals(8, nwSet.getNwDstMask());
+        assertEquals((32 - 8) << OFMatch.OFPFW_NW_DST_SHIFT, nwSet.getInt());
+    }
+
+    @Test
+    public void testToString() {
+        String s = Wildcards.FULL.toString();
+        assertNotNull(s);
+        assertTrue(s.length() > 0);
+    }
+
+    @Test
+    public void testInvert() {
+        assertEquals(Wildcards.FULL, Wildcards.EXACT.inverted());
+
+        Wildcards some = Wildcards.of(Flag.DL_VLAN, Flag.DL_VLAN_PCP);
+        Wildcards inv = some.inverted();
+
+        for(Flag f : Flag.values()) {
+            boolean shouldBeSet = (f == Flag.DL_VLAN || f == Flag.DL_VLAN_PCP);
+
+            assertEquals("Flag " + f + " "
+                         + (shouldBeSet ? "should be set " : "should not be set"),
+                    shouldBeSet, some.isWildcarded(f));
+            assertEquals(!(f == Flag.DL_VLAN || f == Flag.DL_VLAN_PCP), inv.isWildcarded(f));
+        }
+        assertEquals(0, inv.getNwDstMask());
+        assertEquals(0, inv.getNwSrcMask());
+    }
+}
diff --git a/src/test/java/org/openflow/protocol/action/MockVendorAction.java b/src/test/java/org/openflow/protocol/action/MockVendorAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..49b69fb8181d4a6dd6959a40786d643fe05ead20
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/action/MockVendorAction.java
@@ -0,0 +1,41 @@
+package org.openflow.protocol.action;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+
+public class MockVendorAction extends OFActionVendor {
+    public static final int VENDOR_ID = 0xdeadbeef;
+
+    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+    private byte[] mockData;
+
+    public byte[] getMockData() {
+        return mockData;
+    }
+
+    public void setMockData(byte[] mockData) {
+        this.mockData = mockData;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+
+        int dataLength = getLength() - MINIMUM_LENGTH;
+        if(dataLength > 0) {
+            mockData = new byte[dataLength];
+            data.readBytes(mockData);
+        } else {
+            mockData = EMPTY_BYTE_ARRAY;
+        }
+
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeBytes(mockData);
+    }
+
+
+}
diff --git a/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java b/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..bbc254ca0074cc9e418c5541f976d000074cf0b1
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java
@@ -0,0 +1,15 @@
+package org.openflow.protocol.action;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.factory.OFVendorActionFactory;
+
+public class MockVendorActionFactory implements OFVendorActionFactory {
+
+    @Override
+    public OFActionVendor readFrom(ChannelBuffer data) {
+        MockVendorAction action = new MockVendorAction();
+        action.readFrom(data);
+        return action;
+    }
+
+}
diff --git a/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java b/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..31ad675d6a0a708c5a69a7ae3b0dcb21bc24e5c5
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java
@@ -0,0 +1,17 @@
+package org.openflow.protocol.action;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.openflow.protocol.factory.OFVendorActionRegistry;
+
+public class OFVendorActionRegistryTest {
+
+    @Test
+    public void test() {
+        MockVendorActionFactory factory = new MockVendorActionFactory();
+        OFVendorActionRegistry.getInstance().register(MockVendorAction.VENDOR_ID, factory);
+        assertEquals(factory, OFVendorActionRegistry.getInstance().get(MockVendorAction.VENDOR_ID));
+    }
+
+}
diff --git a/src/test/java/org/openflow/util/HexStringTest.java b/src/test/java/org/openflow/util/HexStringTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8f8ba4b89760e797255da01e3cecb162f0da41b
--- /dev/null
+++ b/src/test/java/org/openflow/util/HexStringTest.java
@@ -0,0 +1,88 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import org.junit.Test;
+
+import junit.framework.TestCase;
+
+/**
+ * Does hexstring conversion work?
+ * 
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ * 
+ */
+
+public class HexStringTest extends TestCase {
+    
+    @Test
+    public void testMarshalling() throws Exception {
+        String dpidStr = "00:00:00:23:20:2d:16:71";
+        long dpid = HexString.toLong(dpidStr);
+        String testStr = HexString.toHexString(dpid);
+        TestCase.assertEquals(dpidStr, testStr);
+    }
+    
+    @Test
+    public void testToLong() {
+        String dpidStr = "3e:1f:01:fc:72:8c:63:31";
+        long valid = 0x3e1f01fc728c6331L;
+        long testLong = HexString.toLong(dpidStr);
+        TestCase.assertEquals(valid, testLong);
+    }
+    
+    @Test
+    public void testToLongMSB() {
+        String dpidStr = "ca:7c:5e:d1:64:7a:95:9b";
+        long valid = -3856102927509056101L;
+        long testLong = HexString.toLong(dpidStr);
+        TestCase.assertEquals(valid, testLong);
+    }
+    
+    @Test
+    public void testToLongError() {
+        String dpidStr = "09:08:07:06:05:04:03:02:01";
+        try {
+            HexString.toLong(dpidStr);
+            fail("HexString.toLong() should have thrown a NumberFormatException");
+        }
+        catch (NumberFormatException expected) {
+            // do nothing
+        }
+    }
+
+    @Test
+    public void testToStringBytes() {
+        byte[] dpid = { 0, 0, 0, 0, 0, 0, 0, -1 };
+        String valid = "00:00:00:00:00:00:00:ff";
+        String testString = HexString.toHexString(dpid);
+        TestCase.assertEquals(valid, testString);
+    }
+    
+    @Test
+    public void testFromHexStringError() {
+        String invalidStr = "00:00:00:00:00:00:ffff";
+        try {
+            HexString.fromHexString(invalidStr);
+            fail("HexString.fromHexString() should have thrown a NumberFormatException");
+        }
+        catch (NumberFormatException expected) {
+            // do nothing
+        }
+    }
+}
diff --git a/src/test/java/org/openflow/util/OFTestCase.java b/src/test/java/org/openflow/util/OFTestCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..07bee2d589a1901ad1f77afc3a2ee262a48be429
--- /dev/null
+++ b/src/test/java/org/openflow/util/OFTestCase.java
@@ -0,0 +1,36 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.factory.OFMessageFactory;
+
+import junit.framework.TestCase;
+
+public class OFTestCase extends TestCase {
+    public OFMessageFactory messageFactory;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        messageFactory = BasicFactory.getInstance();
+    }
+
+    public void test() throws Exception {
+    }
+}
diff --git a/src/test/java/org/openflow/util/U16Test.java b/src/test/java/org/openflow/util/U16Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba87e7b122d5cdb101a6d5a74898a612cb57fcdd
--- /dev/null
+++ b/src/test/java/org/openflow/util/U16Test.java
@@ -0,0 +1,33 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import junit.framework.TestCase;
+
+public class U16Test extends TestCase {
+  /**
+   * Tests that we correctly translate unsigned values in and out of a short
+   * @throws Exception
+   */
+  public void test() throws Exception {
+      int val = 0xffff;
+      TestCase.assertEquals((short)-1, U16.t(val));
+      TestCase.assertEquals((short)32767, U16.t(0x7fff));
+      TestCase.assertEquals(val, U16.f((short)-1));
+  }
+}
diff --git a/src/test/java/org/openflow/util/U32Test.java b/src/test/java/org/openflow/util/U32Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..223c1034e74cef66403f3c786a30f771a88b970b
--- /dev/null
+++ b/src/test/java/org/openflow/util/U32Test.java
@@ -0,0 +1,32 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import junit.framework.TestCase;
+
+public class U32Test extends TestCase {
+  /**
+   * Tests that we correctly translate unsigned values in and out of an int
+   * @throws Exception
+   */
+  public void test() throws Exception {
+      long val = 0xffffffffL;
+      TestCase.assertEquals(-1, U32.t(val));
+      TestCase.assertEquals(val, U32.f(-1));
+  }
+}
diff --git a/src/test/java/org/openflow/util/U64Test.java b/src/test/java/org/openflow/util/U64Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a97e302f78e84700a0407b5770766eea339ffd4
--- /dev/null
+++ b/src/test/java/org/openflow/util/U64Test.java
@@ -0,0 +1,34 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import java.math.BigInteger;
+
+import junit.framework.TestCase;
+
+public class U64Test extends TestCase {
+  /**
+   * Tests that we correctly translate unsigned values in and out of a long
+   * @throws Exception
+   */
+  public void test() throws Exception {
+      BigInteger val = new BigInteger("ffffffffffffffff", 16);
+      TestCase.assertEquals(-1, U64.t(val));
+      TestCase.assertEquals(val, U64.f(-1));
+  }
+}
diff --git a/src/test/java/org/openflow/util/U8Test.java b/src/test/java/org/openflow/util/U8Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c06c4db31f56699dbcac37d1f4296d1ad16342d
--- /dev/null
+++ b/src/test/java/org/openflow/util/U8Test.java
@@ -0,0 +1,32 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import junit.framework.TestCase;
+
+public class U8Test extends TestCase {
+  /**
+   * Tests that we correctly translate unsigned values in and out of a byte
+   * @throws Exception
+   */
+  public void test() throws Exception {
+      short val = 0xff;
+      TestCase.assertEquals(-1, U8.t(val));
+      TestCase.assertEquals(val, U8.f((byte)-1));
+  }
+}
diff --git a/src/test/java/org/openflow/util/UnsignedTest.java b/src/test/java/org/openflow/util/UnsignedTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7cdf7391bccd390ca941338cf99563dbb9da229c
--- /dev/null
+++ b/src/test/java/org/openflow/util/UnsignedTest.java
@@ -0,0 +1,83 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    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 org.openflow.util;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+import junit.framework.TestCase;
+
+public class UnsignedTest extends TestCase {
+    public static String ULONG_MAX = "18446744073709551615";
+
+  /**
+   * Tests that we correctly extract an unsigned long into a BigInteger
+   * @throws Exception
+   */
+  public void testGetUnsignedLong() throws Exception {
+    ByteBuffer bb = ByteBuffer.allocate(8);
+    bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff);
+    bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff);
+    bb.position(0);
+    bb.limit(8);
+    BigInteger bi = Unsigned.getUnsignedLong(bb);
+    BigInteger uLongMax = new BigInteger(ULONG_MAX);
+    for (int i = 0; i < uLongMax.bitCount(); ++i) {
+        TestCase.assertTrue("Bit: " + i + " should be: " + uLongMax.testBit(i),
+                uLongMax.testBit(i) == bi.testBit(i));
+    }
+    TestCase.assertEquals(ULONG_MAX, bi.toString());
+
+    bb = ByteBuffer.allocate(10);
+    bb.put((byte)0x00);
+    bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff);
+    bb.put((byte)0xff).put((byte)0xff).put((byte)0xff).put((byte)0xff);
+    bb.put((byte)0x00);
+    bb.position(0);
+    bb.limit(10);
+    bi = Unsigned.getUnsignedLong(bb, 1);
+    uLongMax = new BigInteger(ULONG_MAX);
+    for (int i = 0; i < uLongMax.bitCount(); ++i) {
+        TestCase.assertTrue("Bit: " + i + " should be: " + uLongMax.testBit(i),
+                uLongMax.testBit(i) == bi.testBit(i));
+    }
+    TestCase.assertEquals(ULONG_MAX, bi.toString());
+  }
+
+  /**
+   * Tests that we correctly put an unsigned long into a ByteBuffer
+   * @throws Exception
+   */
+  public void testPutUnsignedLong() throws Exception {
+    ByteBuffer bb = ByteBuffer.allocate(8);
+    BigInteger uLongMax = new BigInteger(ULONG_MAX);
+    Unsigned.putUnsignedLong(bb, uLongMax);
+    for (int i = 0; i < 8; ++i) {
+        TestCase.assertTrue("Byte: " + i + " should be 0xff, was: " + bb.get(i),
+                (bb.get(i) & (short)0xff) == 0xff);
+    }
+
+    bb = ByteBuffer.allocate(10);
+    Unsigned.putUnsignedLong(bb, uLongMax, 1);
+    int offset = 1;
+    for (int i = 0; i < 8; ++i) {
+        TestCase.assertTrue("Byte: " + i + " should be 0xff, was: " +
+                bb.get(offset+i), (bb.get(offset+i) & (short)0xff) == 0xff);
+    }
+  }
+}