diff --git a/apps/circuitpusher/circuitpusher.py b/apps/circuitpusher/circuitpusher.py
index 6c1af0e83a1dfdb4def897e2295051f606d296eb..344ecd96029ab9494d9672257affa358c58519d6 100755
--- a/apps/circuitpusher/circuitpusher.py
+++ b/apps/circuitpusher/circuitpusher.py
@@ -94,14 +94,26 @@ if args.action=='add':
     result = os.popen(command).read()
     parsedResult = json.loads(result)
     print command+"\n"
-    sourceSwitch = parsedResult[0]['attachmentPoint'][0]['switchDPID']
+    
+    try:
+    	sourceSwitch = parsedResult[0]['attachmentPoint'][0]['switchDPID']
+    except IndexError:
+	print "ERROR : the specified end point (%s) must already been known to the controller (i.e., already have sent packets on the network, easy way to assure this is to do a ping (to any target) from the two hosts." % (args.srcAddress)
+	sys.exit()
+
     sourcePort = parsedResult[0]['attachmentPoint'][0]['port']
     
     command = "curl -s http://%s/wm/device/?ipv4=%s" % (args.controllerRestIp, args.dstAddress)
     result = os.popen(command).read()
     parsedResult = json.loads(result)
     print command+"\n"
-    destSwitch = parsedResult[0]['attachmentPoint'][0]['switchDPID']
+
+    try:
+        destSwitch = parsedResult[0]['attachmentPoint'][0]['switchDPID']
+    except IndexError:
+        print "ERROR : the specified end point (%s) must already been known to the controller (i.e., already have sent packets on the network, easy way to assure this is to do a ping (to any target) from the two hosts." % (args.dstAddress) 
+        sys.exit()
+ 
     destPort = parsedResult[0]['attachmentPoint'][0]['port']
     
     print "Creating circuit:"
diff --git a/build.xml b/build.xml
index bed6c6081d4964a5d764284d52b4dcfe6ad22b7a..1c0dfe8fa473331aaba42ac283c5e8b6134b92e5 100644
--- a/build.xml
+++ b/build.xml
@@ -44,8 +44,8 @@
     <property name="floodlight-test-jar" location="${target}/floodlight-test.jar"/>
     <property name="thrift.dir" value="${basedir}/src/main/thrift"/>
     <property name="thrift.out.dir" value="lib/gen-java"/>
-    <property name="ant.build.javac.source" value="1.6"/>
-    <property name="ant.build.javac.target" value="1.6"/>
+    <property name="ant.build.javac.source" value="1.7"/>
+    <property name="ant.build.javac.target" value="1.7"/>
     <property name="findbugs.home" value="../build/findbugs-2.0.2"/>
     <property name="findbugs.results" value="findbugs-results" />
     <property name="lib" location="lib"/>
@@ -75,6 +75,12 @@
         <include name="findbugs-annotations-2.0.1.jar" />
         <include name="findbugs-jsr305-2.0.1.jar" />
         <include name="derby-10.9.1.0.jar"/>
+    	<include name="openflowj-0.3.5-SNAPSHOT.jar"/>
+    	<include name="openflowj-0.3.5-SNAPSHOT-javadoc.jar"/>
+    	<include name="hamcrest-core-1.3.jar"/>
+    	<include name="hamcrest-integration-1.3.jar"/>
+    	<include name="hamcrest-library-1.3.jar"/>
+        <include name="j3dutils.jar"/>
     </patternset>
 
     <path id="classpath">
diff --git a/floodlight.sh b/floodlight.sh
index 5bc8564af7321c0a23968946edc347f4e861463a..9bdf2641155ee85bee34840e78a2c13d81e5deb7 100755
--- a/floodlight.sh
+++ b/floodlight.sh
@@ -25,10 +25,10 @@ JVM_OPTS="$JVM_OPTS -Dpython.security.respectJavaAccessibility=false"
     <root level="INFO">
         <appender-ref ref="STDOUT" />
     </root>
-    <logger name="org" level="WARN"/>
-    <logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
-    <logger name="net.floodlightcontroller" level="INFO"/>
-    <logger name="net.floodlightcontroller.logging" level="ERROR"/>
+    <logger name="org" level=“ALL”/>
+    <logger name="LogService" level=“DEBUG”/> <!-- Restlet access logging -->
+    <logger name="net.floodlightcontroller" level=“ALL”/>
+    <logger name="net.floodlightcontroller.logging" level=“ALL”/>
 </configuration>
 EOF_LOGBACK
 
diff --git a/lib/hamcrest-core-1.3.jar b/lib/hamcrest-core-1.3.jar
new file mode 100644
index 0000000000000000000000000000000000000000..9d5fe16e3dd37ebe79a36f61f5d0e1a69a653a8a
Binary files /dev/null and b/lib/hamcrest-core-1.3.jar differ
diff --git a/lib/hamcrest-integration-1.3.jar b/lib/hamcrest-integration-1.3.jar
new file mode 100644
index 0000000000000000000000000000000000000000..e07447a0cdcd5897de3556296e184ab8d956af4f
Binary files /dev/null and b/lib/hamcrest-integration-1.3.jar differ
diff --git a/lib/hamcrest-library-1.3.jar b/lib/hamcrest-library-1.3.jar
new file mode 100644
index 0000000000000000000000000000000000000000..9eac80d7bae2bd61a36c1d0dcb27d2407430f316
Binary files /dev/null and b/lib/hamcrest-library-1.3.jar differ
diff --git a/lib/j3dutils.jar b/lib/j3dutils.jar
new file mode 100644
index 0000000000000000000000000000000000000000..6e5e44112affe0084c91be22645114ba9096ff76
Binary files /dev/null and b/lib/j3dutils.jar differ
diff --git a/lib/openflowj-0.3.5-SNAPSHOT-javadoc.jar b/lib/openflowj-0.3.5-SNAPSHOT-javadoc.jar
new file mode 100644
index 0000000000000000000000000000000000000000..49c3f4551b6588514f1b18581e274c688fbf5bce
Binary files /dev/null and b/lib/openflowj-0.3.5-SNAPSHOT-javadoc.jar differ
diff --git a/lib/openflowj-0.3.5-SNAPSHOT-sources.jar b/lib/openflowj-0.3.5-SNAPSHOT-sources.jar
new file mode 100644
index 0000000000000000000000000000000000000000..5786ced23c2b240d20195b3acef6e18a3e676db5
Binary files /dev/null and b/lib/openflowj-0.3.5-SNAPSHOT-sources.jar differ
diff --git a/lib/openflowj-0.3.5-SNAPSHOT-tests.jar b/lib/openflowj-0.3.5-SNAPSHOT-tests.jar
new file mode 100644
index 0000000000000000000000000000000000000000..67646a8c35818bb017599121b16d7aff19718d9a
Binary files /dev/null and b/lib/openflowj-0.3.5-SNAPSHOT-tests.jar differ
diff --git a/lib/openflowj-0.3.5-SNAPSHOT.jar b/lib/openflowj-0.3.5-SNAPSHOT.jar
new file mode 100644
index 0000000000000000000000000000000000000000..dcb33c10e467f75f74ea96062893d7608d6ce71c
Binary files /dev/null and b/lib/openflowj-0.3.5-SNAPSHOT.jar differ
diff --git a/logback.xml b/logback.xml
index 29427f88cf4483609142d068b5eb0ae71bf18c69..a25cc7f639cbb65d64acfca5a5df190e83c674d4 100644
--- a/logback.xml
+++ b/logback.xml
@@ -4,12 +4,12 @@
       <pattern>%date{yyyy-MM-dd HH:mm:ss.S} %-5level [%logger{15}] %msg%n</pattern>
     </encoder>
   </appender>
-  <root level="INFO">
+  <root level="DEBUG">
     <appender-ref ref="STDOUT" />
   </root>
-  <logger name="org" level="WARN"/>
-  <logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
-  <logger name="net.floodlightcontroller" level="INFO"/>
-  <logger name="net.floodlightcontroller.logging" level="WARN"/>
-  <logger name="org.sdnplatform" level="INFO"/>
+  <logger name="org" level="DEBUG"/>
+  <logger name="LogService" level="DEBUG"/> <!-- Restlet access logging -->
+  <logger name="net.floodlightcontroller" level="DEBUG"/>
+  <logger name="net.floodlightcontroller.logging" level="DEBUG"/>
+  <logger name="org.sdnplatform" level="DEBUG"/>
 </configuration>
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionBigSwitchVendor.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionBigSwitchVendor.java
deleted file mode 100644
index 147820f479bea7596961e29225931f5856118648..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionBigSwitchVendor.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.action.OFActionVendor;
-
-public abstract class OFActionBigSwitchVendor extends OFActionVendor {
-    public static int MINIMUM_LENGTH = 12;
-    public static int BSN_VENDOR_ID = OFBigSwitchVendorData.BSN_VENDOR_ID;
-
-    protected int subtype;
-
-    protected OFActionBigSwitchVendor(int subtype) {
-        super();
-        super.setLength((short)MINIMUM_LENGTH);
-        super.setVendor(BSN_VENDOR_ID);
-        this.subtype = subtype;
-    }
-
-    public int getSubtype() {
-        return this.subtype;
-    }
-
-    public void setSubtype(int subtype) {
-        this.subtype = subtype;
-    }
-
-    @Override
-    public void readFrom(ChannelBuffer data) {
-        super.readFrom(data);
-        this.subtype = data.readInt();
-    }
-
-    @Override
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-        data.writeInt(this.subtype);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 379;
-        int result = super.hashCode();
-        result = prime * result + vendor;
-        result = prime * result + subtype;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!super.equals(obj)) {
-            return false;
-        }
-        if (!(obj instanceof OFActionBigSwitchVendor)) {
-            return false;
-        }
-        OFActionBigSwitchVendor other = (OFActionBigSwitchVendor) obj;
-        if (subtype != other.subtype) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return super.toString() + "; subtype=" + subtype;
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionMirror.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionMirror.java
deleted file mode 100644
index 3b55ca7201234a7d39f76db2416fc3ac1a1e1298..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionMirror.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-
-
-public class OFActionMirror extends OFActionBigSwitchVendor {
-    public final static int MINIMUM_LENGTH = 12;
-    public final static int BSN_ACTION_MIRROR = 1;
-
-    protected int destPort;
-    protected int vlanTag;
-    protected byte copyStage;
-    protected byte pad0;
-    protected byte pad1;
-    protected byte pad2;
-
-    public OFActionMirror(short portNumber) {
-        super(BSN_ACTION_MIRROR);
-        super.setLength((short) (OFActionBigSwitchVendor.MINIMUM_LENGTH + OFActionMirror.MINIMUM_LENGTH));
-        this.destPort = portNumber;
-        this.vlanTag = 0;
-        this.copyStage = 0;
-    }
-
-    public int getDestPort() {
-        return destPort;
-    }
-
-    public void setDestPort(int destPort) {
-        this.destPort = destPort;
-    }
-
-    public int getVlanTag() {
-        return vlanTag;
-    }
-
-    public void setVlanTag(int vlanTag) {
-        this.vlanTag = vlanTag;
-    }
-
-    public byte getCopyStage() {
-        return copyStage;
-    }
-
-    public void setCopyStage(byte copyStage) {
-        this.copyStage = copyStage;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = super.hashCode();
-        result = prime * result + copyStage;
-        result = prime * result + destPort;
-        result = prime * result + pad0;
-        result = prime * result + pad1;
-        result = prime * result + pad2;
-        result = prime * result + vlanTag;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (!super.equals(obj)) return false;
-        if (getClass() != obj.getClass()) return false;
-        OFActionMirror other = (OFActionMirror) obj;
-        if (copyStage != other.copyStage) return false;
-        if (destPort != other.destPort) return false;
-        if (pad0 != other.pad0) return false;
-        if (pad1 != other.pad1) return false;
-        if (pad2 != other.pad2) return false;
-        if (vlanTag != other.vlanTag) return false;
-        return true;
-    }
-
-    @Override
-    public void readFrom(ChannelBuffer data) {
-        super.readFrom(data);
-        this.destPort = data.readInt();
-        this.vlanTag = data.readInt();
-        this.copyStage = data.readByte();
-        this.pad0 = data.readByte();
-        this.pad1 = data.readByte();
-        this.pad2 = data.readByte();
-    }
-
-    @Override
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-        data.writeInt(this.destPort);
-        data.writeInt(this.vlanTag);
-        data.writeByte(this.copyStage);
-        data.writeByte(this.pad0);
-        data.writeByte(this.pad1);
-        data.writeByte(this.pad2);
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append(type);
-        builder.append("[");
-        builder.append("BSN-MIRROR");
-        builder.append(", Dest Port: ");
-        builder.append(destPort);
-        builder.append(", Vlan: ");
-        builder.append(vlanTag);
-        builder.append(", Copy Stage: ");
-        builder.append(copyStage);
-        builder.append("]");
-        return builder.toString();
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraTtlDecrement.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraTtlDecrement.java
deleted file mode 100644
index 51b829a815f5ee92e2972de55bfb1c94cee4a38a..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraTtlDecrement.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-
-public class OFActionNiciraTtlDecrement extends OFActionNiciraVendor {
-    public static int MINIMUM_LENGTH_TTL_DECREMENT = 16;
-    public static final short TTL_DECREMENT_SUBTYPE = 18;
-    
-    
-    public OFActionNiciraTtlDecrement() {
-        super(TTL_DECREMENT_SUBTYPE);
-        super.setLength((short)MINIMUM_LENGTH_TTL_DECREMENT);
-    }
-    
-    @Override
-    public void readFrom(ChannelBuffer data) {
-        super.readFrom(data);
-        data.skipBytes(6);  // pad
-    }
-    
-    @Override
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-        data.writeZero(6);
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append(type);
-        builder.append("[");
-        builder.append("NICIRA-TTL-DECR");
-        builder.append("]");
-        return builder.toString();
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraVendor.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraVendor.java
deleted file mode 100644
index b4d9fa523baff8fb12150d2e5665300b7b4cd39a..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionNiciraVendor.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.action.OFActionVendor;
-import org.openflow.vendor.nicira.OFNiciraVendorData;
-
-/**
- * FIXME: this should really be handled by a consistent parse tree for
- * different vendor actions but for the time being this works and gets the
- * job done. 
- * 
- * @author gregor
- *
- */
-public class OFActionNiciraVendor extends OFActionVendor {
-    public static int MINIMUM_LENGTH = 16;
-    public static int NICIRA_VENDOR_ID = OFNiciraVendorData.NX_VENDOR_ID;
-    
-    protected short subtype;
-
-    protected OFActionNiciraVendor(short subtype) {
-        // We don't allow direct instantiation of this class because its 
-        // minimum length is 16 and the only way to guarantee this is by 
-        // having a subclass that properly adds padding. 
-        super();
-        super.setLength((short)MINIMUM_LENGTH);
-        super.setVendor(NICIRA_VENDOR_ID);
-        this.subtype = subtype;
-    }
-    
-    public short getSubtype() {
-        return this.subtype;
-    }
-    
-    public void setSubtype(short subtype) {
-        this.subtype = subtype;
-    }
-
-    @Override
-    public void readFrom(ChannelBuffer data) {
-        super.readFrom(data);
-        this.subtype = data.readShort();
-    }
-
-    @Override
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-        data.writeShort(this.subtype);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 379;
-        int result = super.hashCode();
-        result = prime * result + vendor;
-        result = prime * result + subtype;
-        return result;
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!super.equals(obj)) {
-            return false;
-        }
-        if (!(obj instanceof OFActionNiciraVendor)) {
-            return false;
-        }
-        OFActionNiciraVendor other = (OFActionNiciraVendor) obj;
-        if (subtype != other.subtype) {
-            return false;
-        }
-        return true;
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFActionTunnelDstIP.java b/src/main/java/com/bigswitch/floodlight/vendor/OFActionTunnelDstIP.java
deleted file mode 100644
index 9cd851c634178c22af5edd467712f51104e53e88..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFActionTunnelDstIP.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import net.floodlightcontroller.core.web.serializers.IPv4Serializer;
-import net.floodlightcontroller.packet.IPv4;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-
-public class OFActionTunnelDstIP extends OFActionBigSwitchVendor {
-    public final static int MINIMUM_LENGTH_TUNNEL_DST = 16;
-    public  final static int SET_TUNNEL_DST_SUBTYPE = 2;
-
-    protected int dstIPAddr;
-
-    public OFActionTunnelDstIP() {
-        super(SET_TUNNEL_DST_SUBTYPE);
-        super.setLength((short)MINIMUM_LENGTH_TUNNEL_DST);
-    }
-
-    public OFActionTunnelDstIP(int dstIPAddr) {
-        this();
-        this.dstIPAddr = dstIPAddr;
-    }
-
-    @JsonSerialize(using=IPv4Serializer.class)
-    public int getTunnelDstIP() {
-        return this.dstIPAddr;
-    }
-
-    public void setTunnelDstIP(int ipAddr) {
-        this.dstIPAddr = ipAddr;
-    }
-
-    @Override
-    public void readFrom(ChannelBuffer data) {
-        super.readFrom(data);
-        this.dstIPAddr = data.readInt();
-    }
-
-    @Override
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-        data.writeInt(this.dstIPAddr);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = super.hashCode();
-        result = prime * result + dstIPAddr;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (!super.equals(obj)) return false;
-        if (getClass() != obj.getClass()) return false;
-        OFActionTunnelDstIP other = (OFActionTunnelDstIP) obj;
-        if (dstIPAddr != other.dstIPAddr) return false;
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append(type);
-        builder.append("[");
-        builder.append("BSN-SET-TUNNEL-DST-IP");
-        builder.append(", IP: ");
-        builder.append(IPv4.fromIPv4Address(dstIPAddr));
-        builder.append("]");
-        return builder.toString();
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorActionFactory.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorActionFactory.java
deleted file mode 100644
index 3b58cabf632df06fbbc187e3f8e0bdf14efa05cd..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorActionFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.action.OFActionVendor;
-import org.openflow.protocol.factory.OFVendorActionFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class OFBigSwitchVendorActionFactory implements OFVendorActionFactory {
-    protected static Logger logger =
-            LoggerFactory.getLogger(OFBigSwitchVendorActionFactory.class);
-
-    static class OFActionBigSwitchVendorDemux extends OFActionBigSwitchVendor {
-        OFActionBigSwitchVendorDemux() {
-            super((short) 0);
-        }
-    }
-
-    @Override
-    public OFActionVendor readFrom(ChannelBuffer data) {
-        data.markReaderIndex();
-        OFActionBigSwitchVendor demux = new OFActionBigSwitchVendorDemux();
-        demux.readFrom(data);
-        data.resetReaderIndex();
-
-        switch(demux.getSubtype()) {
-            case OFActionMirror.BSN_ACTION_MIRROR:
-                OFActionMirror mirrorAction = new OFActionMirror((short) 0);
-                mirrorAction.readFrom(data);
-                return mirrorAction;
-            case OFActionTunnelDstIP.SET_TUNNEL_DST_SUBTYPE:
-                OFActionTunnelDstIP tunnelAction = new OFActionTunnelDstIP();
-                tunnelAction.readFrom(data);
-                return tunnelAction;
-            default:
-                logger.error("Unknown BSN vendor action subtype: "+demux.getSubtype());
-                return null;
-        }
-    }
-
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorData.java
deleted file mode 100644
index b5288f1381a5d5706a1813a4ff625fbcf94ffc3e..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorData.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.vendor.OFVendorData;
-
-/**
- * Base class for vendor data corresponding to BigSwitch vendor extensions
- * BigSwitch vendor data always starts with a 4-byte integer data type value
- *
- * @author Munish Mehta (munish.mehta@bigswitch.com)
- */
-public class OFBigSwitchVendorData implements OFVendorData {
-
-    public static final int BSN_VENDOR_ID = 0x005c16c7;
-
-    /**
-     * The value of the integer data type at the beginning of the vendor data
-     */
-    protected int dataType;
-
-    /**
-     * Construct BigSwitch vendor data with the specified data type
-     * @param dataType : the data type value at the beginning (opcode)
-     */
-    public OFBigSwitchVendorData(int dataType) {
-        super();
-        this.dataType = dataType;
-    }
-
-    /**
-     * Get the data type value at the beginning of the vendor data
-     * @return
-     */
-    public int getDataType() {
-        return dataType;
-    }
-
-    /**
-     * Set the data type value
-     * @param dataType
-     */
-    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);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + dataType;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (getClass() != obj.getClass()) return false;
-        OFBigSwitchVendorData other = (OFBigSwitchVendorData) obj;
-        if (dataType != other.dataType) return false;
-        return true;
-    }
-
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorExtensions.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorExtensions.java
deleted file mode 100644
index 0b3d069c4a1af871433509094f7a73e001fda17e..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFBigSwitchVendorExtensions.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.openflow.protocol.vendor.OFBasicVendorDataType;
-import org.openflow.protocol.vendor.OFBasicVendorId;
-import org.openflow.protocol.vendor.OFVendorId;
-
-public class OFBigSwitchVendorExtensions {
-    private static boolean initialized = false;
-
-    public static synchronized void initialize() {
-        if (initialized)
-            return;
-    
-        OFBasicVendorId bsnVendorId = 
-                new OFBasicVendorId(OFBigSwitchVendorData.BSN_VENDOR_ID, 4);
-        OFVendorId.registerVendorId(bsnVendorId);
-
-        // register data types used for big tap
-        OFBasicVendorDataType setEntryVendorData =
-                new OFBasicVendorDataType(
-                         OFNetmaskSetVendorData.BSN_SET_IP_MASK_ENTRY,
-                         OFNetmaskSetVendorData.getInstantiable());
-        bsnVendorId.registerVendorDataType(setEntryVendorData);
-
-        OFBasicVendorDataType getEntryVendorDataRequest =
-                new OFBasicVendorDataType(
-                         OFNetmaskGetVendorDataRequest.BSN_GET_IP_MASK_ENTRY_REQUEST,
-                         OFNetmaskGetVendorDataRequest.getInstantiable());
-        bsnVendorId.registerVendorDataType(getEntryVendorDataRequest);
-
-        OFBasicVendorDataType getEntryVendorDataReply =
-                new OFBasicVendorDataType(
-                         OFNetmaskGetVendorDataReply.BSN_GET_IP_MASK_ENTRY_REPLY,
-                         OFNetmaskGetVendorDataReply.getInstantiable());
-        bsnVendorId.registerVendorDataType(getEntryVendorDataReply);
-
-        // register data types used for tunneling
-        OFBasicVendorDataType getIntfIPVendorDataRequest = 
-                new OFBasicVendorDataType(
-                          OFInterfaceIPRequestVendorData.BSN_GET_INTERFACE_IP_REQUEST,
-                          OFInterfaceIPRequestVendorData.getInstantiable());
-        bsnVendorId.registerVendorDataType(getIntfIPVendorDataRequest);
-
-        OFBasicVendorDataType getIntfIPVendorDataReply = 
-                new OFBasicVendorDataType(
-                          OFInterfaceIPReplyVendorData.BSN_GET_INTERFACE_IP_REPLY,
-                          OFInterfaceIPReplyVendorData.getInstantiable());
-        bsnVendorId.registerVendorDataType(getIntfIPVendorDataReply);
-
-        
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableSetVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableSetVendorData.java
deleted file mode 100644
index 3dd8310148e423889250a281ee240ef6e13f7f3c..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableSetVendorData.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.openflow.protocol.Instantiable;
-import org.openflow.protocol.vendor.OFVendorData;
-
-public class OFBsnL2TableSetVendorData extends OFBsnL2TableVendorData {
-
-    protected static Instantiable<OFVendorData> instantiableSingleton = 
-        new Instantiable<OFVendorData>() {
-            public OFVendorData instantiate() {
-                return new OFBsnL2TableSetVendorData();
-            }
-        };
-        
-    public static final int BSN_L2_TABLE_SET = 12;
-        
-    /**
-     * @return a subclass of Instantiable<OFVendorData> that instantiates
-     *         an instance of OFBsnL2TableSetVendorData.
-     */
-    public static Instantiable<OFVendorData> getInstantiable() {
-        return instantiableSingleton;
-    }
-    
-    public OFBsnL2TableSetVendorData() {
-        super(BSN_L2_TABLE_SET);
-    }
-    
-    public OFBsnL2TableSetVendorData(boolean l2TableEnabled, 
-                                     short l2TablePriority) {
-        super(BSN_L2_TABLE_SET, l2TableEnabled, l2TablePriority);
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableVendorData.java
deleted file mode 100644
index 14e6178d1b4793855b1b6ee8d0946c6f87fa79d0..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnL2TableVendorData.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-
-public class OFBsnL2TableVendorData extends OFBigSwitchVendorData {
-    /*
-     * uint8_t l2_table_enable;    // 1 == enabled, 0 == disabled
-     * uint8_t pad;
-     * uint16_t l2_table_priority;  // priority of all flows in L2 table
-     * uint8_t pad[4];
-     */
-    protected boolean l2TableEnabled;
-    protected short l2TablePriority;
-    
-    
-    public OFBsnL2TableVendorData(int dataType) {
-        super(dataType);
-        this.l2TableEnabled = false;
-        this.l2TablePriority = (short)0;
-    }
-
-
-    public OFBsnL2TableVendorData(int dataType, boolean l2TableEnabled,
-                                  short l2TablePriority) {
-        super(dataType);
-        this.l2TableEnabled = l2TableEnabled;
-        this.l2TablePriority = l2TablePriority;
-    }
-
-
-    public boolean isL2TableEnabled() {
-        return l2TableEnabled;
-    }
-
-
-    public short getL2TablePriority() {
-        return l2TablePriority;
-    }
-
-
-    public void setL2TableEnabled(boolean l2TableEnabled) {
-        this.l2TableEnabled = l2TableEnabled;
-    }
-
-
-    public void setL2TablePriority(short l2TablePriority) {
-        this.l2TablePriority = l2TablePriority;
-    }
-    
-    
-    @Override
-    public int getLength() {
-        return super.getLength() + 8; // 8 additional bytes
-    }
-    
-    /*
-     * (non-Javadoc)
-     * @see com.bigswitch.floodlight.vendor.OFBigSwitchVendorData#readFrom(org.jboss.netty.buffer.ChannelBuffer, int)
-     */
-    @Override 
-    public void readFrom(ChannelBuffer data, int length) {
-        super.readFrom(data, length);
-        l2TableEnabled = (data.readByte() == 0) ? false : true;
-        data.readByte();  // pad
-        l2TablePriority = data.readShort();
-        data.readInt();   // 4 bad bytes
-    }
-    
-    /*
-     * (non-Javadoc)
-     * @see com.bigswitch.floodlight.vendor.OFBigSwitchVendorData#writeTo(org.jboss.netty.buffer.ChannelBuffer)
-     */
-    @Override
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-        data.writeByte(isL2TableEnabled() ? 1 : 0);
-        data.writeByte(0);  // pad
-        data.writeShort(l2TablePriority);
-        data.writeInt(0);   // 4 pad bytes
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnPktinSuppressionSetRequestVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFBsnPktinSuppressionSetRequestVendorData.java
deleted file mode 100644
index da5c33db03397b80d540c6d1c71f2f37e774ac3b..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFBsnPktinSuppressionSetRequestVendorData.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.Instantiable;
-import org.openflow.protocol.vendor.OFVendorData;
-
-public class OFBsnPktinSuppressionSetRequestVendorData
-        extends OFBigSwitchVendorData {
-    protected static Instantiable<OFVendorData> instantiableSingleton =
-            new Instantiable<OFVendorData>() {
-                @Override
-                public OFVendorData instantiate() {
-                    return new OFBsnL2TableSetVendorData();
-                }
-            };
-
-    /**
-     * @return a subclass of Instantiable<OFVendorData> that instantiates
-     *         an instance of OFBsnL2TableSetVendorData.
-     */
-    public static Instantiable<OFVendorData> getInstantiable() {
-        return instantiableSingleton;
-    }
-
-    public static final int BSN_PKTIN_SUPPRESSION_SET_REQUEST = 11;
-    /*
-     * uint8_t enabled;        // 0 to disable the extension, 1 to enable it
-     * uint8_t pad;
-     * uint16_t idle_timeout;  // idle_timeout for new flows
-     * uint16_t hard_timeout;  // idle_timeout for new flows
-     * uint16_t priority;      // priority for new flows
-     * uint64_t cookie;        // cookie for new flows
-     */
-
-    protected boolean suppressionEnabled;
-    protected short idleTimeout;
-    protected short hardTimeout;
-    protected short priority;
-    protected long cookie;
-
-    public OFBsnPktinSuppressionSetRequestVendorData() {
-        super(BSN_PKTIN_SUPPRESSION_SET_REQUEST);
-    }
-
-    public OFBsnPktinSuppressionSetRequestVendorData(boolean suppressionEnabled,
-                                                     short idleTimeout,
-                                                     short hardTimeout,
-                                                     short priority,
-                                                     long cookie) {
-        super(BSN_PKTIN_SUPPRESSION_SET_REQUEST);
-        this.suppressionEnabled = suppressionEnabled;
-        this.idleTimeout = idleTimeout;
-        this.hardTimeout = hardTimeout;
-        this.priority = priority;
-        this.cookie = cookie;
-    }
-
-    public boolean isSuppressionEnabled() {
-        return suppressionEnabled;
-    }
-
-    public short getIdleTimeout() {
-        return idleTimeout;
-    }
-
-    public short getHardTimeout() {
-        return hardTimeout;
-    }
-
-    public short getPriority() {
-        return priority;
-    }
-
-    public long getCookie() {
-        return cookie;
-    }
-
-    public void setSuppressionEnabled(boolean suppressionEnabled) {
-        this.suppressionEnabled = suppressionEnabled;
-    }
-
-    public void setIdleTimeout(short idleTimeout) {
-        this.idleTimeout = idleTimeout;
-    }
-
-    public void setHardTimeout(short hardTimeout) {
-        this.hardTimeout = hardTimeout;
-    }
-
-    public void setPriority(short priority) {
-        this.priority = priority;
-    }
-
-    public void setCookie(long cookie) {
-        this.cookie = cookie;
-    }
-
-    @Override
-    public int getLength() {
-        return super.getLength() + 16;
-    }
-
-    @Override
-    public void readFrom(ChannelBuffer data, int length) {
-        super.readFrom(data, length);
-        suppressionEnabled = (data.readByte() != 0);
-        data.readByte();
-        idleTimeout = data.readShort();
-        hardTimeout = data.readShort();
-        priority = data.readShort();
-        cookie = data.readLong();
-    }
-
-    @Override
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-        data.writeByte(suppressionEnabled ? 1 : 0);
-        data.writeByte(0); // pad
-        data.writeShort(idleTimeout);
-        data.writeShort(hardTimeout);
-        data.writeShort(priority);
-        data.writeLong(cookie);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = super.hashCode();
-        result = prime * result + (int) (cookie ^ (cookie >>> 32));
-        result = prime * result + hardTimeout;
-        result = prime * result + idleTimeout;
-        result = prime * result + priority;
-        result = prime * result + (suppressionEnabled ? 1231 : 1237);
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (!super.equals(obj)) return false;
-        if (getClass() != obj.getClass()) return false;
-        OFBsnPktinSuppressionSetRequestVendorData other = (OFBsnPktinSuppressionSetRequestVendorData) obj;
-        if (cookie != other.cookie) return false;
-        if (hardTimeout != other.hardTimeout) return false;
-        if (idleTimeout != other.idleTimeout) return false;
-        if (priority != other.priority) return false;
-        if (suppressionEnabled != other.suppressionEnabled) return false;
-        return true;
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPReplyVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPReplyVendorData.java
deleted file mode 100644
index 380ba43c299c7ccaaccafbdd846e92ea72a848ef..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPReplyVendorData.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.Instantiable;
-import org.openflow.protocol.vendor.OFVendorData;
-
-public class OFInterfaceIPReplyVendorData extends OFBigSwitchVendorData {
-    
-    protected List<OFInterfaceVendorData> interfaces;
-    protected int length;
-    
-    protected static Instantiable<OFVendorData> instantiable =
-            new Instantiable<OFVendorData>() {
-                public OFVendorData instantiate() {
-                    return new OFInterfaceIPReplyVendorData();
-                }
-    };
-    
-    /**
-     * @return a subclass of Instantiable<OFVendorData> that instantiates
-     *         an instance of OFInterfaceIPReplyVendorData.
-     */
-    public static Instantiable<OFVendorData> getInstantiable() {
-        return instantiable;
-    }
-
-    /**
-     * Opcode/dataType to reply with IP addresses of all interfaces
-     */
-    public static final int BSN_GET_INTERFACE_IP_REPLY = 10;
-
-    /**
-     * Construct an interface IP reply vendor data 
-     */
-    public OFInterfaceIPReplyVendorData() {
-        super(BSN_GET_INTERFACE_IP_REPLY);   
-    }
-    
-    /**
-     * @return the total length of the vendor-data part of the interface IP reply 
-     * message. The OF header (8B) and vendor (4B) are taken care of by the
-     * OFVendor class MINIMUM_LENGTH. This method returns the length of the 
-     * vendor-extension-subtype (4B) + the length of the interfaces
-     */
-    @Override
-    public int getLength() {
-        return length;
-    }
-    
-    /**
-     * Set the length of this message
-     *
-     * @param length
-     */
-    public void setLength(int length) {
-        this.length = length;
-        
-    }
-    
-    /**
-     * @return the interfaces
-     */
-    public List<OFInterfaceVendorData> getInterfaces() {
-        return interfaces;
-    }
-    
-    /**
-     * @param intfs  the ones to set
-     */
-    public void setInterfaces(List<OFInterfaceVendorData> intfs) {
-        this.interfaces = intfs;
-        if (intfs == null) {
-            this.setLength(super.getLength());
-        } else {
-            this.setLength(super.getLength() + intfs.size()
-                    * OFInterfaceVendorData.MINIMUM_LENGTH);
-        }
-    }
-    
-    /**
-     * Read 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 read by super class
-        super.readFrom(data, length);
-        
-        if (this.interfaces == null) {
-            this.interfaces = new ArrayList<OFInterfaceVendorData>();
-        } else {
-            this.interfaces.clear();
-        }
-        int intfCount = (length - 4)
-                / OFInterfaceVendorData.MINIMUM_LENGTH;
-        
-        OFInterfaceVendorData intf;
-        for (int i = 0; i < intfCount; ++i) {
-            intf = new OFInterfaceVendorData();
-            intf.readFrom(data);
-            this.interfaces.add(intf);
-        }
-    }
-
-    /**
-     * Write to the ChannelBuffer
-     * @param data the channel buffer to which we're serializing
-     */
-    @Override
-    public void writeTo(ChannelBuffer data) {
-        // datatype written by super class
-        super.writeTo(data);
-        if (this.interfaces != null) {
-            for (OFInterfaceVendorData intf : this.interfaces) {
-                intf.writeTo(data);
-            }
-        }
-    }
-    
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPRequestVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPRequestVendorData.java
deleted file mode 100644
index 9caf6e54ad299e488b217722941d7b4ae057fc72..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceIPRequestVendorData.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.Instantiable;
-import org.openflow.protocol.vendor.OFVendorData;
-
-public class OFInterfaceIPRequestVendorData extends OFBigSwitchVendorData {
- 
-    protected static Instantiable<OFVendorData> instantiable =
-            new Instantiable<OFVendorData>() {
-                public OFVendorData instantiate() {
-                    return new OFInterfaceIPRequestVendorData();
-                }
-    };
-    
-    /**
-     * @return a subclass of Instantiable<OFVendorData> that instantiates
-     *         an instance of OFInterfaceIPRequestVendorData.
-     */
-    public static Instantiable<OFVendorData> getInstantiable() {
-        return instantiable;
-    }
-
-    /**
-     * Opcode/dataType to request IP addresses of all interfaces
-     */
-    public static final int BSN_GET_INTERFACE_IP_REQUEST = 9;
-
-    /**
-     * Construct an interface IP request vendor data 
-     */
-    public OFInterfaceIPRequestVendorData() {
-        super(BSN_GET_INTERFACE_IP_REQUEST);   
-    }
-    
-    /**
-     * @return the total length of the interface IP request message
-     *         the length is already accounted for in the super class 
-     */
-    @Override
-    public int getLength() {
-        return super.getLength();
-    }
-    
-    /**
-     * Read 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) {
-        super.readFrom(data, length);
-    }
-    
-    /**
-     * Write to the ChannelBuffer
-     * @param data the channel buffer to which we're serializing
-     */
-    @Override
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-    }
-    
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceVendorData.java
deleted file mode 100644
index 0b6f30de4c677b5c694fb2037b759462c1827c29..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFInterfaceVendorData.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-
-import net.floodlightcontroller.core.web.serializers.ByteArrayMACSerializer;
-
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import org.jboss.netty.buffer.ChannelBuffer;
-
-public class OFInterfaceVendorData {
-    public static int MINIMUM_LENGTH = 32;
-    private static int OFP_ETH_ALEN = 6;
-    private static int OFP_MAX_PORT_NAME_LEN = 16;
-
-    protected byte[] hardwareAddress;
-    protected String name;
-    protected int ipv4Addr;
-    protected int ipv4AddrMask;
-
-    /**
-     * @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;
-    }
-
-    public int getIpv4Addr() {
-        return ipv4Addr;
-    }
-
-    public void setIpv4Addr(int ipv4Addr) {
-        this.ipv4Addr = ipv4Addr;
-    }
-
-    public int getIpv4AddrMask() {
-        return ipv4AddrMask;
-    }
-
-    public void setIpv4AddrMask(int ipv4AddrMask) {
-        this.ipv4AddrMask = ipv4AddrMask;
-    }
-
-    /**
-     * @return the name
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * @param name the name to set
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * Write this message's binary format to the specified ByteBuffer
-     * @param data
-     */
-    public void writeTo(ChannelBuffer data) {
-        data.writeBytes(hardwareAddress);
-        data.writeBytes(new byte[] {0, 0});
-
-        try {
-            byte[] name = this.name.getBytes("ASCII");
-            if (name.length < OFP_MAX_PORT_NAME_LEN) {
-                data.writeBytes(name);
-                for (int i = name.length; i < OFP_MAX_PORT_NAME_LEN; ++i) {
-                    data.writeByte((byte) 0);
-                }
-            } else {
-                data.writeBytes(name, 0, 15);
-                data.writeByte((byte) 0);
-            }
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-
-        data.writeInt(ipv4Addr);
-        data.writeInt(ipv4AddrMask);
-    }
-
-    /**
-     * Read this message off the wire from the specified ByteBuffer
-     * @param data
-     */
-    public void readFrom(ChannelBuffer data) {
-        if (this.hardwareAddress == null)
-            this.hardwareAddress = new byte[OFP_ETH_ALEN];
-        data.readBytes(this.hardwareAddress);
-        data.readBytes(new byte[2]);
-
-        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"));
-        ipv4Addr = data.readInt();
-        ipv4AddrMask = data.readInt();
-    }
-
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataReply.java b/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataReply.java
deleted file mode 100644
index d8d83b404eb8b3a31d369e3e49fb9a15ed3760c6..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataReply.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.openflow.protocol.Instantiable;
-import org.openflow.protocol.vendor.OFVendorData;
-
-
-/**
- * Subclass of OFVendorData 
- */
-public class OFMirrorGetVendorDataReply extends OFNetmaskVendorData {
-
-
-    protected static Instantiable<OFVendorData> instantiable =
-        new Instantiable<OFVendorData>() {
-        public OFVendorData instantiate() {
-            return new OFMirrorGetVendorDataReply();
-        }
-    };
-
-    /**
-     * @return a subclass of Instantiable<OFVendorData> that instantiates
-     *         an instance of OFNetmaskGetVendorData.
-     */
-    public static Instantiable<OFVendorData> getInstantiable() {
-        return instantiable;
-    }
-
-    /**
-     * Opcode/dataType to represent REPLY of GET_MASK request
-     */
-    public static final int BSN_GET_MIRRORING_REPLY = 5;
-
-    /**
-     * Construct a get network mask vendor data
-     */
-    public OFMirrorGetVendorDataReply() {
-        super(BSN_GET_MIRRORING_REPLY);   
-    }
-    
-    /**
-     * Construct a get network mask vendor data for a specific table entry
-     */
-    public OFMirrorGetVendorDataReply(byte tableIndex, int netMask) {
-        super(BSN_GET_MIRRORING_REPLY, tableIndex, netMask);
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataRequest.java b/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataRequest.java
deleted file mode 100644
index 6692cdfdde002140a87256f62cdb8cfa7a26f52d..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorGetVendorDataRequest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.openflow.protocol.Instantiable;
-import org.openflow.protocol.vendor.OFVendorData;
-
-
-/**
- * Subclass of OFVendorData
- */
-public class OFMirrorGetVendorDataRequest extends OFNetmaskVendorData {
-
-
-    protected static Instantiable<OFVendorData> instantiable =
-        new Instantiable<OFVendorData>() {
-        public OFVendorData instantiate() {
-            return new OFMirrorGetVendorDataRequest();
-        }
-    };
-
-    /**
-     * @return a subclass of Instantiable<OFVendorData> that instantiates
-     *         an instance of OFNetmaskGetVendorData.
-     */
-    public static Instantiable<OFVendorData> getInstantiable() {
-        return instantiable;
-    }
-
-    /**
-     * Opcode/dataType to request an entry in the switch netmask table
-     */
-    public static final int BSN_GET_MIRRORING_REQUEST = 4;
-
-    /**
-     * Construct a get network mask vendor data
-     */
-    public OFMirrorGetVendorDataRequest() {
-        super(BSN_GET_MIRRORING_REQUEST);   
-    }
-    
-    /**
-     * Construct a get network mask vendor data for a specific table entry
-     */
-    public OFMirrorGetVendorDataRequest(byte tableIndex, int netMask) {
-        super(BSN_GET_MIRRORING_REQUEST, tableIndex, netMask);
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorSetVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorSetVendorData.java
deleted file mode 100644
index 5eba6512b7c4f07f9087aabe4f52e5cd0e300bee..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFMirrorSetVendorData.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-
-public class OFMirrorSetVendorData extends OFBigSwitchVendorData {
-    
-    /**
-     * Opcode/dataType to set mirroring
-     */
-    public static final int BSN_SET_MIRRORING = 3;
-
-    protected byte reportMirrorPorts;
-    protected byte pad1;
-    protected byte pad2;
-    protected byte pad3;
-    
-    public OFMirrorSetVendorData() {
-        super(BSN_SET_MIRRORING);
-        this.reportMirrorPorts=1;
-    }
-
-    public byte getReportMirrorPorts() {
-        return reportMirrorPorts;
-    }
-
-    public void setReportMirrorPorts(byte report) {
-        this.reportMirrorPorts = report;
-    }
-    
-    /**
-     * @return the total length vendor date
-     */
-    @Override
-    public int getLength() {
-        return super.getLength() + 4; // 4 extra bytes
-    }
-    
-    /**
-     * Read the vendor data from the channel buffer
-     * @param data: the channel buffer from which we are deserializing
-     * @param length: the length to the end of the enclosing message
-     */
-    public void readFrom(ChannelBuffer data, int length) {
-        super.readFrom(data, length);
-        reportMirrorPorts = data.readByte();
-        pad1 = data.readByte();
-        pad2 = data.readByte();
-        pad3 = data.readByte();
-    }
-    
-    /**
-     * Write the vendor data to the channel buffer
-     */
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-        data.writeByte(reportMirrorPorts);
-        data.writeByte(pad1);
-        data.writeByte(pad2);
-        data.writeByte(pad3);
-    }
-    
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataReply.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataReply.java
deleted file mode 100644
index 62d711020b71f8c962ff2fd068451acb3d9f9ab7..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataReply.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.openflow.protocol.Instantiable;
-import org.openflow.protocol.vendor.OFVendorData;
-
-
-/**
- * Subclass of OFVendorData
- * 
- * @author munish_mehta
- */
-public class OFNetmaskGetVendorDataReply extends OFNetmaskVendorData {
-
-
-    protected static Instantiable<OFVendorData> instantiable =
-        new Instantiable<OFVendorData>() {
-        public OFVendorData instantiate() {
-            return new OFNetmaskGetVendorDataReply();
-        }
-    };
-
-    /**
-     * @return a subclass of Instantiable<OFVendorData> that instantiates
-     *         an instance of OFNetmaskGetVendorData.
-     */
-    public static Instantiable<OFVendorData> getInstantiable() {
-        return instantiable;
-    }
-
-    /**
-     * Opcode/dataType to represent REPLY of GET_MASK request
-     */
-    public static final int BSN_GET_IP_MASK_ENTRY_REPLY = 2;
-
-    /**
-     * Construct a get network mask vendor data
-     */
-    public OFNetmaskGetVendorDataReply() {
-        super(BSN_GET_IP_MASK_ENTRY_REPLY);   
-    }
-    
-    /**
-     * Construct a get network mask vendor data for a specific table entry
-     */
-    public OFNetmaskGetVendorDataReply(byte tableIndex, int netMask) {
-        super(BSN_GET_IP_MASK_ENTRY_REPLY, tableIndex, netMask);
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataRequest.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataRequest.java
deleted file mode 100644
index 1d075e9a3b9a87584f92b6ad7ea04442457f5ac9..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskGetVendorDataRequest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.openflow.protocol.Instantiable;
-import org.openflow.protocol.vendor.OFVendorData;
-
-
-/**
- * Subclass of OFVendorData
- * 
- * @author munish_mehta
- */
-public class OFNetmaskGetVendorDataRequest extends OFNetmaskVendorData {
-
-
-    protected static Instantiable<OFVendorData> instantiable =
-        new Instantiable<OFVendorData>() {
-        public OFVendorData instantiate() {
-            return new OFNetmaskGetVendorDataRequest();
-        }
-    };
-
-    /**
-     * @return a subclass of Instantiable<OFVendorData> that instantiates
-     *         an instance of OFNetmaskGetVendorData.
-     */
-    public static Instantiable<OFVendorData> getInstantiable() {
-        return instantiable;
-    }
-
-    /**
-     * Opcode/dataType to request an entry in the switch netmask table
-     */
-    public static final int BSN_GET_IP_MASK_ENTRY_REQUEST = 1;
-
-    /**
-     * Construct a get network mask vendor data
-     */
-    public OFNetmaskGetVendorDataRequest() {
-        super(BSN_GET_IP_MASK_ENTRY_REQUEST);   
-    }
-    
-    /**
-     * Construct a get network mask vendor data for a specific table entry
-     */
-    public OFNetmaskGetVendorDataRequest(byte tableIndex, int netMask) {
-        super(BSN_GET_IP_MASK_ENTRY_REQUEST, tableIndex, netMask);
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskSetVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskSetVendorData.java
deleted file mode 100644
index 54421c10334acb5d7ca793c699f5005977a3a873..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskSetVendorData.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.openflow.protocol.Instantiable;
-import org.openflow.protocol.vendor.OFVendorData;
-
-public class OFNetmaskSetVendorData extends OFNetmaskVendorData {
-
-
-    protected static Instantiable<OFVendorData> instantiable =
-        new Instantiable<OFVendorData>() {
-        public OFVendorData instantiate() {
-            return new OFNetmaskSetVendorData();
-        }
-    };
-
-    /**
-     * @return a subclass of Instantiable<OFVendorData> that instantiates
-     *         an instance of OFNetmaskSetVendorData.
-     */
-    public static Instantiable<OFVendorData> getInstantiable() {
-        return instantiable;
-    }
-
-    /**
-     * Opcode/dataType to set an entry in the switch netmask table
-     */
-    public static final int BSN_SET_IP_MASK_ENTRY = 0;
-    
-    /**
-     * Construct a get network mask vendor data
-     */
-    public OFNetmaskSetVendorData() {
-        super(BSN_SET_IP_MASK_ENTRY);   
-    }
-    
-    /**
-     * Construct a get network mask vendor data for a specific table entry
-     */
-    public OFNetmaskSetVendorData(byte tableIndex, int netMask) {
-        super(BSN_SET_IP_MASK_ENTRY, tableIndex, netMask);
-    }
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskVendorData.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskVendorData.java
deleted file mode 100644
index 66539f98e757e8b133eaf04c115557fad8904ebd..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFNetmaskVendorData.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-
-
-/**
- * Class that represents the vendor data in the netmask table request
- * extension implemented by Arista switches
- * 
- * @author munish_mehta (munish.mehta@bigswitch.com)
- */
-
-public class OFNetmaskVendorData extends OFBigSwitchVendorData {
-
-    /**
-     * Table index for set or get of the the entry from netmask table
-     */
-    protected byte tableIndex;
-    protected byte pad1;
-    protected byte pad2;
-    protected byte pad3;
-    protected int  netMask;
-    
-    public OFNetmaskVendorData(int dataType) {
-        super(dataType);
-        this.tableIndex = 0;
-        this.netMask = (int)0xffffffffL;
-    }
-
-    public OFNetmaskVendorData(int dataType, byte table_index, int netmask) {
-        super(dataType);
-        this.tableIndex = table_index;
-        this.netMask = netmask;
-    }
-
-
-    public byte getTableIndex() {
-        return tableIndex;
-    }
-
-    public void setTableIndex(byte tableIndex) {
-        this.tableIndex = tableIndex;
-    }
-
-    public int getNetMask() {
-        return netMask;
-    }
-
-    public void setNetMask(int netMask) {
-        this.netMask = netMask;
-    }
-
-    /**
-     * @return the total length of the netmask vendor data
-     */
-    @Override
-    public int getLength() {
-        return super.getLength() + 8; // 8 extra bytes
-    }
-    
-    /**
-     * Read the vendor data from the channel buffer
-     * @param data: the channel buffer from which we are deserializing
-     * @param length: the length to the end of the enclosing message
-     */
-    public void readFrom(ChannelBuffer data, int length) {
-        super.readFrom(data, length);
-        tableIndex = data.readByte();
-        pad1 = data.readByte();
-        pad2 = data.readByte();
-        pad3 = data.readByte();
-        netMask = data.readInt();
-    }
-    
-    /**
-     * Write the vendor data to the channel buffer
-     */
-    public void writeTo(ChannelBuffer data) {
-        super.writeTo(data);
-        data.writeByte(tableIndex);
-        data.writeByte(pad1);
-        data.writeByte(pad2);
-        data.writeByte(pad3);
-        data.writeInt(netMask);
-    }
-    
-
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFNiciraVendorActionFactory.java b/src/main/java/com/bigswitch/floodlight/vendor/OFNiciraVendorActionFactory.java
deleted file mode 100644
index 716373794f263aa3db5a60d316d982f7ce668a5f..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFNiciraVendorActionFactory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.action.OFActionVendor;
-import org.openflow.protocol.factory.OFVendorActionFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class OFNiciraVendorActionFactory implements OFVendorActionFactory {
-    protected static Logger logger =
-            LoggerFactory.getLogger(OFNiciraVendorActionFactory.class);
-
-    static class OFActionNiciraVendorDemux extends OFActionNiciraVendor {
-        OFActionNiciraVendorDemux() {
-            super((short) 0);
-        }
-    }
-
-    @Override
-    public OFActionVendor readFrom(ChannelBuffer data) {
-        data.markReaderIndex();
-        OFActionNiciraVendorDemux demux = new OFActionNiciraVendorDemux();
-        demux.readFrom(data);
-        data.resetReaderIndex();
-
-        switch(demux.getSubtype()) {
-            case OFActionNiciraTtlDecrement.TTL_DECREMENT_SUBTYPE:
-                OFActionNiciraTtlDecrement ttlAction = new OFActionNiciraTtlDecrement();
-                ttlAction.readFrom(data);
-                return ttlAction;
-            default:
-                logger.error("Unknown Nicira vendor action subtype: "+demux.getSubtype());
-                return null;
-        }
-    }
-
-}
diff --git a/src/main/java/com/bigswitch/floodlight/vendor/OFVendorActions.java b/src/main/java/com/bigswitch/floodlight/vendor/OFVendorActions.java
deleted file mode 100644
index 0b555340cea7abe3364d1c05b7feaa7be0b3ff0d..0000000000000000000000000000000000000000
--- a/src/main/java/com/bigswitch/floodlight/vendor/OFVendorActions.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.openflow.protocol.factory.OFVendorActionRegistry;
-
-public final class OFVendorActions {
-    public static final void registerStandardVendorActions() {
-        OFVendorActionRegistry registry = OFVendorActionRegistry.getInstance();
-        registry.register(OFActionBigSwitchVendor.BSN_VENDOR_ID, new OFBigSwitchVendorActionFactory());
-        registry.register(OFActionNiciraVendor.NICIRA_VENDOR_ID, new OFNiciraVendorActionFactory());
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/ControllerId.java b/src/main/java/net/floodlightcontroller/core/ControllerId.java
new file mode 100644
index 0000000000000000000000000000000000000000..6fd347b234219ae4bee0b36923d5cf3893018b0c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/ControllerId.java
@@ -0,0 +1,61 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..c82f31d85bd2ffab1567ac8fee25a926315f77b7
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/Deliverable.java
@@ -0,0 +1,38 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..1e724ac51819fc6a52d26a649ded028f0bd917cf
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/DeliverableListenableFuture.java
@@ -0,0 +1,22 @@
+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/HARole.java b/src/main/java/net/floodlightcontroller/core/HARole.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c2886f1e179579fc0b011317cdf8362a95cab9f
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/HARole.java
@@ -0,0 +1,88 @@
+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 c0aa1fd6d5faa9426c7580d7e02fc685c0a96021..c91e55fc1720c5e36307cfb108084fe9f156da0e 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -17,8 +17,6 @@
 
 package net.floodlightcontroller.core;
 
-import java.util.HashMap;
-
 import java.util.List;
 import java.util.Set;
 import java.util.Map;
@@ -26,11 +24,22 @@ import java.util.Map;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.packet.Ethernet;
 
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.factory.BasicFactory;
-import org.openflow.vendor.nicira.OFRoleVendorData;
-
+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;
 /**
  * The interface exposed by the core bundle that allows you to interact
  * with connected switches.
@@ -47,37 +56,6 @@ public interface IFloodlightProviderService extends
     public static final String CONTEXT_PI_PAYLOAD =
             "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
      * packet-in payload
@@ -85,6 +63,15 @@ 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
@@ -106,77 +93,52 @@ public interface IFloodlightProviderService extends
     public Map<OFType, List<IOFMessageListener>> getListeners();
 
     /**
-     * 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
+     * Get the current role of the controller
      */
-    public IOFSwitch getSwitch(long dpid);
+    public HARole getRole();
 
     /**
-     * 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
+     * Get the current role of the controller
      */
-    public Set<Long> getAllSwitchDpids();
+    public RoleInfo getRoleInfo();
 
     /**
-     * Return a snapshot
-     * FIXME: asdf
-     * @return
+     * Get the current mapping of controller IDs to their IP addresses
+     * Returns a copy of the current mapping.
+     * @see IHAListener
      */
-    public Map<Long,IOFSwitch> getAllSwitchMap();
+    public Map<String,String> getControllerNodeIPs();
 
     /**
-     * Get the current role of the controller
+     * Gets the ID of the controller
      */
-    public Role getRole();
+    public String getControllerId();
 
     /**
-     * Get the current role of the controller
+     * Gets the controller hostname
+     * @return the controller hostname
      */
-    public RoleInfo getRoleInfo();
+    public String getOFHostname();
 
     /**
-     * Get the current mapping of controller IDs to their IP addresses
-     * Returns a copy of the current mapping.
-     * @see IHAListener
+     * Gets the controller's openflow port
+     * @return the controller's openflow port
      */
-    public Map<String,String> getControllerNodeIPs();
-
+    public int getOFPort();
 
     /**
      * 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(Role role, String changeDescription);
-
-    /**
-     * Add a switch listener
-     * @param listener The module that wants to listen for events
-     */
-    public void addOFSwitchListener(IOFSwitchListener listener);
+    public void setRole(HARole role, String changeDescription);
 
     /**
-     * Remove a switch listener
-     * @param listener The The module that no longer wants to listen for events
+     * Add an update task for asynchronous, serialized execution
+     *
+     * @param update
      */
-    public void removeOFSwitchListener(IOFSwitchListener listener);
+    public void addUpdateToQueue(IUpdate update);
 
     /**
      * Adds a listener for HA role events
@@ -190,53 +152,13 @@ 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,
-            FloodlightContext bc);
-
-    /**
-     * Gets the BasicFactory
-     * @return an OpenFlow message factory
-     */
-    public BasicFactory getOFMessageFactory();
+    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m);
 
     /**
      * Run the main I/O loop of the Controller.
@@ -265,21 +187,12 @@ 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
     */
@@ -292,30 +205,38 @@ public interface IFloodlightProviderService extends
    public Long getUptime();
 
    /**
-    * 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
+    * Get the set of port prefixes that will define an UPLINK port.
+    * @return The set of prefixes
     */
-   public void addOFSwitchDriver(String desc, IOFSwitchDriver driver);
+   public Set<String> getUplinkPortPrefixSet();
+
+
+   public void handleMessage(IOFSwitch sw, OFMessage m,
+                          FloodlightContext bContext);
 
    /**
-    * 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
+    * Gets a hash wheeled timer to be used for for timeout scheduling
+    * @return a hash wheeled timer
     */
-   public void addSwitchEvent(long switchDPID, String reason, boolean flushNow);
+   public Timer getTimer();
 
    /**
-    * Get the set of port prefixes that will define an UPLINK port.
-    * @return The set of prefixes
+    * Gets the role manager
+    * @return the role manager
     */
-   public Set<String> getUplinkPortPrefixSet();
+   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
+    */
+   public int getWorkerThreads();
 
 }
+
diff --git a/src/main/java/net/floodlightcontroller/core/IHAListener.java b/src/main/java/net/floodlightcontroller/core/IHAListener.java
index 2ffe82fd586b1012f29c24d397eb6c212a5aa02e..399a5b6a5968a8392305abefe6c5adf518f0f3ea 100644
--- a/src/main/java/net/floodlightcontroller/core/IHAListener.java
+++ b/src/main/java/net/floodlightcontroller/core/IHAListener.java
@@ -18,28 +18,43 @@ package net.floodlightcontroller.core;
 
 import java.util.Map;
 
-public interface IHAListener extends IListener<HAListenerTypeMarker> {
 
+/** Listener interface for the {@link HARole} of the local controller. Listeners
+ *  are notified when the controller transitions to role {@link HARole#ACTIVE}.
+ *  <p>
+ *  <strong>NOTE:</strong> The floodlight platform currently does not support
+ *  a transition to the STANDBY role.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+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.
+     * This notification is fired if the controller's initial role was STANDBY
+     * and the controller is now transitioning to ACTIVE.
+     * Clients can query the current (and initial) role from
+     * {@link IFloodlightProviderService#getRole()} (in startup).
      */
-    public void transitionToMaster();
+    public void transitionToActive();
 
     /**
-     * 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
+     * This notification is fired if the controller's initial role was ACTIVE
+     * and the controller is now transitioning to STANDBY.
+     * <strong>NOTE:</strong> The floodlight platform currently terminates
+     * after the transition to STANDBY. Clients should prepare for the shutdown
+     * in transitionToStandby (e.g., ensure that current updates to operational
+     * states are fully synced).
+     */
+    public void transitionToStandby();
+    
+    /**
+     * 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
+     * @param addedControllerNodeIPs
+     * @param removedControllerNodeIPs
      */
-    public void controllerNodeIPsChanged(
-            Map<String, String> curControllerNodeIPs,
-            Map<String, String> addedControllerNodeIPs,
-            Map<String, String> removedControllerNodeIPs
-            );
+    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
new file mode 100644
index 0000000000000000000000000000000000000000..a14021fbd47b087495b57bdd3b1736966df0a798
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IOFConnection.java
@@ -0,0 +1,62 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..0ec7a9e1b2b081b34c813d5d9dd959028e1e49cc
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IOFConnectionBackend.java
@@ -0,0 +1,23 @@
+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 00fdac1f99379ee8aa1e5dfee00de6bd4da9a4f1..1fe71529c9e64d364c92a0d2255083169a737dc8 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.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
 
 /**
  *
diff --git a/src/main/java/net/floodlightcontroller/core/IOFMessageWriter.java b/src/main/java/net/floodlightcontroller/core/IOFMessageWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd27181f19e9170fac71db1557942dcc8cef0510
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IOFMessageWriter.java
@@ -0,0 +1,79 @@
+/**
+*    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
index fb27460401007cdc639d4c8ee38cc73101ce0c40..3b46ded638f72120733d9865bc58a37c82409512 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -1,5 +1,4 @@
 /**
-*    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
@@ -17,248 +16,112 @@
 
 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;
+import java.util.Set;
+import java.util.Date;
+
+import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.projectfloodlight.openflow.protocol.OFCapabilities;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFRequest;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.ListenableFuture;
 
 /**
- *
- *
- * @author David Erickson (daviderickson@cs.stanford.edu)
+ * 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 IOFSwitch {
+public interface IOFSwitch extends IOFMessageWriter {
     // 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() + "]";
-        }
+    // These match our YANG schema, make sure they are in sync
+    public static final String SWITCH_DESCRIPTION_FUTURE = "description-future";
+    public static final String SWITCH_DESCRIPTION_DATA = "description-data";
+    public static final String SWITCH_SUPPORTS_NX_ROLE = "supports-nx-role";
+    public static final String PROP_FASTWILDCARDS = "fast-wildcards";
+    public static final String PROP_REQUIRES_L3_MATCH = "requires-l3-match";
+    public static final String PROP_SUPPORTS_OFPP_TABLE = "supports-ofpp-table";
+    public static final String PROP_SUPPORTS_OFPP_FLOOD = "supports-ofpp-flood";
+    public static final String PROP_SUPPORTS_NETMASK_TBL = "supports-netmask-table";
+    public static final String PROP_SUPPORTS_BSN_SET_TUNNEL_DST_ACTION =
+            "supports-set-tunnel-dst-action";
+    public static final String PROP_SUPPORTS_NX_TTL_DECREMENT = "supports-nx-ttl-decrement";
+
+    public enum SwitchStatus {
+       /** this switch is in the process of being handshaked. Initial State. */
+       HANDSHAKE(false),
+       /** the OF channel to this switch is currently in SLAVE role - the switch will not accept
+        *  state-mutating messages from this controller node.
+        */
+       SLAVE(true),
+       /** the OF channel to this switch is currently in MASTER (or EQUALS) role - the switch is
+        *  controllable from this controller node.
+        */
+       MASTER(true),
+       /** the switch has been sorted out and quarantined by the handshake. It does not show up
+        *  in normal switch listings
+        */
+       QUARANTINED(false),
+       /** the switch has disconnected, and will soon be removed from the switch database */
+       DISCONNECTED(false);
+
+       private final boolean visible;
+
+       SwitchStatus(boolean visible) {
+        this.visible = visible;
+       }
+
+       /** wether this switch is currently visible for normal operation */
+       public boolean isVisible() {
+            return visible;
+       }
+
+       /** wether this switch is currently ready to be controlled by this controller */
+       public boolean isControllable() {
+            return this == MASTER;
+       }
     }
 
-    /**
-     * 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);
+    SwitchStatus getStatus();
 
     /**
-     * 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.
+     * Returns switch features from features Reply
      * @return
      */
-    boolean isOverloaded();
+    long getBuffers();
 
     /**
-     * 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
+     * Disconnect all the switch's channels and mark the switch as disconnected
      */
-    public void writeThrottled(OFMessage msg, FloodlightContext cntx) throws IOException;
+    void disconnect();
 
-    /**
-     * 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;
+    Set<OFActionType> getActions();
 
-    /**
-     * 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;
+    Set<OFCapabilities> getCapabilities();
 
-    /**
-     * 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();
+    short getTables();
 
     /**
      * @return a copy of the description statistics for this switch
      */
-    public OFDescriptionStatistics getDescriptionStatistics();
+    SwitchDescription getSwitchDescription();
 
     /**
-     * Set the OFFeaturesReply message returned by the switch during initial
-     * handshake.
-     * @param featuresReply
+     * Get the IP address of the remote (switch) end of the connection
+     * @return the inet address
      */
-    public void setFeaturesReply(OFFeaturesReply featuresReply);
+    SocketAddress getInetAddress();
 
     /**
      * Get list of all enabled ports. This will typically be different from
@@ -268,7 +131,7 @@ public interface IOFSwitch {
      * been received.
      * @return Unmodifiable list of ports not backed by the underlying collection
      */
-    public Collection<ImmutablePort> getEnabledPorts();
+    Collection<OFPortDesc> getEnabledPorts();
 
     /**
      * Get list of the port numbers of all enabled ports. This will typically
@@ -278,7 +141,7 @@ public interface IOFSwitch {
      * messages that have been received.
      * @return Unmodifiable list of ports not backed by the underlying collection
      */
-    public Collection<Short> getEnabledPortNumbers();
+    Collection<OFPort> getEnabledPortNumbers();
 
     /**
      * Retrieve the port object by the port number. The port object
@@ -287,7 +150,7 @@ public interface IOFSwitch {
      * @param portNumber
      * @return port object
      */
-    public ImmutablePort getPort(short portNumber);
+    OFPortDesc getPort(OFPort portNumber);
 
     /**
      * Retrieve the port object by the port name. The port object
@@ -297,29 +160,7 @@ public interface IOFSwitch {
      * @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);
+    OFPortDesc getPort(String portName);
 
     /**
      * Get list of all ports. This will typically be different from
@@ -329,172 +170,67 @@ public interface IOFSwitch {
      * been received.
      * @return Unmodifiable list of ports
      */
-    public Collection<ImmutablePort> getPorts();
+    Collection<OFPortDesc> getPorts();
+
+    /**
+     * This is mainly for the benefit of the DB code which currently has the
+     * requirement that list elements be sorted by key. Hopefully soon the
+     * DB will handle the sorting automatically or not require it at all, in
+     * which case we could get rid of this method.
+     * @return
+     */
+    Collection<OFPortDesc> getSortedPorts();
 
     /**
      * @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);
+    boolean portEnabled(OFPort 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);
+    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
+     * Check is switch is connected
+     * @return Whether or not this switch is connected
      */
-    public OrderedCollection<PortChangeEvent>
-            comparePorts(Collection<ImmutablePort> ports);
+    boolean isConnected();
 
     /**
-     * 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
+     * Retrieves the date the switch connected to this controller
+     * @return the date
      */
-    public OrderedCollection<PortChangeEvent>
-            setPorts(Collection<ImmutablePort> ports);
-
+    Date getConnectedSince();
 
     /**
      * 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();
+    DatapathId getId();
 
     /**
      * 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();
+    Map<Object, Object> getAttributes();
 
     /**
      * 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);
+    boolean isActive();
 
     /**
      * 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();
+    OFControllerRole getControllerRole();
 
     /**
      * Checks if a specific switch property exists for this switch
@@ -535,135 +271,67 @@ public interface IOFSwitch {
     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
+     * Returns a factory object that can be used to create OpenFlow messages.
      * @return
      */
-    public Map<Short, Long> getPortBroadcastHits();
+    OFFactory getOFFactory();
 
     /**
-     * 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.
+     * Flush all flows queued for this switch on all connections that were written by the current thread.
+     *
+     *
      */
-    public void setAccessFlowPriority(short prio);
+    void flush();
 
     /**
-     * Set the suggested priority to use when installing core flows in
-     * this switch.
+     * Gets the OF connections for this switch instance
+     * @return Collection of IOFConnection
      */
-    public void setCoreFlowPriority(short prio);
+    ImmutableList<IOFConnection> getConnections();
 
     /**
-     * Get the suggested priority to use when installing access flows in
-     * this switch.
+     * Writes a message to the connection specified by the logical OFMessage category
+     * @param m an OF Message
+     * @param category the category of the OF Message to be sent
      */
-    public short getAccessFlowPriority();
+    void write(OFMessage m, LogicalOFMessageCategory category);
 
     /**
-     * Get the suggested priority to use when installing core flows in
-     * this switch.
+     * Writes a message list to the connection specified by the logical OFMessage category
+     * @param msglist an OF Message list
+     * @param category the category of the OF Message list to be sent
      */
-    public short getCoreFlowPriority();
+    void write(Iterable<OFMessage> msglist, LogicalOFMessageCategory category);
 
     /**
-     * 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
+     * Get a connection specified by the logical OFMessage category
+     * @param category the category for the connection the user desires
+     * @return an OF Connection
      */
-    public void startDriverHandshake();
+    OFConnection getConnectionByCategory(LogicalOFMessageCategory category);
 
-    /**
-     * Check if the sub-handshake for this switch driver has been completed.
-     * This method can only be called after startDriverHandshake()
+    /** 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.
      *
-     * 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.
+     * @param request stats request
+     * @param category the category for the connection that this request should be written to
+     * @return Future object wrapping OFStatsReply
+     *         If the connection is not currently connected, will
+     *         return a Future that immediately fails with a @link{SwitchDisconnectedException}.
      */
-    public boolean isDriverHandshakeComplete();
+    <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> writeStatsRequest(OFStatsRequest<REPLY> request, LogicalOFMessageCategory category);
 
-    /**
-     * 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.
+    /** write an OpenFlow Request message, register for a single corresponding reply message
+     *  or error message.
+     *
+     * @param request
+     * @param categiry the category for the connection that this request should be written to
+     * @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}.
      */
-    public void processDriverHandshakeMessage(OFMessage m);
+    <R extends OFMessage> ListenableFuture<R> writeRequest(OFRequest<R> request, LogicalOFMessageCategory category);
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java
new file mode 100644
index 0000000000000000000000000000000000000000..d16c5e20f97b2420b4991b9ba252e450cdc3b6ee
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchBackend.java
@@ -0,0 +1,186 @@
+/**
+*    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);
+
+    /**
+     * 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 f7f720f914d34f6e812dc9032ccb135a8a3f100a..b56655535373e57b59e017791dce25834abe5649 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
@@ -16,7 +16,10 @@
 
 package net.floodlightcontroller.core;
 
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import net.floodlightcontroller.core.IOFSwitchBackend;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+
+import net.floodlightcontroller.core.SwitchDescription;
 
 public interface IOFSwitchDriver {
     /**
@@ -26,5 +29,5 @@ public interface IOFSwitchDriver {
      * @return A IOFSwitch instance if the driver found an implementation
      * for the given description. Null otherwise
      */
-    public IOFSwitch getOFSwitchImpl(OFDescriptionStatistics description);
-}
+    public IOFSwitchBackend getOFSwitchImpl(SwitchDescription description, OFFactory factory);
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
index e0c7b53f8b29eb8349f28d9f42cc97b43b309c8f..57eb4d179d27ad38d7202991ac26799bd822e6e7 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
@@ -17,6 +17,9 @@
 
 package net.floodlightcontroller.core;
 
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.types.DatapathId;
+
 /**
  * Switch lifecycle notifications.
  *
@@ -45,20 +48,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(long switchId);
+    public void switchAdded(DatapathId switchId);
 
     /**
      * Fired when a switch disconnects from the cluster ,
      * @param switchId the datapath Id of the switch
      */
-    public void switchRemoved(long switchId);
+    public void switchRemoved(DatapathId 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(long switchId);
+    public void switchActivated(DatapathId switchId);
 
     /**
      * Fired when a port on a known switch changes.
@@ -74,9 +77,9 @@ public interface IOFSwitchListener {
      * @param port
      * @param type
      */
-    public void switchPortChanged(long switchId,
-                                  ImmutablePort port,
-                                  IOFSwitch.PortChangeType type);
+    public void switchPortChanged(DatapathId switchId,
+                                  OFPortDesc port,
+                                  PortChangeType type);
 
     /**
      * Fired when any non-port related information (e.g., attributes,
@@ -84,5 +87,5 @@ public interface IOFSwitchListener {
      * TODO: currently unused
      * @param switchId
      */
-    public void switchChanged(long switchId);
+    public void switchChanged(DatapathId switchId);
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IShutdownListener.java b/src/main/java/net/floodlightcontroller/core/IShutdownListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3fe5108b866c9d383ef7388c6d220a7a46f2365
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IShutdownListener.java
@@ -0,0 +1,13 @@
+package net.floodlightcontroller.core;
+
+/**
+ * This listener is called when floodlight is about to terminate to enable
+ * interested parties to perform final steps, e.g., persisting debug
+ * information.
+ * Listeners are unordered.
+ * @author gregor
+ *
+ */
+public interface IShutdownListener {
+    public void floodlightIsShuttingDown();
+}
diff --git a/src/main/java/net/floodlightcontroller/core/IShutdownService.java b/src/main/java/net/floodlightcontroller/core/IShutdownService.java
new file mode 100644
index 0000000000000000000000000000000000000000..81e8c6f45c9875902519e7900754e402cda547f3
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IShutdownService.java
@@ -0,0 +1,43 @@
+package net.floodlightcontroller.core;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+
+public interface IShutdownService extends IFloodlightService {
+    /**
+     * Terminate floodlight process by calling System.exit() with the given
+     * exitCode. If reason is non-null, reason will be logged. Before
+     * terminating the shutdownListeners are called
+     * If exitCode == 0 the termination cause is deemed "normal" and info
+     * level log is used. In all other cases the exit is abnormal and an error
+     * is logged.
+     * @param reason
+     * @param exitCode
+     */
+    public void terminate(@Nullable String reason, int exitCode);
+
+    /**
+     * Terminate floodlight process by calling System.exit() with the given
+     * exitCode. If reason is non-null, reason will be logged. In addition,
+     * the throwable will be logged as well.
+     * Before terminating the shutdownListeners are called
+     *
+     * This method is generally used to terminate floodlight due to an
+     * unhandled Exception. As such all messages are logged as error and it is
+     * recommended that an exitCode != 0 is used.
+     * @param reason
+     * @param e The throwable causing floodlight to terminate
+     * @param exitCode
+     */
+    public void terminate(@Nullable String reason,
+                          @Nonnull Throwable e, int exitCode);
+
+    /**
+     * Register a shutdown listener. Registered listeners are called when
+     * floodlight is about to terminate due to a call to terminate()
+     * @param listener
+     */
+    public void registerShutdownListener(@Nonnull IShutdownListener listener);
+}
diff --git a/src/main/java/net/floodlightcontroller/core/ImmutablePort.java b/src/main/java/net/floodlightcontroller/core/ImmutablePort.java
deleted file mode 100644
index c015454cad15d3d24d85a0d0ddc89531062237d4..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/ImmutablePort.java
+++ /dev/null
@@ -1,561 +0,0 @@
-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
new file mode 100644
index 0000000000000000000000000000000000000000..514d3541cbfc06820205ad40e9f3499bf441ceba
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/LogicalOFMessageCategory.java
@@ -0,0 +1,68 @@
+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 627a56c1477f2191abc11f2f8dbc5304128c0bd6..0bda3c0c55abf9497a8dcb334e0b65141bccd1c2 100644
--- a/src/main/java/net/floodlightcontroller/core/Main.java
+++ b/src/main/java/net/floodlightcontroller/core/Main.java
@@ -18,8 +18,11 @@ 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;
@@ -30,36 +33,50 @@ import net.floodlightcontroller.restserver.IRestApiService;
  * @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 {
-        // 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();
-    }
+	/**
+	 * 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());
+				// @Ryan TODO This should probably be implemented and run as a normal service for consistency;
+				// although, it does need all modules to be loaded and their prior to running.
+				IRestApiService restApi = moduleContext.getServiceImpl(IRestApiService.class);
+				restApi.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(); // 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);
+		}
+	}
 }
diff --git a/src/main/java/net/floodlightcontroller/core/NullConnection.java b/src/main/java/net/floodlightcontroller/core/NullConnection.java
new file mode 100644
index 0000000000000000000000000000000000000000..41a5a1591bf631e2bd419b2ed996e1294dc3748a
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/NullConnection.java
@@ -0,0 +1,114 @@
+package net.floodlightcontroller.core;
+
+import java.net.SocketAddress;
+import java.util.List;
+
+import java.util.Date;
+import net.floodlightcontroller.core.internal.IOFConnectionListener;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+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.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFAuxId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class NullConnection implements IOFConnectionBackend, IOFMessageWriter {
+    private static final Logger logger = LoggerFactory.getLogger(NullConnection.class);
+
+    @Override
+    public boolean isConnected() {
+        return false;
+    }
+
+    @Override
+    public Date getConnectedSince() {
+        return null;
+    }
+
+    private void warn() {
+        logger.debug("Switch {} not connected -- cannot send message", getDatapathId());
+    }
+
+    @Override
+    public void write(OFMessage m) {
+        warn();
+    }
+
+    @Override
+    public void write(Iterable<OFMessage> msglist) {
+        warn();
+    }
+
+    @Override
+    public SocketAddress getRemoteInetAddress() {
+        return null;
+    }
+
+    @Override
+    public SocketAddress getLocalInetAddress() {
+        return null;
+    }
+
+    @Override
+    public OFFactory getOFFactory() {
+        return OFFactories.getFactory(OFVersion.OF_13);
+    }
+
+    @Override
+    public <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> writeStatsRequest(
+            OFStatsRequest<REPLY> request) {
+        return Futures.immediateFailedFuture(new SwitchDisconnectedException(getDatapathId()));
+    }
+
+    @Override
+    public void cancelAllPendingRequests() {
+        // noop
+    }
+
+    @Override
+    public void flush() {
+        // noop
+    }
+
+    @Override
+    public <R extends OFMessage> ListenableFuture<R> writeRequest(OFRequest<R> request) {
+        return Futures.immediateFailedFuture(new SwitchDisconnectedException(getDatapathId()));
+    }
+
+    @Override
+    public void disconnect(){
+        // noop
+    }
+
+    public void disconnected() {
+        // noop
+    }
+
+    @Override
+    public boolean isWritable() {
+        return false;
+    }
+
+    @Override
+    public DatapathId getDatapathId() {
+        return DatapathId.NONE;
+    }
+
+    @Override
+    public OFAuxId getAuxId() {
+        return OFAuxId.MAIN;
+    }
+
+    @Override
+    public void setListener(IOFConnectionListener listener) {
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/OFConnection.java b/src/main/java/net/floodlightcontroller/core/OFConnection.java
new file mode 100644
index 0000000000000000000000000000000000000000..e53c7dfd0c2c61eefd7d8e98f95d599da701d092
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/OFConnection.java
@@ -0,0 +1,408 @@
+/**
+ *    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.isDebugEnabled())
+            logger.debug("{}: 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
new file mode 100644
index 0000000000000000000000000000000000000000..403fb4bbda1c3bd0ec87c8423df624e45b69ab96
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/OFConnectionCounters.java
@@ -0,0 +1,710 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..f990f0a451052dfac060673e5bca7b20d6e802ad
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/OFErrorMsgException.java
@@ -0,0 +1,28 @@
+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
deleted file mode 100644
index c5adf4470355476526cfe896c92195760d5e8d0f..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/OFMessageFilterManager.java
+++ /dev/null
@@ -1,532 +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 java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ScheduledExecutorService;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-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;
-
-import java.util.List;
-import java.util.ArrayList;
-import org.apache.thrift.TException;
-import org.apache.thrift.transport.TFramedTransport;
-import org.apache.thrift.transport.TTransport;
-import org.apache.thrift.transport.TSocket;
-import org.apache.thrift.protocol.TBinaryProtocol;
-import org.apache.thrift.protocol.TProtocol;
-
-import net.floodlightcontroller.core.annotations.LogMessageCategory;
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
-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.packet.Ethernet;
-import net.floodlightcontroller.packetstreamer.thrift.*;
-import net.floodlightcontroller.threadpool.IThreadPoolService;
-
-@LogMessageCategory("OpenFlow Message Tracing")
-public class OFMessageFilterManager 
-        implements IOFMessageListener, IFloodlightModule, IOFMessageFilterManagerService {
-
-    /**
-     * @author Srini
-     */
-    protected static Logger log = LoggerFactory.getLogger(OFMessageFilterManager.class);
-
-    // The port and client reference for packet streaming
-    protected int serverPort = 9090;
-    protected final int MaxRetry = 1;
-    protected static volatile TTransport transport = null;
-    protected static volatile PacketStreamer.Client packetClient = null;
-
-    protected IFloodlightProviderService floodlightProvider = null;
-    protected IThreadPoolService threadPool = null;
-    // filter List is a key value pair.  Key is the session id, 
-    // value is the filter rules.
-    protected ConcurrentHashMap<String, 
-                                ConcurrentHashMap<String,
-                                                  String>> filterMap = null;
-    protected ConcurrentHashMap<String, Long> filterTimeoutMap = null;
-    protected Timer timer = null;
-
-    protected int MAX_FILTERS=5;
-    protected long MAX_FILTER_TIME= 300000; // maximum filter time is 5 minutes.
-    protected int TIMER_INTERVAL = 1000;  // 1 second time interval.
-
-    public static final String SUCCESS                     = "0";
-    public static final String FILTER_SETUP_FAILED         = "-1001"; 
-    public static final String FILTER_NOT_FOUND            = "-1002";
-    public static final String FILTER_LIMIT_REACHED        = "-1003";
-    public static final String FILTER_SESSION_ID_NOT_FOUND = "-1004";
-    public static final String SERVICE_UNAVAILABLE         = "-1005";
-
-    public enum FilterResult {
-        /*
-         * FILTER_NOT_DEFINED: Filter is not defined
-         * FILTER_NO_MATCH:    Filter is defined and the packet doesn't 
-         *                     match the filter
-         * FILTER_MATCH:       Filter is defined and the packet matches
-         *                     the filter
-         */
-        FILTER_NOT_DEFINED, FILTER_NO_MATCH, FILTER_MATCH
-    }
-
-    protected String addFilter(ConcurrentHashMap<String,String> f, long delta) {
-
-        // Create unique session ID.  
-        int prime = 33791;
-        String s = null;
-        int i;
-
-        if ((filterMap == null) || (filterTimeoutMap == null))
-            return String.format("%s", FILTER_SETUP_FAILED);
-
-        for (i=0; i<MAX_FILTERS; ++i) {
-            Integer x = prime + i;
-            s = String.format("%d", x.hashCode());
-            // implies you can use this key for session id.    
-            if (!filterMap.containsKey(s)) break; 
-        }
-
-        if (i==MAX_FILTERS) {
-            return FILTER_LIMIT_REACHED;
-        }
-
-        filterMap.put(s, f);
-        if (filterTimeoutMap.containsKey(s))  filterTimeoutMap.remove(s);
-        filterTimeoutMap.put(s, delta);
-
-        // set the timer as there will be no existing timers. 
-        if (filterMap.size() == 1) { 
-            TimeoutFilterTask task = new TimeoutFilterTask(this);
-            Timer timer = new Timer();
-            timer.schedule (task, TIMER_INTERVAL);                
-            // Keep the listeners to avoid race condition
-            //startListening();
-        }   
-        return s;  // the return string is the session ID.
-    }
-
-    @Override
-    public String setupFilter(String sid, 
-                              ConcurrentHashMap<String,String> f, 
-                              int deltaInMilliSeconds) {
-
-        if (sid == null) {
-            // Delta in filter needs to be milliseconds
-            log.debug("Adding new filter: {} for {} ms", f, deltaInMilliSeconds);
-            return addFilter(f, deltaInMilliSeconds);
-        } else {// this is the session id.
-            // we will ignore the hash map features.
-            if (deltaInMilliSeconds > 0)  
-                return refreshFilter(sid, deltaInMilliSeconds);
-            else 
-                return deleteFilter(sid);
-        }
-    }
-
-    public int timeoutFilters() {                
-        Iterator<String> i = filterTimeoutMap.keySet().iterator();
-
-        while(i.hasNext()) {
-            String s = i.next();
-
-            Long t = filterTimeoutMap.get(s);
-            if (t != null) {
-                i.remove();
-                t -= TIMER_INTERVAL;
-                if (t > 0) {
-                    filterTimeoutMap.put(s, t);
-                } else deleteFilter(s);
-            } else deleteFilter(s);
-        }
-        return filterMap.size();
-    }
-
-    protected String refreshFilter(String s, int delta) {
-        Long t = filterTimeoutMap.get(s);
-        if (t != null) {
-            filterTimeoutMap.remove(s);
-            t += delta;  // time is in milliseconds
-            if (t > MAX_FILTER_TIME) t = MAX_FILTER_TIME;
-            filterTimeoutMap.put(s, t);
-            return SUCCESS;
-        } else return FILTER_SESSION_ID_NOT_FOUND;
-    }
-
-    @LogMessageDoc(level="ERROR",
-                   message="Error while terminating packet " +
-                           "filter session",
-                   explanation="An unknown error occurred while terminating " +
-                   		"a packet filter session.",
-                   recommendation=LogMessageDoc.GENERIC_ACTION)
-    protected String deleteFilter(String sessionId) {
-
-        if (filterMap.containsKey(sessionId)) {
-            filterMap.remove(sessionId);
-            try {
-                if (packetClient != null)
-                    packetClient.terminateSession(sessionId);
-            } catch (TException e) {
-                log.error("Error while terminating packet " +
-                		  "filter session", e);
-            }
-            log.debug("Deleted Filter {}.  # of filters" +
-            		 " remaining: {}", sessionId, filterMap.size());
-            return SUCCESS;
-        } else return FILTER_SESSION_ID_NOT_FOUND;
-    }
-
-    public HashSet<String> getMatchedFilters(OFMessage m, FloodlightContext cntx) {  
-
-        HashSet<String> matchedFilters = new HashSet<String>();
-
-        // This default function is written to match on packet ins and 
-        // packet outs.
-        Ethernet eth = null;
-
-        if (m.getType() == OFType.PACKET_IN) {
-            eth = IFloodlightProviderService.bcStore.get(cntx, 
-                    IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-        } else if (m.getType() == OFType.PACKET_OUT) {
-            eth = new Ethernet();
-            OFPacketOut p = (OFPacketOut) m;
-            
-            // No MAC match if packetOut doesn't have the packet.
-            if (p.getPacketData() == null) return null;
-            
-            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;
-        }
-
-        if (eth == null) return null;
-
-        Iterator<String> filterIt = filterMap.keySet().iterator();
-        while (filterIt.hasNext()) {   // for every filter
-            boolean filterMatch = false;
-            String filterSessionId = filterIt.next();
-            Map<String,String> filter = filterMap.get(filterSessionId);
-
-            // If the filter has empty fields, then it is not considered as a match.
-            if (filter == null || filter.isEmpty()) continue;                  
-            Iterator<String> fieldIt = filter.keySet().iterator();
-            while (fieldIt.hasNext()) {   
-                String filterFieldType = fieldIt.next();
-                String filterFieldValue = filter.get(filterFieldType);
-                if (filterFieldType.equals("mac")) {
-
-                    String srcMac = HexString.toHexString(eth.getSourceMACAddress());
-                    String dstMac = HexString.toHexString(eth.getDestinationMACAddress());
-                    log.debug("srcMac: {}, dstMac: {}", srcMac, dstMac);
-
-                    if (filterFieldValue.equals(srcMac) || 
-                            filterFieldValue.equals(dstMac)){
-                        filterMatch = true; 
-                    } else {
-                        filterMatch = false;
-                        break;
-                    }
-                }
-            }
-            if (filterMatch) {
-                matchedFilters.add(filterSessionId);
-            }
-        }
-
-        if (matchedFilters.isEmpty())
-            return null;    
-        else 
-            return matchedFilters;
-    }
-    
-    @LogMessageDoc(level="ERROR",
-                   message="Failed to establish connection with the " +
-                           "packetstreamer server.",
-                   explanation="The message tracing server is not running " +
-                   		"or otherwise unavailable.",
-                   recommendation=LogMessageDoc.CHECK_CONTROLLER)
-    public boolean connectToPSServer() {
-        int numRetries = 0;
-        if (transport != null && transport.isOpen()) {
-            return true;
-        }
-
-        while (numRetries++ < MaxRetry) {
-            try {
-                TFramedTransport t = 
-                        new TFramedTransport(new TSocket("localhost", 
-                                                         serverPort));
-                t.open();
-
-                TProtocol protocol = new  TBinaryProtocol(t);
-                packetClient = new PacketStreamer.Client(protocol);
-
-                log.debug("Have a connection to packetstreamer server " +
-                		  "localhost:{}", serverPort);
-                transport = t;
-                break;
-            } catch (TException x) {
-                try {
-                    // Wait for 1 second before retry
-                    if (numRetries < MaxRetry) {
-                        Thread.sleep(1000);
-                    }
-                } catch (Exception e) {}
-            } 
-        }
-
-        if (numRetries > MaxRetry) {
-            log.error("Failed to establish connection with the " +
-            		  "packetstreamer server.");
-            return false;
-        }
-        return true;
-    }
-
-    public void disconnectFromPSServer() {
-        if (transport != null && transport.isOpen()) {
-            log.debug("Close the connection to packetstreamer server" +
-            		  " localhost:{}", serverPort);
-            transport.close();
-        }
-    }
-
-    @Override
-    public String getName() {
-        return "messageFilterManager";
-    }
-
-    @Override
-    public boolean isCallbackOrderingPrereq(OFType type, String name) {
-        return (type == OFType.PACKET_IN && name.equals("devicemanager"));
-    }
-
-    @Override
-    public boolean isCallbackOrderingPostreq(OFType type, String name) {
-        return (type == OFType.PACKET_IN && name.equals("learningswitch"));
-    }
-
-    @Override
-    @LogMessageDoc(level="ERROR",
-                   message="Error while sending packet",
-                   explanation="Failed to send a message to the message " +
-                   		"tracing server",
-                   recommendation=LogMessageDoc.CHECK_CONTROLLER)
-    public Command receive(IOFSwitch sw, OFMessage msg, 
-                           FloodlightContext cntx) {
-
-        if (filterMap == null || filterMap.isEmpty()) return Command.CONTINUE;
-
-        HashSet<String> matchedFilters = null;
-        if (log.isDebugEnabled()) {
-            log.debug("Received packet {} from switch {}", 
-                      msg, sw.getStringId());
-        }
-
-        matchedFilters = getMatchedFilters(msg, cntx);
-        if (matchedFilters == null) {
-            return Command.CONTINUE;
-        } else {
-            try {
-                sendPacket(matchedFilters, sw, msg, cntx, true);
-            } catch (Exception e) {
-                log.error("Error while sending packet", e);
-            }
-        }
-        
-        return Command.CONTINUE;
-    }
-
-
-    public class TimeoutFilterTask extends TimerTask {
-
-        OFMessageFilterManager filterManager;
-        ScheduledExecutorService ses = threadPool.getScheduledExecutor();
-
-        public TimeoutFilterTask(OFMessageFilterManager manager) {
-            filterManager = manager;
-        }
-
-        public void run() {
-            int x = filterManager.timeoutFilters();
-
-            if (x > 0) {  // there's at least one filter still active.
-                Timer timer = new Timer();
-                timer.schedule(new TimeoutFilterTask(filterManager), 
-                               TIMER_INTERVAL);
-            } else {
-                // Don't stop the listener to avoid race condition
-                //stopListening();
-            }
-        }
-    }
-
-    public int getNumberOfFilters() {
-        return filterMap.size();
-    }
-
-    public int getMaxFilterSize() {
-        return MAX_FILTERS;
-    }
-
-    protected void sendPacket(HashSet<String> matchedFilters, IOFSwitch sw, 
-            OFMessage msg, FloodlightContext cntx, boolean sync) 
-                    throws TException {
-        Message sendMsg = new Message();
-        Packet packet = new Packet();
-        ChannelBuffer bb;
-        sendMsg.setPacket(packet);
-
-        List<String> sids = new ArrayList<String>(matchedFilters);
-
-        sendMsg.setSessionIDs(sids);
-        packet.setMessageType(OFMessageType.findByValue((msg.getType().ordinal())));
-
-        switch (msg.getType()) {
-            case PACKET_IN:
-                OFPacketIn pktIn = (OFPacketIn)msg;
-                packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), 
-                                                          pktIn.getInPort()));
-                bb = ChannelBuffers.buffer(pktIn.getLength());
-                pktIn.writeTo(bb);
-                packet.setData(OFMessage.getData(sw, msg, cntx));
-                break;
-            case PACKET_OUT:
-                OFPacketOut pktOut = (OFPacketOut)msg;
-                packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), 
-                                                          pktOut.getInPort()));
-                bb = ChannelBuffers.buffer(pktOut.getLength());
-                pktOut.writeTo(bb);
-                packet.setData(OFMessage.getData(sw, msg, cntx));
-                break;
-            case FLOW_MOD:
-                OFFlowMod offlowMod = (OFFlowMod)msg;
-                packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), 
-                                                          offlowMod.
-                                                          getOutPort()));
-                bb = ChannelBuffers.buffer(offlowMod.getLength());
-                offlowMod.writeTo(bb);
-                packet.setData(OFMessage.getData(sw, msg, cntx));
-                break;
-            default:
-                packet.setSwPortTuple(new SwitchPortTuple(sw.getId(), 
-                                                          (short)0));
-                String strData = "Unknown packet";
-                packet.setData(strData.getBytes());
-                break;
-        }
-
-        try {
-            if (transport == null || 
-                !transport.isOpen() || 
-                packetClient == null) {
-                if (!connectToPSServer()) {
-                    // No need to sendPacket if can't make connection to 
-                    // the server
-                    return;
-                }
-            }
-            if (sync) {
-                log.debug("Send packet sync: {}", packet.toString());
-                packetClient.pushMessageSync(sendMsg);
-            } else {
-                log.debug("Send packet sync: ", packet.toString());
-                packetClient.pushMessageAsync(sendMsg);
-            }
-        } catch (Exception e) {
-            log.error("Error while sending packet", e);
-            disconnectFromPSServer();
-            connectToPSServer();
-        }
-    }
-
-    // IFloodlightModule methods
-    
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l = 
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IOFMessageFilterManagerService.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(IOFMessageFilterManagerService.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(IThreadPoolService.class);
-        return l;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context) 
-            throws FloodlightModuleException {
-        this.floodlightProvider = 
-                context.getServiceImpl(IFloodlightProviderService.class);
-        this.threadPool =
-                context.getServiceImpl(IThreadPoolService.class);
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        // This is our 'constructor'
-        
-        filterMap = new ConcurrentHashMap<String, ConcurrentHashMap<String,String>>();
-        filterTimeoutMap = new ConcurrentHashMap<String, Long>();
-        serverPort = 
-                Integer.parseInt(System.getProperty("net.floodlightcontroller." +
-                		"packetstreamer.port", "9090"));
-        
-        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-        floodlightProvider.addOFMessageListener(OFType.PACKET_OUT, this);
-        floodlightProvider.addOFMessageListener(OFType.FLOW_MOD, this);
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/OFSwitch.java b/src/main/java/net/floodlightcontroller/core/OFSwitch.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee6d4c942ac235fb92c667fc7207d804630ba30c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/OFSwitch.java
@@ -0,0 +1,1106 @@
+/**
+*    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.OFPortConfig;
+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 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.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.LINK_DOWN) 
+                		&& !p.getConfig().contains(OFPortConfig.PORT_DOWN)) {
+                    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.LINK_DOWN) 
+                    		&& !prevPort.getConfig().contains(OFPortConfig.PORT_DOWN)) 
+                    		&& (newPort.getState().contains(OFPortState.LINK_DOWN) 
+                    		|| newPort.getConfig().contains(OFPortConfig.PORT_DOWN))) {
+                        events.add(new PortChangeEvent(newPort,
+                                                       PortChangeType.DOWN));
+                    } else if ((prevPort.getState().contains(OFPortState.LINK_DOWN) 
+                    		|| prevPort.getConfig().contains(OFPortConfig.PORT_DOWN)) 
+                    		&& (!newPort.getState().contains(OFPortState.LINK_DOWN) 
+                    		&& !newPort.getConfig().contains(OFPortConfig.PORT_DOWN))) {
+                        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 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>
+                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);
+                    }
+                    // Enabled = not down admin (config) or phys (state)
+                    if (!p.getConfig().contains(OFPortConfig.PORT_DOWN)
+                    		&& !p.getState().contains(OFPortState.LINK_DOWN)) {
+                        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) {
+    	log.debug("Channel info: {} {}", connections.get(OFAuxId.MAIN).getRemoteInetAddress(), connections.get(OFAuxId.MAIN).isConnected());
+        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());
+        }
+        log.debug("~~~~~~~SWITCH DISCONNECTED~~~~~~");
+        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.BLOCKED) && !p.getState().contains(OFPortState.LINK_DOWN) && !p.getState().contains(OFPortState.STP_BLOCK));
+    }
+
+    @Override
+    public boolean portEnabled(String portName) {
+        OFPortDesc p = portManager.getPort(portName);
+        if (p == null) return false;
+        return (!p.getState().contains(OFPortState.BLOCKED) && !p.getState().contains(OFPortState.LINK_DOWN) && !p.getState().contains(OFPortState.STP_BLOCK));
+    }
+
+    @Override
+    public DatapathId getId() {
+        if (datapathId == null)
+            throw new RuntimeException("Features reply has not yet been set");
+        return datapathId;
+    }
+
+    /* (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 void setSwitchProperties(SwitchDescription description) {
+        this.description = description;
+    }
+
+
+    @Override
+    public SwitchStatus getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(SwitchStatus switchStatus) {
+        this.status = switchStatus;
+    }
+
+    @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
deleted file mode 100644
index 1fb321baddd352b137c78e68b99fab388766fd27..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java
+++ /dev/null
@@ -1,1579 +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.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
new file mode 100644
index 0000000000000000000000000000000000000000..557d8417db5dadb117202fd75fad0cab02efdba2
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/PortChangeEvent.java
@@ -0,0 +1,54 @@
+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().getPortNumber()) + "]";
+    }
+}
\ 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
new file mode 100644
index 0000000000000000000000000000000000000000..178d27b7603eebaa1c8400160843fd4e5d04be33
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/PortChangeType.java
@@ -0,0 +1,8 @@
+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 1e6c186f759e2d7b81b529f91438d3b37210f46e..31ec6464c95932a094717a02b18f400d98764d8f 100644
--- a/src/main/java/net/floodlightcontroller/core/RoleInfo.java
+++ b/src/main/java/net/floodlightcontroller/core/RoleInfo.java
@@ -16,67 +16,34 @@
 
 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 {
-    protected String role;
-    protected String roleChangeDescription;
-    protected Date roleChangeDateTime;
-
-    public RoleInfo() {
-    }
-
-    public RoleInfo(RoleInfo o) {
-        role = o.role;
-        roleChangeDescription = o.roleChangeDescription;
-        roleChangeDateTime = (Date)o.roleChangeDateTime.clone();
-    }
+    private final HARole role;
+    private final String roleChangeDescription;
+    private final Date roleChangeDateTime;
 
-    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";
+    public RoleInfo(HARole role, String description, Date dt) {
+        this.role = role;
         this.roleChangeDescription = description;
         this.roleChangeDateTime = dt;
     }
 
-    public String getRole() {
+    public HARole 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 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);
+    public Date getRoleChangeDateTime() {
+        return 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
new file mode 100644
index 0000000000000000000000000000000000000000..57697d70916554da6cb73881b1237fadcd863101
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDescription.java
@@ -0,0 +1,182 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..21b74ec7470071ee2fee36333c0316fd3381b5d7
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDisconnectedException.java
@@ -0,0 +1,23 @@
+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/SwitchDriverSubHandshakeCompleted.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeCompleted.java
index ed39b5f44bc34597b41d3fc848d2b3410c7943b4..fff0a6598185e202042a296e8f67394ee46f9a3c 100644
--- a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeCompleted.java
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeCompleted.java
@@ -1,6 +1,6 @@
 package net.floodlightcontroller.core;
 
-import org.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFMessage;
 
 /**
  * Indicates that a message was passed to a switch driver's subhandshake
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchSyncRepresentation.java b/src/main/java/net/floodlightcontroller/core/SwitchSyncRepresentation.java
index 6284ba3c38785c2e5dc21421d012147f74c165ed..ea583510844a32655d7019afe2a10d620a02c892 100644
--- a/src/main/java/net/floodlightcontroller/core/SwitchSyncRepresentation.java
+++ b/src/main/java/net/floodlightcontroller/core/SwitchSyncRepresentation.java
@@ -2,16 +2,20 @@ 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 net.floodlightcontroller.util.EnumBitmaps;
-import net.floodlightcontroller.util.MACAddress;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
 
-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 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 com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -27,27 +31,11 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class SwitchSyncRepresentation {
     public static class SyncedPort {
         @JsonProperty
-        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 OFPortDesc port;
 
-        public static SyncedPort fromImmutablePort(ImmutablePort p) {
+        /*public static SyncedPort fromImmutablePort(OFPortDesc p) {
             SyncedPort rv = new SyncedPort();
-            rv.portNumber = p.getPortNumber();
+            rv.port = OFPortDesc.of(p.getPortNumber());
             if (p.getHardwareAddress() == null) {
                 rv.hardwareAddress = 0;
             } else {
@@ -66,32 +54,38 @@ public class SwitchSyncRepresentation {
                     EnumBitmaps.toBitmap(p.getSupportedFeatures());
             rv.peerFeatures = EnumBitmaps.toBitmap(p.getPeerFeatures());
             return rv;
-        }
-
-        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;
+        }*/
+
+        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();
         }
     }
 
     // From FeaturesReply
-    private final long dpid;
-    private final int buffers;
-    private final byte tables;
-    private final int capabilities;
-    private final int actions;
+    private final DatapathId dpid;
+    private final long buffers;
+    private final short tables;
+    private final Set<OFCapabilities> capabilities;
+    private final Set<OFActionType> actions;
     private final List<SyncedPort> ports;
 
-    // From OFDescriptionStatistics
+    // From OFDescStatsReply
     private final String manufacturerDescription;
     private final String hardwareDescription;
     private final String softwareDescription;
@@ -115,11 +109,11 @@ public class SwitchSyncRepresentation {
      */
     @JsonCreator
     public SwitchSyncRepresentation(
-            @JsonProperty("dpid") long dpid,
+            @JsonProperty("dpid") DatapathId dpid,
             @JsonProperty("buffers") int buffers,
             @JsonProperty("tables") byte tables,
-            @JsonProperty("capabilities") int capabilities,
-            @JsonProperty("actions") int actions,
+            @JsonProperty("capabilities") Set<OFCapabilities> capabilities,
+            @JsonProperty("actions") Set<OFActionType> actions,
             @JsonProperty("ports") List<SyncedPort> ports,
             @JsonProperty("manufacturerDescription") String manufacturerDescription,
             @JsonProperty("hardwareDescription") String hardwareDescription,
@@ -147,7 +141,7 @@ public class SwitchSyncRepresentation {
         this.actions = sw.getActions();
         this.ports = toSyncedPortList(sw.getPorts());
 
-        OFDescriptionStatistics d = sw.getDescriptionStatistics();
+        SwitchDescription d = sw.getSwitchDescription();
         this.manufacturerDescription = d.getManufacturerDescription();
         this.hardwareDescription = d.getHardwareDescription();
         this.softwareDescription = d.getSoftwareDescription();
@@ -156,14 +150,13 @@ public class SwitchSyncRepresentation {
     }
 
     public SwitchSyncRepresentation(OFFeaturesReply fr,
-                                    OFDescriptionStatistics d) {
+                                    SwitchDescription d) {
         this.dpid = fr.getDatapathId();
-        this.buffers = fr.getBuffers();
-        this.tables = fr.getTables();
+        this.buffers = fr.getNBuffers();
+        this.tables = fr.getNTables();
         this.capabilities = fr.getCapabilities();
         this.actions = fr.getActions();
-        this.ports = toSyncedPortList(
-                ImmutablePort.immutablePortListOf(fr.getPorts()));
+        this.ports = toSyncedPortList(fr.getPorts());
 
         this.manufacturerDescription = d.getManufacturerDescription();
         this.hardwareDescription = d.getHardwareDescription();
@@ -172,65 +165,73 @@ public class SwitchSyncRepresentation {
         this.datapathDescription = d.getDatapathDescription();
     }
 
-    private static List<SyncedPort> toSyncedPortList(Collection<ImmutablePort> ports) {
+    private static List<SyncedPort> toSyncedPortList(Collection<OFPortDesc> ports) {
         List<SyncedPort> rv = new ArrayList<SyncedPort>(ports.size());
-        for (ImmutablePort p: ports) {
-            rv.add(SyncedPort.fromImmutablePort(p));
+        for (OFPortDesc p: ports) {
+            rv.add(SyncedPort.fromOFPortDesc(p));
         }
         return rv;
     }
 
-    private static List<OFPhysicalPort> toOFPhysicalPortList(Collection<SyncedPort> ports) {
-        List<OFPhysicalPort> rv = new ArrayList<OFPhysicalPort>(ports.size());
+    private static List<OFPortDesc> toOFPortDescList(OFFactory factory, Collection<SyncedPort> ports) {
+        List<OFPortDesc> rv = new ArrayList<OFPortDesc>(ports.size());
         for (SyncedPort p: ports) {
-            rv.add(p.toOFPhysicalPort());
+            rv.add(p.toOFPortDesc(factory));
         }
         return rv;
 
     }
 
     @JsonIgnore
-    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;
+    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;
     }
 
     @JsonIgnore
-    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 SwitchDescription getDescription() {
+    	return new SwitchDescription(manufacturerDescription,
+                hardwareDescription, softwareDescription, softwareDescription,
+                datapathDescription);
     }
 
-
-
-    public long getDpid() {
+    public DatapathId getDpid() {
         return dpid;
     }
 
-    public int getBuffers() {
+    public long getBuffers() {
         return buffers;
     }
 
-    public byte getTables() {
+    public short getTables() {
         return tables;
     }
 
-    public int getCapabilities() {
+    public Set<OFCapabilities> getCapabilities() {
         return capabilities;
     }
 
-    public int getActions() {
+    public Set<OFActionType> getActions() {
         return actions;
     }
 
@@ -261,7 +262,7 @@ public class SwitchSyncRepresentation {
     @Override
     public String toString() {
         String dpidString;
-        dpidString = HexString.toHexString(dpid);
+        dpidString = HexString.toHexString(dpid.getLong());
         return "SwitchSyncRepresentation [DPID=" + dpidString + "]";
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/CmdLineSettings.java b/src/main/java/net/floodlightcontroller/core/internal/CmdLineSettings.java
index e22640a91f07b81fe1dba80dd4c81052d4e65610..972321f62e1f2323c5916340d96346ad7d240bc4 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/CmdLineSettings.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/CmdLineSettings.java
@@ -22,7 +22,7 @@ import org.kohsuke.args4j.Option;
  * Expresses the port settings of OpenFlow controller.
  */
 public class CmdLineSettings {
-    public static final String DEFAULT_CONFIG_FILE = "config/floodlight.properties";
+    public static final String DEFAULT_CONFIG_FILE = "src/main/resources/floodlightdefault.properties";
 
     @Option(name="-cf", aliases="--configFile", metaVar="FILE", usage="Floodlight configuration file")
     private String configFile = DEFAULT_CONFIG_FILE;
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 7d6227d108b6a1279056b450622c05750f77e90c..730287381acd161714fa4d8b8fc06e75d79d7017 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -17,71 +17,58 @@
 
 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 org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timer;
+
+import net.floodlightcontroller.core.ControllerId;
 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.IInfoProvider;
+import net.floodlightcontroller.core.IShutdownService;
 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.LogicalOFMessageCategory;
+import net.floodlightcontroller.core.PortChangeType;
 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.module.FloodlightModuleLoader;
 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 org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.types.DatapathId;
+
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
 import net.floodlightcontroller.restserver.IRestApiService;
@@ -90,107 +77,81 @@ 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.sdnplatform.sync.internal.config.ClusterConfig;
+
+import net.floodlightcontroller.util.LoadMonitor;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.bigswitch.floodlight.vendor.OFVendorActions;
-
+import com.google.common.base.Optional;
+import com.google.common.base.Strings;
 
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * The main controller class.  Handles all setup and network listeners
  */
-public class Controller implements IFloodlightProviderService,
-            IStorageSourceListener, IInfoProvider {
+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 static final INotificationManager notifier = NotificationManagerFactory.getNotificationManager(Controller.class);
 
-    protected BasicFactory factory;
-    protected ConcurrentMap<OFType,
-                            ListenerDispatcher<OFType,IOFMessageListener>>
-                                messageListeners;
-
-    // OFSwitch driver binding map and order
-    private ISwitchDriverRegistry driverRegistry;
+    static final String ERROR_DATABASE = "The controller could not communicate with the system database.";
 
+    protected ConcurrentMap<OFType, ListenerDispatcher<OFType,IOFMessageListener>> messageListeners;
+    
     // 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;
+    protected ControllerCounters counters;
+    protected Timer timer;
+    
+    // Module Loader State
+    private ModuleLoaderState moduleLoaderState;
+    public enum ModuleLoaderState {
+        INIT, STARTUP, COMPLETE
+    }
 
     // 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 IStorageSourceService storageSourceService;
+    private IOFSwitchService switchService;
+    private IDebugCounterService debugCounterService;
+    protected IDebugEventService debugEventService;
+    private IRestApiService restApiService;
+    private IPktInProcessingTimeService pktinProcTimeService;
+    private IThreadPoolService threadPoolService;
     private ISyncService syncService;
-    private IStoreClient<Long, SwitchSyncRepresentation> storeClient;
+    private IShutdownService shutdownService;
 
     // Configuration options
-    protected String openFlowHost = null;
-    protected int openFlowPort = 6633;
+    protected int openFlowPort = 6653; // new registered OF port number
+    private String openFlowHostname = null;
     protected int workerThreads = 0;
-
+    
+    // The id for this controller node. Should be unique for each controller
+    // node in a controller cluster.
+    protected String controllerId = "my-floodlight-controller";
 
     // 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;
+    // if they should operate in ACTIVE / STANDBY
+    protected volatile HARole notifiedRole;
 
     private static final String
             INITIAL_ROLE_CHANGE_DESCRIPTION = "Controller startup.";
+    /**
+     * NOTE: roleManager is not 'final' because it's initialized at run time
+     * based on parameters that are only available in init()
+     */
     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";
@@ -218,15 +179,12 @@ public class Controller implements IFloodlightProviderService,
             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;
-
-
+    // TODO @Ryan delete? not referenced anywhere private static short DEFAULT_ACCESS_PRIORITY = 10;
+    // TODO @Ryan delete? not referenced anywhere private static short DEFAULT_CORE_PRIORITY = 1000;
+    
     // Perf. related configuration
     protected static final int SEND_BUFFER_SIZE = 128 * 1024;
-    public static final int BATCH_MAX_SIZE = 100;
+    public static final int BATCH_MAX_SIZE = 1; //TODO @Ryan this was 100. Causes packet_out messages to stall until 100 accumulated...
     protected static final boolean ALWAYS_DECODE_ETH = true;
 
     // Set of port name prefixes that will be classified as uplink ports,
@@ -242,1337 +200,59 @@ public class Controller implements IFloodlightProviderService,
         this.uplinkPortPrefixSet = prefixSet;
     }
 
-    // Event IDs for debug events
-    protected IEventUpdater<SwitchEvent> evSwitch;
+    @Override
+    public ModuleLoaderState getModuleLoaderState(){
+        return this.moduleLoaderState;
+    }
 
     // Load monitor for overload protection
-    protected final boolean overload_drop =
-        Boolean.parseBoolean(System.getProperty("overload_drop", "false"));
+    protected final boolean overload_drop = Boolean.parseBoolean(System.getProperty("overload_drop", "false"));
     protected final LoadMonitor loadmonitor = new LoadMonitor(log);
-
-    private class NotificationSwitchListener implements IOFSwitchListener {
+    
+    private static class NotificationSwitchListener implements IOFSwitchListener {
 
         @Override
-        public void switchAdded(long switchId) {
-            notifier.postNotification("Switch " + HexString.toHexString(switchId) + " connected.");
+        public void switchAdded(DatapathId switchId) {
+            notifier.postNotification("Switch " +  switchId + " connected.");
         }
 
         @Override
-        public void switchRemoved(long switchId) {
-            notifier.postNotification("Switch " + HexString.toHexString(switchId) + " disconnected.");
+        public void switchRemoved(DatapathId switchId) {
+            notifier.postNotification("Switch " + switchId + " disconnected.");
         }
 
         @Override
-        public void switchActivated(long switchId) {
+        public void switchActivated(DatapathId switchId) {
+
         }
 
         @Override
-        public void switchPortChanged(long switchId, ImmutablePort port,
+        public void switchPortChanged(DatapathId switchId, OFPortDesc port,
                                       PortChangeType type) {
             String msg = String.format("Switch %s port %s changed: %s",
-                                       HexString.toHexString(switchId),
+                                       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);
-            }
+        public void switchChanged(DatapathId switchId) {
         }
-
-        /**
-         * 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 {
+    public 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;
-            }
-        }
-    }
-
+    
+    //TODO @Ryan ReadyForReconcileUpdate was here. Obsolete?
+    
     /**
      * Update message indicating
      * IPs of controllers in controller cluster have changed.
@@ -1612,51 +292,67 @@ public class Controller implements IFloodlightProviderService,
     // ***************
 
     void setStorageSourceService(IStorageSourceService storageSource) {
-        this.storageSource = storageSource;
+        this.storageSourceService = storageSource;
     }
 
     IStorageSourceService getStorageSourceService() {
-        return this.storageSource;
+        return this.storageSourceService;
     }
-
-    void setCounterStore(ICounterStoreService counterStore) {
-        this.counterStore = counterStore;
+    
+    IShutdownService getShutdownService() {
+    	return this.shutdownService;
     }
-
-    void setDebugCounter(IDebugCounterService debugCounters) {
-        this.debugCounters = debugCounters;
+    
+    void setShutdownService(IShutdownService shutdownService) {
+    	this.shutdownService = shutdownService;
     }
 
     public void setDebugEvent(IDebugEventService debugEvent) {
-        this.debugEvents = debugEvent;
+        this.debugEventService = debugEvent;
+    }
+    
+    void setDebugCounter(IDebugCounterService debugCounters) {
+        this.debugCounterService = debugCounters;
     }
 
     IDebugCounterService getDebugCounter() {
-        return this.debugCounters;
+        return this.debugCounterService;
     }
 
     void setSyncService(ISyncService syncService) {
         this.syncService = syncService;
     }
     void setPktInProcessingService(IPktInProcessingTimeService pits) {
-        this.pktinProcTime = pits;
+        this.pktinProcTimeService = pits;
     }
-
+    
     void setRestApiService(IRestApiService restApi) {
-        this.restApi = restApi;
+        this.restApiService = restApi;
     }
 
+    
     void setThreadPoolService(IThreadPoolService tp) {
-        this.threadPool = tp;
+        this.threadPoolService = tp;
     }
-
     IThreadPoolService getThreadPoolService() {
-        return this.threadPool;
+        return this.threadPoolService;
+    }
+
+    
+    public void setSwitchService(IOFSwitchService switchService) {
+       this.switchService = switchService;
+    }
+    public IOFSwitchService getSwitchService() {
+        return this.switchService;
     }
 
     @Override
-    public Role getRole() {
-        // FIXME:
+    public int getWorkerThreads() {
+        return this.workerThreads;
+    }
+
+    @Override
+    public HARole getRole() {
         return notifiedRole;
     }
 
@@ -1666,39 +362,15 @@ public class Controller implements IFloodlightProviderService,
     }
 
     @Override
-    public void setRole(Role role, String roleChangeDescription) {
-        roleManager.setRole(role, roleChangeDescription);
+    public void setRole(HARole role, String changeDescription) {
+        roleManager.setRole(role, changeDescription);
     }
 
     // ****************
     // 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);
-     }
+    
+    // Handler for SwitchPortsChanged was here (notifyPortChanged). Handled in OFSwitchManager
 
     /**
      * flcontext_cache - Keep a thread local stack of contexts
@@ -1765,33 +437,33 @@ public class Controller implements IFloodlightProviderService,
                 explanation="The switch sent a message not handled by " +
                         "the controller")
     })
-    protected void handleMessage(IOFSwitch sw, OFMessage m,
-                                 FloodlightContext bContext)
-            throws IOException {
+    @SuppressFBWarnings(value="SF_SWITCH_NO_DEFAULT",
+                        justification="False positive -- has default")
+    @Override
+    public void handleMessage(IOFSwitch sw, OFMessage m,
+                                 FloodlightContext bContext) {
         Ethernet eth = null;
-
-        if (this.notifiedRole == Role.SLAVE) {
-            counters.dispatchMessageWhileSlave.updateCounterNoFlush();
+        log.debug("~~~~~~~~GOT PACKET IN MESSAGE FROM SWITCH~~~~~~~~~");
+        if (this.notifiedRole == HARole.STANDBY) {
+            counters.dispatchMessageWhileStandby.increment();
             // We are SLAVE. Do not dispatch messages to listeners.
             return;
         }
-        counters.dispatchMessage.updateCounterNoFlush();
+        counters.dispatchMessage.increment();
 
         switch (m.getType()) {
             case PACKET_IN:
+            	counters.packetIn.increment();
                 OFPacketIn pi = (OFPacketIn)m;
 
-                if (pi.getPacketData().length <= 0) {
-                    log.error("Ignoring PacketIn (Xid = " + pi.getXid() +
-                              ") because the data field is empty.");
+                if (pi.getData().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);
+                    eth.deserialize(pi.getData(), 0, pi.getData().length);
                 }
                 // fall through to default case...
 
@@ -1799,8 +471,7 @@ public class Controller implements IFloodlightProviderService,
 
                 List<IOFMessageListener> listeners = null;
                 if (messageListeners.containsKey(m.getType())) {
-                    listeners = messageListeners.get(m.getType()).
-                            getOrderedListeners();
+                    listeners = messageListeners.get(m.getType()).getOrderedListeners();
                 }
 
                 FloodlightContext bc = null;
@@ -1822,18 +493,19 @@ public class Controller implements IFloodlightProviderService,
                     // Get the starting time (overall and per-component) of
                     // the processing chain for this packet if performance
                     // monitoring is turned on
-                    pktinProcTime.recordStartTimePktIn();
+                    pktinProcTimeService.bootstrap(listeners);
+                    pktinProcTimeService.recordStartTimePktIn();
                     Command cmd;
                     for (IOFMessageListener listener : listeners) {
-                        pktinProcTime.recordStartTimeComp(listener);
+                        pktinProcTimeService.recordStartTimeComp(listener);
                         cmd = listener.receive(sw, m, bc);
-                        pktinProcTime.recordEndTimeComp(listener);
+                        pktinProcTimeService.recordEndTimeComp(listener);
 
                         if (Command.STOP.equals(cmd)) {
                             break;
                         }
                     }
-                    pktinProcTime.recordEndTimePktIn(sw, m, bc);
+                    pktinProcTimeService.recordEndTimePktIn(sw, m, bc);
                 } else {
                     if (m.getType() != OFType.BARRIER_REPLY)
                         log.warn("Unhandled OF Message: {} from {}", m, sw);
@@ -1844,77 +516,36 @@ public class Controller implements IFloodlightProviderService,
                 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 ofSwitchHandshakeHandler
      * @param role
      */
-    void reassertRole(OFChannelHandler h, Role role) {
-        roleManager.reassertRole(h, role);
+    void reassertRole(OFSwitchHandshakeHandler ofSwitchHandshakeHandler, HARole role) {
+        roleManager.reassertRole(ofSwitchHandshakeHandler, role);
     }
 
-    // FIXME: remove this method
     @Override
-    public Map<Long,IOFSwitch> getAllSwitchMap() {
-        return this.switchManager.getAllSwitchMap();
+    public String getControllerId() {
+        return controllerId;
     }
-
+    
     @Override
-    public Set<Long> getAllSwitchDpids() {
-        return this.switchManager.getAllSwitchDpids();
+    public String getOFHostname() {
+        return openFlowHostname;
     }
-
-    @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);
+    public int getOFPort() {
+        return openFlowPort;
     }
 
     @Override
-    public synchronized void addOFMessageListener(OFType type,
-                                                  IOFMessageListener listener) {
+    public synchronized void addOFMessageListener(OFType type, IOFMessageListener listener) {
         ListenerDispatcher<OFType, IOFMessageListener> ldd =
             messageListeners.get(type);
         if (ldd == null) {
@@ -1925,8 +556,7 @@ public class Controller implements IFloodlightProviderService,
     }
 
     @Override
-    public synchronized void removeOFMessageListener(OFType type,
-                                                     IOFMessageListener listener) {
+    public synchronized void removeOFMessageListener(OFType type, IOFMessageListener listener) {
         ListenerDispatcher<OFType, IOFMessageListener> ldd =
             messageListeners.get(type);
         if (ldd != null) {
@@ -1935,14 +565,9 @@ public class Controller implements IFloodlightProviderService,
     }
 
     private void logListeners() {
-        for (Map.Entry<OFType,
-                       ListenerDispatcher<OFType,
-                                          IOFMessageListener>> entry
-             : messageListeners.entrySet()) {
-
+        for (Map.Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> entry : messageListeners.entrySet()) {
             OFType type = entry.getKey();
-            ListenerDispatcher<OFType, IOFMessageListener> ldd =
-                    entry.getValue();
+            ListenerDispatcher<OFType, IOFMessageListener> ldd = entry.getValue();
 
             StringBuilder sb = new StringBuilder();
             sb.append("OFListeners for ");
@@ -1972,76 +597,25 @@ public class Controller implements IFloodlightProviderService,
     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()) {
+        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) {
+    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m) {
         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);
-        }
+
+        // FIXME floodlight context not supported any more
+        FloodlightContext bc = new FloodlightContext();
 
         List<IOFMessageListener> listeners = null;
         if (messageListeners.containsKey(m.getType())) {
-            listeners =
-                    messageListeners.get(m.getType()).getOrderedListeners();
+            listeners = messageListeners.get(m.getType()).getOrderedListeners();
         }
 
         if (listeners != null) {
@@ -2053,16 +627,10 @@ public class Controller implements IFloodlightProviderService,
         }
     }
 
-    @Override
-    public BasicFactory getOFMessageFactory() {
-        return factory;
-    }
-
     // **************
     // Initialization
     // **************
 
-
     /**
      * Sets the initial role based on properties in the config params.
      * It looks for two different properties.
@@ -2092,42 +660,19 @@ public class Controller implements IFloodlightProviderService,
                             "properties file",
                 recommendation=LogMessageDoc.CHECK_CONTROLLER)
     })
-    protected Role getInitialRole(Map<String, String> configParams) {
-        Role role = Role.MASTER;
+    protected HARole getInitialRole(Map<String, String> configParams) {
+        HARole role = HARole.STANDBY;
         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);
+                role = HARole.valueOfBackwardsCompatible(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;
     }
 
@@ -2150,34 +695,12 @@ public class Controller implements IFloodlightProviderService,
                 recommendation=LogMessageDoc.GENERIC_ACTION)
     })
     public void run() {
+        this.moduleLoaderState = ModuleLoaderState.COMPLETE;
+
         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();
@@ -2185,170 +708,113 @@ public class Controller implements IFloodlightProviderService,
             } catch (InterruptedException e) {
                 log.error("Received interrupted exception in updates loop;" +
                           "terminating process");
-                terminate();
+                log.info("Calling System.exit");
+                System.exit(1);
             } catch (StorageException e) {
                 log.error("Storage exception in controller " +
                           "updates loop; terminating process", e);
-                terminate();
+                log.info("Calling System.exit");
+                System.exit(1);
             } 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) throws FloodlightModuleException {
+        String ofPort = configParams.get("openflowPort");
+        if (!Strings.isNullOrEmpty(ofPort)) {
+            try {
+                this.openFlowPort = Integer.parseInt(ofPort);
+            } catch (NumberFormatException e) {
+                log.error("invalid openflow port specifier", e);
+                throw new FloodlightModuleException("invalid port specifier in cofig");
+            }
+            log.debug("OpenFlow port set to {}", this.openFlowPort);
         }
-    }
 
-    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) {
+        if (!Strings.isNullOrEmpty(threads)) {
             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) {
+    public void init(Map<String, String> configParams) throws FloodlightModuleException {
+
+        this.moduleLoaderState = ModuleLoaderState.INIT;
+
         // 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();
+        // module's startUp() might be called before ours        
+        this.messageListeners = new ConcurrentHashMap<OFType, ListenerDispatcher<OFType, IOFMessageListener>>();
+        this.haListeners = new ListenerDispatcher<HAListenerTypeMarker, IHAListener>();
         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");
+        HARole initialRole = getInitialRole(configParams);
+        this.notifiedRole = initialRole;
+        this.shutdownService = new ShutdownServiceImpl();
 
-        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");
-        }
+        this.roleManager = new RoleManager(this, this.shutdownService,
+                                           this.notifiedRole,
+                                           INITIAL_ROLE_CHANGE_DESCRIPTION);
+        this.timer = new HashedWheelTimer();
 
-        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);
-                    }
-                }
-            }
-        }
+        // Switch Service Startup
+        this.switchService.registerLogicalOFMessageCategory(LogicalOFMessageCategory.MAIN);
+        this.switchService.addOFSwitchListener(new NotificationSwitchListener());
 
-        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
+        this.counters = new ControllerCounters(debugCounterService);
      }
 
     /**
      * Startup all of the controller's components
+     * @param floodlightModuleLoader
      */
     @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 {
+    public void startupComponents(FloodlightModuleLoader floodlightModuleLoader) throws FloodlightModuleException {
+
+        this.moduleLoaderState = ModuleLoaderState.STARTUP;
+
         // 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);
+        storageSourceService.createTable(CONTROLLER_TABLE_NAME, null);
+        storageSourceService.createTable(CONTROLLER_INTERFACE_TABLE_NAME, null);
+        storageSourceService.createTable(SWITCH_CONFIG_TABLE_NAME, null);
+        storageSourceService.setTablePrimaryKeyName(CONTROLLER_TABLE_NAME, CONTROLLER_ID);
+        storageSourceService.addListener(CONTROLLER_INTERFACE_TABLE_NAME, this);
+
+        storageSourceService.createTable(FLOW_PRIORITY_TABLE_NAME, null);
+        storageSourceService.setTablePrimaryKeyName(FLOW_PRIORITY_TABLE_NAME, FLOW_COLUMN_PRIMARY_KEY);
+        storageSourceService.addListener(FLOW_PRIORITY_TABLE_NAME, this);
         readFlowPriorityConfigurationFromStorage();
-
+        
         // Startup load monitoring
         if (overload_drop) {
-            this.loadmonitor.startMonitoring(
-                this.threadPool.getScheduledExecutor());
+            this.loadmonitor.startMonitoring(this.threadPoolService.getScheduledExecutor());
         }
 
         // Add our REST API
-        restApi.addRestletRoutable(new CoreWebRoutable());
-
-        this.ses = threadPool.getScheduledExecutor();
-
+        restApiService.addRestletRoutable(new CoreWebRoutable());
+                
         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);
+            this.syncService.registerStore(OFSwitchManager.SWITCH_SYNC_STORE_NAME, Scope.LOCAL);
         } 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",
@@ -2356,7 +822,7 @@ public class Controller implements IFloodlightProviderService,
     private void readFlowPriorityConfigurationFromStorage() {
         try {
             Map<String, Object> row;
-            IResultSet resultSet = storageSource.executeQuery(
+            IResultSet resultSet = storageSourceService.executeQuery(
                 FLOW_PRIORITY_TABLE_NAME, FLOW_COLUMN_NAMES, null, null);
             if (resultSet == null)
                 return;
@@ -2367,20 +833,17 @@ public class Controller implements IFloodlightProviderService,
                     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));
+                            //TODO @Ryan delete? Not referenced anywhere DEFAULT_ACCESS_PRIORITY = 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));
+                            //TODO @Ryan delete? Not referenced anywhere DEFAULT_CORE_PRIORITY = Short.valueOf((String) row.get(FLOW_COLUMN_CORE_PRIORITY));
                         }
                     }
                 }
             }
         }
         catch (StorageException e) {
-            log.error("Failed to access storage for forwarding configuration: {}",
-                      e.getMessage());
+            log.error("Failed to access storage for forwarding configuration: {}", e.getMessage());
         }
         catch (NumberFormatException e) {
             // log error, no stack-trace
@@ -2389,34 +852,6 @@ public class Controller implements IFloodlightProviderService,
         }
     }
 
-
-    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)) {
@@ -2431,7 +866,6 @@ public class Controller implements IFloodlightProviderService,
             log.debug("Provider type {} doesn't exist.", type);
             return;
         }
-
         providerMap.get(type).remove(provider);
     }
 
@@ -2443,7 +877,6 @@ public class Controller implements IFloodlightProviderService,
         for (IInfoProvider provider : providerMap.get(type)) {
             result.putAll(provider.getInfo(type));
         }
-
         return result;
     }
 
@@ -2457,12 +890,6 @@ public class Controller implements IFloodlightProviderService,
         this.haListeners.removeListener(listener);
     }
 
-    @Override
-    public void addReadyForReconcileListener(IReadyForReconcileListener l) {
-        this.readyForReconcileListeners.add(l);
-    }
-
-
     /**
      * Handle changes to the controller nodes IPs and dispatch update.
      */
@@ -2481,7 +908,7 @@ public class Controller implements IFloodlightProviderService,
             // 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,
+            IResultSet res = storageSourceService.executeQuery(CONTROLLER_INTERFACE_TABLE_NAME,
                     colNames,null, null);
             while (res.next()) {
                 if (res.getString(CONTROLLER_INTERFACE_TYPE).equals("Ethernet") &&
@@ -2513,7 +940,7 @@ public class Controller implements IFloodlightProviderService,
                                              controllerNodeIPsCache.get(removedControllerID));
             controllerNodeIPsCache.clear();
             controllerNodeIPsCache.putAll(curControllerNodeIPs);
-            counters.controllerNodeIpsChanged.updateCounterWithFlush();
+            //counters.controllerNodeIpsChanged.updateCounterWithFlush();
             HAControllerNodeIPUpdate update = new HAControllerNodeIPUpdate(
                                 curControllerNodeIPs, addedControllerNodeIPs,
                                 removedControllerNodeIPs);
@@ -2522,7 +949,7 @@ public class Controller implements IFloodlightProviderService,
             }
         }
     }
-
+    
     @Override
     public Map<String, String> getControllerNodeIPs() {
         // We return a copy of the mapping so we can guarantee that
@@ -2534,7 +961,7 @@ public class Controller implements IFloodlightProviderService,
         }
         return retval;
     }
-
+    
     private static final String FLOW_PRIORITY_CHANGED_AFTER_STARTUP =
             "Flow priority configuration has changed after " +
             "controller startup. Restart controller for new " +
@@ -2553,8 +980,6 @@ public class Controller implements IFloodlightProviderService,
         } else if (tableName.equals(FLOW_PRIORITY_TABLE_NAME)) {
             log.warn(FLOW_PRIORITY_CHANGED_AFTER_STARTUP);
         }
-
-
     }
 
     @Override
@@ -2572,12 +997,6 @@ public class Controller implements IFloodlightProviderService,
         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>();
@@ -2593,37 +1012,13 @@ public class Controller implements IFloodlightProviderService,
         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) {
+    @Override
+    public void addUpdateToQueue(IUpdate update) {
         try {
             this.updates.put(update);
         } catch (InterruptedException e) {
@@ -2632,22 +1027,6 @@ public class Controller implements IFloodlightProviderService,
         }
     }
 
-    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
@@ -2670,18 +1049,17 @@ public class Controller implements IFloodlightProviderService,
 
     /**
      * FOR TESTING ONLY
-     * @param update
      */
-    void setConsolidateStoreTaskDelay(int consolidateStoreTaskDelayMs) {
-        this.consolidateStoreTimeDelayMs = consolidateStoreTaskDelayMs;
+    void resetModuleState() {
+        this.moduleLoaderState = ModuleLoaderState.INIT;
     }
 
     /**
      * FOR TESTING ONLY
-     * returns the store listener so we can send events to the listener
+     * sets module loader state
      */
-    IStoreListener<Long> getStoreListener() {
-        return this.switchManager;
+    void setModuleLoaderStateForTesting(ModuleLoaderState state) {
+        this.moduleLoaderState = state;
     }
 
     @Override
@@ -2690,7 +1068,35 @@ public class Controller implements IFloodlightProviderService,
 
         Map<String, Object> info = new HashMap<String, Object>();
 
-        info.put("# Switches", this.getAllSwitchDpids().size());
+        info.put("# Switches", this.switchService.getAllSwitchDpids().size());
         return info;
     }
+
+    protected void setNotifiedRole(HARole newRole) {
+        notifiedRole = newRole;
+    }
+
+    @Override
+    public RoleManager getRoleManager() {
+        return this.roleManager;
+    }
+
+    public Optional<ControllerId> getId() {
+        short nodeId = this.syncService.getLocalNodeId();
+        if(nodeId == ClusterConfig.NODE_ID_UNCONFIGURED)
+            return Optional.absent();
+        else
+            return Optional.of(ControllerId.of(nodeId));
+    }
+
+    @Override
+    public Timer getTimer() {
+        return this.timer;
+    }
+
+    public ControllerCounters getCounters() {
+        return this.counters;
+    }
 }
+
+
diff --git a/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java b/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java
new file mode 100644
index 0000000000000000000000000000000000000000..de5b99255c8e2968a7d914b50dc7c0115f330d4c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/ControllerCounters.java
@@ -0,0 +1,50 @@
+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 final IDebugCounter packetIn;
+
+    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);
+        
+        packetIn = debugCounters.registerCounter(prefix, "packet-in", "Number of packet_in's seen");
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java b/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java
index 8299bb2c223f6c93437813db9dc8963acf386859..e28d428a2a2cb210600a3ea700bdb112648c70f6 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/FloodlightProvider.java
@@ -21,6 +21,10 @@ 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.sdnplatform.sync.ISyncService;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -28,7 +32,6 @@ 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.counter.ICounterStoreService;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.debugevent.IDebugEventService;
 import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
@@ -39,6 +42,10 @@ 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 =
@@ -67,9 +74,9 @@ public class FloodlightProvider implements IFloodlightModule {
         dependencies.add(IStorageSourceService.class);
         dependencies.add(IPktInProcessingTimeService.class);
         dependencies.add(IRestApiService.class);
-        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;
@@ -81,8 +88,6 @@ public class FloodlightProvider implements IFloodlightModule {
            context.getServiceImpl(IStorageSourceService.class));
        controller.setPktInProcessingService(
            context.getServiceImpl(IPktInProcessingTimeService.class));
-       controller.setCounterStore(
-           context.getServiceImpl(ICounterStoreService.class));
        controller.setDebugCounter(
            context.getServiceImpl(IDebugCounterService.class));
        controller.setDebugEvent(
@@ -93,12 +98,19 @@ public class FloodlightProvider implements IFloodlightModule {
            context.getServiceImpl(IThreadPoolService.class));
        controller.setSyncService(
            context.getServiceImpl(ISyncService.class));
+       controller.setSwitchService(
+    	   context.getServiceImpl(IOFSwitchService.class));
        controller.init(context.getConfigParams(this));
     }
 
     @Override
     public void startUp(FloodlightModuleContext context)
             throws FloodlightModuleException {
-        controller.startupComponents();
+        controller.startupComponents(context.getModuleLoader());
+    }
+    
+    @Run(mainLoop=true)
+    public void run() throws FloodlightModuleException {
+        controller.run();
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java b/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
index e89b3895c7e77ff7fde72e83e61aad25e1598fe1..89ef68109bdc715eb2c16ea3f59f6c2c7b33fc67 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,36 +30,37 @@ 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 channelHandler;
+
+    final OFChannelHandler handshakeHandler;
     final Timer timer;
     final long timeoutNanos;
     volatile Timeout timeout;
-    
-    public HandshakeTimeoutHandler(OFChannelHandler channelHandler,
+
+    public HandshakeTimeoutHandler(OFChannelHandler handshakeHandler,
                                    Timer timer,
                                    long timeoutSeconds) {
         super();
-        this.channelHandler = channelHandler;
+        this.handshakeHandler = handshakeHandler;
         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 {
@@ -68,7 +69,7 @@ public class HandshakeTimeoutHandler
             timeout = null;
         }
     }
-    
+
     private final class HandshakeTimeoutTask implements TimerTask {
 
         private final ChannelHandlerContext ctx;
@@ -86,7 +87,7 @@ public class HandshakeTimeoutHandler
             if (!ctx.getChannel().isOpen()) {
                 return;
             }
-            if (!channelHandler.isHandshakeComplete())
+            if (!handshakeHandler.isSwitchHandshakeComplete())
                 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
new file mode 100644
index 0000000000000000000000000000000000000000..fd45309f30208a9b965de54fa92c7b1e4f5859e2
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/IAppHandshakePluginFactory.java
@@ -0,0 +1,19 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..9f03bc38e422bb3da8623b5e8bf2eddf245d7d90
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/INewOFConnectionListener.java
@@ -0,0 +1,19 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..f537e2d4fff00de8405346326f91fff9a93cba42
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/IOFConnectionListener.java
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..81a85346ca78e944cf2cf6dd4d52d6fb7d74ee16
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchManager.java
@@ -0,0 +1,124 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..24e105ed06a96824231e3e1de5aeee5be6010672
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchService.java
@@ -0,0 +1,120 @@
+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.IOFSwitchDriver;
+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);
+    
+    /**
+     * Add a switch driver
+     * @param manufacturerDescriptionPrefix
+     * @param driver
+     */
+    void addOFSwitchDriver(String manufacturerDescriptionPrefix, IOFSwitchDriver driver);
+
+    /**
+     * 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
index 6251fd26db9eab73cef4824c28ef20100d3b756f..a0cdf915338a43ad93536c6b19f37227b43dd1f2 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/ISwitchDriverRegistry.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/ISwitchDriverRegistry.java
@@ -1,9 +1,11 @@
 package net.floodlightcontroller.core.internal;
 
-import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFConnectionBackend;
+import net.floodlightcontroller.core.IOFSwitchBackend;
 import net.floodlightcontroller.core.IOFSwitchDriver;
-
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
+import net.floodlightcontroller.core.SwitchDescription;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.types.DatapathId;
 
 /**
  * Maintain a registry for SwitchDrivers. Drivers can register with the
@@ -27,7 +29,7 @@ public interface ISwitchDriverRegistry {
      *
      * @param manufacturerDescriptionPrefix Register the given prefix
      * with the driver.
-     * @param driver A IOFSwitchDriver instance to handle IOFSwitch instaniation
+     * @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
@@ -37,7 +39,7 @@ public interface ISwitchDriverRegistry {
     void addSwitchDriver(String manufacturerDescriptionPrefix,
                          IOFSwitchDriver driver);
     /**
-     * Return an IOFSwitch instance according to the description stats.
+     * Return an IOFSwitch instance according to the switch description.
      *
      * 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
@@ -47,14 +49,17 @@ public interface ISwitchDriverRegistry {
      * 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
+     * switch properties set according to the SwitchDescription passed in
      *
-     * @param description The OFDescriptionStatistics for which to return an
+     *@param connection The main OF connection
+     * @param description The SwitchDescription for which to return an
      * IOFSwitch implementation
+     * @param factory The factory to use to create OF messages.
+     * @param datapathId
      * @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.
+     * @throws NullPointerException If the SwitchDescription or any of its
+     * members is null.
      */
-    IOFSwitch getOFSwitchInstance(OFDescriptionStatistics description);
+    IOFSwitchBackend getOFSwitchInstance(IOFConnectionBackend connection, SwitchDescription description, OFFactory factory, DatapathId datapathId);
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/NaiiveSwitchDriverRegistry.java b/src/main/java/net/floodlightcontroller/core/internal/NaiiveSwitchDriverRegistry.java
deleted file mode 100644
index 8109e3add7ebc6f580596eccac975e14b3bf7c6c..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/NaiiveSwitchDriverRegistry.java
+++ /dev/null
@@ -1,105 +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 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
new file mode 100644
index 0000000000000000000000000000000000000000..6f2fffed183dd3e58ab59729a5f8d636ad3a9009
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/NaiveSwitchDriverRegistry.java
@@ -0,0 +1,102 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..bf84d89a9047bf4bdc91bb635e6aecd11d0cbf69
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/NiciraRoleUtils.java
@@ -0,0 +1,40 @@
+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/OFAuxException.java b/src/main/java/net/floodlightcontroller/core/internal/OFAuxException.java
new file mode 100644
index 0000000000000000000000000000000000000000..e2a6ccfdd8c0e1a6af30bfe91f4fecea3b6035d5
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFAuxException.java
@@ -0,0 +1,42 @@
+/**
+*    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;
+
+/**
+ * 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>
+ */
+public class OFAuxException extends SwitchStateException{
+
+        private static final long serialVersionUID = 8452081020837079086L;
+
+        public OFAuxException() {
+            super();
+        }
+
+        public OFAuxException(String arg0) {
+            super(arg0);
+        }
+
+        public OFAuxException(Throwable arg0) {
+            super(arg0);
+        }
+        
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
index 4af5444cae8317b0cee0fb811fcd487e0b78cb94..ca76c6af55d27536b3741538e47d8a86056d73d3 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
@@ -2,1783 +2,758 @@ 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 javax.annotation.Nonnull;
+
 import org.jboss.netty.channel.Channel;
 import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelPipeline;
 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.IdleStateHandler;
 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.jboss.netty.util.Timer;
+import net.floodlightcontroller.core.IOFConnectionBackend;
+import net.floodlightcontroller.core.OFConnection;
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
+import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandler;
+import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandshakeTimeout;
+import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineIdleReadTimeout;
+import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineIdleWriteTimeout;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+import org.projectfloodlight.openflow.protocol.OFEchoReply;
+import org.projectfloodlight.openflow.protocol.OFEchoRequest;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+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.OFFeaturesRequest;
+import org.projectfloodlight.openflow.protocol.OFHello;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.OFAuxId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.bigswitch.floodlight.vendor.OFBigSwitchVendorData;
-import com.bigswitch.floodlight.vendor.OFBsnL2TableSetVendorData;
-
-
+import com.google.common.base.Preconditions;
 
 /**
  * Channel handler deals with the switch connection and dispatches
- * switch messages to the appropriate locations.
- * @author readams
+ *  messages to the higher orders of control.
+ * @author Jason Parraga <Jason.Parraga@Bigswitch.com>
  */
-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);
-            }
-        },
-
-        /**
-         * 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);
-    }
+class OFChannelHandler extends IdleStateAwareChannelHandler {
+
+	private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
+
+	private final ChannelPipeline pipeline;
+	private final INewOFConnectionListener newConnectionListener;
+	private final SwitchManagerCounters counters;
+	private Channel channel;
+	private final Timer timer;
+	private volatile OFChannelState state;
+	private OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
+	private OFFeaturesReply featuresReply;
+	private volatile OFConnection connection;
+	private final IDebugCounterService debugCounters;
+
+	/** 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;
+
+
+	/**
+	 * Default implementation for message handlers in any OFChannelState.
+	 *
+	 * Individual states must override these if they want a behavior
+	 * that differs from the default.
+	 */
+	public abstract class OFChannelState {
+
+		void processOFHello(OFHello m)
+				throws IOException {
+			// we only expect hello in the WAIT_HELLO state
+			illegalMessageReceived(m);
+		}
+
+		void processOFEchoRequest(OFEchoRequest m)
+				throws IOException {
+			sendEchoReply(m);
+		}
+
+		void processOFEchoReply(OFEchoReply m)
+				throws IOException {
+			// do nothing
+		}
+
+		void processOFError(OFErrorMsg m) {
+			logErrorDisconnect(m);
+		}
+
+		void processOFExperimenter(OFExperimenter m) {
+			unhandledMessageReceived(m);
+		}
+
+		void processOFFeaturesReply(OFFeaturesReply  m)
+				throws IOException {
+			// we only expect features reply in the WAIT_FEATURES_REPLY state
+			illegalMessageReceived(m);
+		}
+
+		private final boolean channelHandshakeComplete;
+
+		OFChannelState(boolean handshakeComplete) {
+			this.channelHandshakeComplete = handshakeComplete;
+		}
+
+		void logState() {
+			log.debug("{} OFConnection Handshake - enter state {}",
+					getConnectionInfoString(), this.getClass().getSimpleName());
+		}
+
+		/** enter this state. Can initialize the handler, send
+		 *  the necessary messages, etc.
+		 * @throws IOException
+		 */
+		void enterState() throws IOException{
+			// Do Nothing
+		}
+
+		/**
+		 * 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",
+					getConnectionInfoString(),
+					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) {
+			counters.unhandledMessage.increment();
+			if (log.isDebugEnabled()) {
+				String msg = getSwitchStateMessage(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(OFErrorMsg error) {
+			log.error("{} from switch {} in state {}",
+					new Object[] {
+					error.toString(),
+					getConnectionInfoString(),
+					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(OFErrorMsg error) {
+			logError(error);
+			channel.disconnect();
+		}
+
+		/**
+		 * 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)
+				throws IOException {
+			// Handle Channel Handshake
+			if (!state.channelHandshakeComplete) {
+				switch(m.getType()) {
+				case HELLO:
+					processOFHello((OFHello)m);
+					break;
+				case ERROR:
+					processOFError((OFErrorMsg)m);
+					break;
+				case FEATURES_REPLY:
+					processOFFeaturesReply((OFFeaturesReply)m);
+					break;
+				case EXPERIMENTER:
+					processOFExperimenter((OFExperimenter)m);
+					break;
+				default:
+					illegalMessageReceived(m);
+					break;
+				}
+			}
+			else{
+				switch(m.getType()){
+				// Always handle echos at the channel level!
+				// Echos should only be sent in the complete.
+				case ECHO_REPLY:
+					processOFEchoReply((OFEchoReply)m);
+					break;
+				case ECHO_REQUEST:
+					processOFEchoRequest((OFEchoRequest)m);
+					break;
+					// Send to SwitchManager and thus higher orders of control
+				default:
+					sendMessageToConnection(m);
+					break;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Initial state before channel is connected.
+	 */
+	class InitState extends OFChannelState {
+
+		InitState() {
+			super(false);
+		}
+	}
+
+	/**
+	 * We send a HELLO to the switch and wait for a reply.
+	 * Once we receive the reply we send an OFFeaturesRequest
+	 * Next state is WaitFeaturesReplyState
+	 */
+	class WaitHelloState extends OFChannelState {
+
+		WaitHelloState() {
+			super(false);
+		}
+
+		@Override
+		void processOFHello(OFHello m) throws IOException {
+			OFVersion version = m.getVersion();
+			factory = OFFactories.getFactory(version);
+			OFMessageDecoder decoder = pipeline.get(OFMessageDecoder.class);
+			decoder.setVersion(version);
+			setState(new WaitFeaturesReplyState());
+		}
+
+		@Override
+		void enterState() throws IOException {
+			sendHelloMessage();
+		}
+	}
+
+	/**
+	 * We are waiting for a features reply message. Once we receive it
+	 * we send capture the features reply.
+	 * Next state is CompleteState
+	 */
+	class WaitFeaturesReplyState extends OFChannelState{
+
+		WaitFeaturesReplyState() {
+			super(false);
+		}
+		@Override
+		void processOFFeaturesReply(OFFeaturesReply  m)
+				throws IOException {
+			featuresReply = m;
+
+			// Mark handshake as completed
+			setState(new CompleteState());
+
+		}
+		@Override
+		void enterState() throws IOException {
+			sendFeaturesRequest();
+		}
+	};
+
+	/**
+	 * This state denotes that the channel handshaking is complete.
+	 * An OF connection is generated and passed to the switch manager
+	 * for handling.
+	 */
+	class CompleteState extends OFChannelState{
+
+		CompleteState() {
+			super(true);
+		}
+
+		@Override
+		void enterState() throws IOException{
+
+			setSwitchHandshakeTimeout();
+
+			// Handle non 1.3 connections
+			if(featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0){
+				connection = new OFConnection(featuresReply.getDatapathId(), factory, channel, OFAuxId.MAIN, debugCounters, timer);
+			}
+			// Handle 1.3 connections
+			else{
+				connection = new OFConnection(featuresReply.getDatapathId(), factory, channel, featuresReply.getAuxiliaryId(), debugCounters, timer);
+
+				// If this is an aux connection, we set a longer echo idle time
+				if (!featuresReply.getAuxiliaryId().equals(OFAuxId.MAIN)) {
+					setAuxChannelIdle();
+				}
+			}
+			// Notify the connection broker
+			notifyConnectionOpened(connection);
+
+		}
+	};
+
+	/**
+	 * Creates a handler for interacting with the switch channel
+	 *
+	 * @param controller
+	 *            the controller
+	 * @param newConnectionListener
+	 *            the class that listens for new OF connections (switchManager)
+	 * @param pipeline
+	 *            the channel pipeline
+	 * @param threadPool
+	 *            the thread pool
+	 * @param idleTimer
+	 *            the hash wheeled timer used to send idle messages (echo).
+	 *            passed to constructor to modify in case of aux connection.
+	 * @param debugCounters
+	 */
+	OFChannelHandler(@Nonnull IOFSwitchManager switchManager,
+			@Nonnull INewOFConnectionListener newConnectionListener,
+			@Nonnull ChannelPipeline pipeline,
+			@Nonnull IDebugCounterService debugCounters,
+			@Nonnull Timer timer) {
+
+		Preconditions.checkNotNull(switchManager, "switchManager");
+		Preconditions.checkNotNull(newConnectionListener, "connectionOpenedListener");
+		Preconditions.checkNotNull(pipeline, "pipeline");
+		Preconditions.checkNotNull(timer, "timer");
+		Preconditions.checkNotNull(debugCounters, "debugCounters");
+
+		this.pipeline = pipeline;
+		this.debugCounters = debugCounters;
+		this.newConnectionListener = newConnectionListener;
+		this.counters = switchManager.getCounters();
+		this.state = new InitState();
+		this.timer = timer;
+
+		log.debug("constructor on OFChannelHandler {}", String.format("%08x", System.identityHashCode(this)));
+	}
+
+	/**
+	 * Determines if the entire switch handshake is complete (channel+switch).
+	 * If the channel handshake is complete the call is forwarded to the
+	 * connection listener/switch manager to be handled by the appropriate
+	 * switch handshake handler.
+	 *
+	 * @return whether or not complete switch handshake is complete
+	 */
+	public boolean isSwitchHandshakeComplete() {
+		if (this.state.channelHandshakeComplete) {
+			return connection.getListener().isSwitchHandshakeComplete(connection);
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * Notifies the channel listener that we have a valid baseline connection
+	 */
+	private final void notifyConnectionOpened(OFConnection connection){
+		this.connection = connection;
+		this.newConnectionListener.connectionOpened(connection, featuresReply);
+	}
+
+	/**
+	 * Notifies the channel listener that we our connection has been closed
+	 */
+	private final void notifyConnectionClosed(OFConnection connection){
+		connection.getListener().connectionClosed(connection);
+	}
+
+	/**
+	 * Notifies the channel listener that we have a valid baseline connection
+	 */
+	private final void sendMessageToConnection(OFMessage m) {
+		connection.messageReceived(m);
+	}
+
+	@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 {
+		log.debug("channelConnected on OFChannelHandler {}", String.format("%08x", System.identityHashCode(this)));
+		counters.switchConnected.increment();
+		channel = e.getChannel();
+		log.info("New switch connection from {}",
+				channel.getRemoteAddress());
+		setState(new WaitHelloState());
+	}
+
+	@Override
+	@LogMessageDoc(message="Disconnected switch {switch information}",
+	explanation="The specified switch has disconnected.")
+	public void channelDisconnected(ChannelHandlerContext ctx,
+			ChannelStateEvent e) throws Exception {
+		// Only handle cleanup connection is even known
+		if(this.connection != null){
+			// Alert the connection object that the channel has been disconnected
+			this.connection.disconnected();
+			// Punt the cleanup to the Switch Manager
+			notifyConnectionClosed(this.connection);
+		}
+		log.info("[{}] Disconnected connection", getConnectionInfoString());
+	}
+
+	@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) {
+
+			if (featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0) {
+				log.error("Disconnecting switch {} due to read timeout on main cxn.",
+						getConnectionInfoString());
+				ctx.getChannel().close();
+			} else {
+				if (featuresReply.getAuxiliaryId().equals(OFAuxId.MAIN)) {
+					log.error("Disconnecting switch {} due to read timeout on main cxn.",
+							getConnectionInfoString());
+					ctx.getChannel().close();
+				} else {
+					// We only don't disconnect on aux connections
+					log.warn("Switch {} encountered read timeout on aux cxn.",
+							getConnectionInfoString());
+				}
+			}
+			// Increment counters
+			counters.switchDisconnectReadTimeout.increment();
+
+		} else if (e.getCause() instanceof HandshakeTimeoutException) {
+			log.error("Disconnecting switch {}: failed to complete handshake. Channel handshake complete : {}",
+					getConnectionInfoString(),
+					this.state.channelHandshakeComplete);
+			counters.switchDisconnectHandshakeTimeout.increment();
+			ctx.getChannel().close();
+		} else if (e.getCause() instanceof ClosedChannelException) {
+			log.debug("Channel for sw {} already closed", getConnectionInfoString());
+		} else if (e.getCause() instanceof IOException) {
+			log.error("Disconnecting switch {} due to IO Error: {}",
+					getConnectionInfoString(), e.getCause().getMessage());
+			if (log.isDebugEnabled()) {
+				// still print stack trace if debug is enabled
+				log.debug("StackTrace for previous Exception: ", e.getCause());
+			}
+			counters.switchDisconnectIOError.increment();
+			ctx.getChannel().close();
+		} else if (e.getCause() instanceof SwitchStateException) {
+			log.error("Disconnecting switch {} due to switch state error: {}",
+					getConnectionInfoString(), e.getCause().getMessage());
+			if (log.isDebugEnabled()) {
+				// still print stack trace if debug is enabled
+				log.debug("StackTrace for previous Exception: ", e.getCause());
+			}
+			counters.switchDisconnectSwitchStateException.increment();
+			ctx.getChannel().close();
+		} else if (e.getCause() instanceof OFAuxException) {
+			log.error("Disconnecting switch {} due to OF Aux error: {}",
+					getConnectionInfoString(), e.getCause().getMessage());
+			if (log.isDebugEnabled()) {
+				// still print stack trace if debug is enabled
+				log.debug("StackTrace for previous Exception: ", e.getCause());
+			}
+			counters.switchDisconnectSwitchStateException.increment();
+			ctx.getChannel().close();
+		} else if (e.getCause() instanceof OFParseError) {
+			log.error("Disconnecting switch "
+					+ getConnectionInfoString() +
+					" due to message parse failure",
+					e.getCause());
+			counters.switchDisconnectParseError.increment();
+			ctx.getChannel().close();
+		} else if (e.getCause() instanceof RejectedExecutionException) {
+			log.warn("Could not process message: queue full");
+			counters.rejectedExecutionException.increment();
+		} else {
+			log.error("Error while processing message from switch "
+					+ getConnectionInfoString()
+					+ "state " + this.state, e.getCause());
+			counters.switchDisconnectOtherException.increment();
+			ctx.getChannel().close();
+		}
+	}
+
+	@Override
+	public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
+			throws Exception {
+
+		log.debug("channelIdle on OFChannelHandler {}", String.format("%08x", System.identityHashCode(this)));
+		OFChannelHandler handler = ctx.getPipeline().get(OFChannelHandler.class);
+		handler.sendEchoRequest();
+	}
+
+	@Override
+	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
+			throws Exception {
+		if (e.getMessage() instanceof List) {
+			@SuppressWarnings("unchecked")
+			List<OFMessage> msglist = (List<OFMessage>)e.getMessage();
+			for (OFMessage ofm : msglist) {
+				try {
+					// Do the actual packet processing
+					state.processOFMessage(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);
+				}
+			}
+		}
+		else {
+			Channels.fireExceptionCaught(ctx.getChannel(),
+					new AssertionError("Message received from channel is not a list"));
+		}
+	}
+
+	/**
+	 * Sets the channel pipeline's idle (Echo) timeouts to a longer interval.
+	 * This is specifically for aux channels.
+	 */
+	private void setAuxChannelIdle() {
+
+		IdleStateHandler idleHandler = new IdleStateHandler(
+				this.timer,
+				PipelineIdleReadTimeout.AUX,
+				PipelineIdleWriteTimeout.AUX,
+				0);
+		pipeline.replace(PipelineHandler.MAIN_IDLE,
+				PipelineHandler.AUX_IDLE,
+				idleHandler);
+	}
+
+	/**
+	 * Sets the channel pipeline's handshake timeout to a more appropriate value
+	 * for the remaining part of the switch handshake.
+	 */
+	private void setSwitchHandshakeTimeout() {
+
+		HandshakeTimeoutHandler handler = new HandshakeTimeoutHandler(
+				this,
+				this.timer,
+				PipelineHandshakeTimeout.SWITCH);
+
+		pipeline.replace(PipelineHandler.CHANNEL_HANDSHAKE_TIMEOUT,
+				PipelineHandler.SWITCH_HANDSHAKE_TIMEOUT, handler);
+	}
+
+	/**
+	 * Return a string describing this switch based on the already available
+	 * information (DPID and/or remote socket)
+	 * @return
+	 */
+	private String getConnectionInfoString() {
+
+		String channelString;
+		if (channel == null || channel.getRemoteAddress() == null) {
+			channelString = "?";
+		} else {
+			channelString = channel.getRemoteAddress().toString();
+			if(channelString.startsWith("/"))
+				channelString = channelString.substring(1);
+		}
+		String dpidString;
+		if (featuresReply == null) {
+			dpidString = "?";
+		} else {
+			StringBuilder b = new StringBuilder();
+			b.append(featuresReply.getDatapathId());
+			if(featuresReply.getVersion().compareTo(OFVersion.OF_13) >= 0) {
+				b.append("(").append(featuresReply.getAuxiliaryId()).append(")");
+			}
+			dpidString = b.toString();
+		}
+		return String.format("[%s from %s]", dpidString, channelString );
+	}
+
+	/**
+	 * Update the channels state. Only called from the state machine.
+	 * @param state
+	 * @throws IOException
+	 */
+	private void setState(OFChannelState state) throws IOException {
+		this.state = state;
+		state.logState();
+		state.enterState();
+	}
+
+	/**
+	 * Send a features request message to the switch using the handshake
+	 * transactions ids.
+	 * @throws IOException
+	 */
+	private void sendFeaturesRequest() throws IOException {
+		// Send initial Features Request
+		OFFeaturesRequest m = factory.buildFeaturesRequest()
+				.setXid(handshakeTransactionIds--)
+				.build();
+		channel.write(Collections.singletonList(m));
+	}
+
+	/**
+	 * Send a hello message to the switch using the handshake transactions ids.
+	 * @throws IOException
+	 */
+	private void sendHelloMessage() throws IOException {
+		// Send initial hello message
+		// FIXME:LOJI: Haven't negotiated version yet, assume 1.3
+		OFHello.Builder builder = factory.buildHello()
+				.setXid(handshakeTransactionIds--);
+		// FIXME: Need to add code here to set the version bitmap hello element
+		OFHello m = builder.build();
+		channel.write(Collections.singletonList(m));
+		log.debug("Send hello: {}", m);
+	}
+
+	private void sendEchoRequest() {
+		OFEchoRequest request = factory.buildEchoRequest()
+				.setXid(handshakeTransactionIds--)
+				.build();
+		channel.write(Collections.singletonList(request));
+	}
+
+	private void sendEchoReply(OFEchoRequest request) {
+		OFEchoReply reply = factory.buildEchoReply()
+				.setXid(request.getXid())
+				.setData(request.getData())
+				.build();
+		channel.write(Collections.singletonList(reply));
+	}
+
+	OFChannelState getStateForTesting() {
+		return state;
+	}
+
+	IOFConnectionBackend getConnectionForTesting() {
+		return connection;
+	}
+
+	ChannelPipeline getPipelineForTesting() {
+		return this.pipeline;
+	}
+
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java b/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java
deleted file mode 100644
index eca67bd97ca289fa5246edbb4196d9f0216e98c5..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- *    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
index 25edf396c943dfce728f79610910162ebd608a12..12faa3be6b49a43d70a8d8fbffec769184524b77 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.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
@@ -17,44 +17,65 @@
 
 package net.floodlightcontroller.core.internal;
 
+import java.util.ArrayList;
 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;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFMessageReader;
+import org.projectfloodlight.openflow.protocol.OFVersion;
 
 /**
- * Decode an openflow message from a Channel, for use in a netty
- * pipeline
+ * Decode an openflow message from a channel, for use in a netty pipeline.
+ *
  * @author readams
  */
 public class OFMessageDecoder extends FrameDecoder {
 
-    OFMessageFactory factory = BasicFactory.getInstance();
-    
+    private OFMessageReader<OFMessage> reader;
+
+    public OFMessageDecoder() {
+        reader = OFFactories.getGenericReader();
+    }
+
+    public OFMessageDecoder(OFVersion version) {
+        setVersion(version);
+    }
+
+    public void setVersion(OFVersion version) {
+        OFFactory factory = OFFactories.getFactory(version);
+        this.reader = factory.getReader();
+    }
+
     @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
+            // This check avoids that from reading corrupted frames
             return null;
         }
 
-        List<OFMessage> message = factory.parseMessage(buffer);
-        return message;
+        List<OFMessage> messageList = new ArrayList<OFMessage>();
+        for (;;) {
+            OFMessage message = reader.readFrom(buffer);
+            if (message == null)
+                break;
+            messageList.add(message);
+        }
+        return messageList.isEmpty() ? null : messageList;
     }
 
     @Override
     protected Object decodeLast(ChannelHandlerContext ctx, Channel channel,
                             ChannelBuffer buffer) throws Exception {
-        // This is not strictly needed atthis time. It is used to detect
+        // This is not strictly needed at this 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
index 6be5f9a1d524b51e85af216f70d9a4800aed0ad6..4d6912ad69a9246da975063127fca3b8d97fe0b0 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.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
@@ -17,14 +17,12 @@
 
 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;
+import org.projectfloodlight.openflow.protocol.OFMessage;
 
 /**
  * Encode an openflow message for output into a ChannelBuffer, for use in a
@@ -36,21 +34,16 @@ public class OFMessageEncoder extends OneToOneEncoder {
     @Override
     protected Object encode(ChannelHandlerContext ctx, Channel channel,
                             Object msg) throws Exception {
-        if (!(  msg instanceof List))
+        if (!(msg instanceof Iterable))
             return msg;
 
         @SuppressWarnings("unchecked")
-        List<OFMessage> msglist = (List<OFMessage>)msg;
-        int size = 0;
-        for (OFMessage ofm :  msglist) {
-                size += ofm.getLengthU();
-        }
+        Iterable<OFMessage> msgList = (Iterable<OFMessage>)msg;
 
-        ChannelBuffer buf = ChannelBuffers.buffer(size);;
-        for (OFMessage ofm :  msglist) {
+        ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
+        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
deleted file mode 100644
index 1fc9c135330d6189652fca4b37aac903bce5bf0d..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/OFMessageFuture.java
+++ /dev/null
@@ -1,171 +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.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
deleted file mode 100644
index 4d3f733a6ed1d3e6b7dbba272643680877f9e982..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/OFStatisticsFuture.java
+++ /dev/null
@@ -1,80 +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.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
new file mode 100644
index 0000000000000000000000000000000000000000..ddfd008720a6853262905afeb7072cf91c99c3f5
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchAppHandshakePlugin.java
@@ -0,0 +1,116 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..5acd44059d5a4bb5a2486e3923143f6cf7ad91b0
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandler.java
@@ -0,0 +1,1566 @@
+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.TimeUnit;
+
+import javax.annotation.Nonnull;
+
+import org.jboss.netty.util.Timer;
+
+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.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.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) {
+			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);
+			}
+		}
+
+		/**
+		 * 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);
+		}
+	}
+
+	/**
+	 * 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) {
+			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);
+
+			sw.startDriverHandshake();
+			if (sw.isDriverHandshakeComplete()) {
+				setState(new WaitAppHandshakeState());
+			} else {
+				setState(new WaitSwitchDriverSubHandshakeState());
+			}
+		}
+
+		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();
+		}
+	}
+
+	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{
+				setState(new WaitInitialRoleState());
+			}
+		}
+
+		@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;
+		}
+	}
+
+	/**
+	 * 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 {
+				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 {
+				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 {
+				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(s) for switch {}", this.featuresReply.getNTables(),
+					getSwitchInfoString());
+		}
+
+		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();
+	}
+
+	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);
+	}
+
+	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());
+
+		// Handle new Auxiliary connections if the main connection has completed (i.e. in ACTIVE or STANDBY state)
+		if (this.getState().equals("ACTIVE") || this.getState().equals("STANDBY")) {
+			auxConnections.put(connection.getAuxId(), connection);
+			connection.setListener(OFSwitchHandshakeHandler.this);
+			log.info("Auxiliary connection {} added for {}.", connection.getAuxId().getValue(), connection.getDatapathId().toString());
+		} else {
+			log.info("Auxiliary connection {} initiated for {} before main connection handshake complete. Ignorning aux connection attempt.", connection.getAuxId().getValue(), connection.getDatapathId().toString());
+		}
+	}
+
+	/**
+	 * 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) {
+				log.debug("[{}] SwitchStatus change to {} requested, switch is in status " + oldStatus,
+						mainConnection.getDatapathId(), status);
+				sw.setStatus(status);
+				switchManager.switchStatusChanged(sw, oldStatus, status);
+			} else {
+				log.warn("[{}] SwitchStatus change to {} requested, switch is already in status",
+						mainConnection.getDatapathId(), status);
+			}
+		} else {
+			log.warn("[{}] SwitchStatus change to {} requested, but switch is not allocated yet",
+					mainConnection.getDatapathId(), status);
+		}
+	}
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
deleted file mode 100644
index 51dfddc1a1625f530610f7ab00d407d57c9a9e70..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ /dev/null
@@ -1,46 +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.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
new file mode 100644
index 0000000000000000000000000000000000000000..b62c6241cde68226d6ef6ecb18faa281a18334eb
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchManager.java
@@ -0,0 +1,867 @@
+package net.floodlightcontroller.core.internal;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+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.SwitchSyncRepresentation;
+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.sdnplatform.sync.IStoreClient;
+import org.sdnplatform.sync.IStoreListener;
+import org.sdnplatform.sync.ISyncService;
+import org.sdnplatform.sync.Versioned;
+import org.sdnplatform.sync.error.SyncException;
+import org.sdnplatform.sync.error.UnknownStoreException;
+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, IStoreListener<DatapathId> {
+	private static final Logger log = LoggerFactory.getLogger(OFSwitchManager.class);
+
+	private volatile OFControllerRole role;
+	private SwitchManagerCounters counters;
+
+	private ISyncService syncService;
+	private IStoreClient<DatapathId, SwitchSyncRepresentation> storeClient;
+	public static final String SWITCH_SYNC_STORE_NAME = OFSwitchManager.class.getCanonicalName() + ".stateStore";
+
+
+	private ConcurrentHashMap<DatapathId, OFSwitchHandshakeHandler> switchHandlers;
+	private ConcurrentHashMap<DatapathId, IOFSwitchBackend> switches;
+    private ConcurrentHashMap<DatapathId, IOFSwitch> syncedSwitches;
+
+
+	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.debug("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);
+		l.add(ISyncService.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);
+		syncService = context.getServiceImpl(ISyncService.class);
+
+		// Module variables
+		switchHandlers = new ConcurrentHashMap<DatapathId, OFSwitchHandshakeHandler>();
+		switches = new ConcurrentHashMap<DatapathId, IOFSwitchBackend>();
+        syncedSwitches = new ConcurrentHashMap<DatapathId, IOFSwitch>();
+		floodlightProvider.getTimer();
+		counters = new SwitchManagerCounters(debugCounterService);
+		driverRegistry = new NaiveSwitchDriverRegistry(this);
+
+		this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
+
+		this.counters = new SwitchManagerCounters(debugCounterService);
+		/* TODO @Ryan
+		try {
+			this.storeClient = this.syncService.getStoreClient(
+					SWITCH_SYNC_STORE_NAME,
+					DatapathId.class,
+					SwitchSyncRepresentation.class);
+			this.storeClient.addStoreListener(this);
+		} catch (UnknownStoreException e) {
+			throw new FloodlightModuleException("Error while setting up sync store client", e);
+		} */
+
+	}
+
+	@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() {
+		return null;
+	}
+
+	@Override
+	public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type, String name) {
+		return false;
+	}
+
+	@Override
+	public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type, String name) {
+		return false;
+	}
+
+	@Override
+	public void controllerNodeIPsChanged(Map<String, String> curControllerNodeIPs,
+			Map<String, String> addedControllerNodeIPs,
+			Map<String, String> removedControllerNodeIPs) {		
+	}
+
+	@Override
+	public void keysModified(Iterator<DatapathId> keys, UpdateType type) {
+		if (type == UpdateType.LOCAL) {
+			// We only care for remote updates
+			return;
+		}
+		while(keys.hasNext()) {
+			DatapathId key = keys.next();
+			Versioned<SwitchSyncRepresentation> versionedSwitch = null;
+			try {
+				versionedSwitch = storeClient.get(key);
+			} catch (SyncException e) {
+				log.error("Exception while retrieving switch " + key.toString() +
+						" 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 = getSwitch(storedSwitch.getDpid());
+			//TODO @Ryan need to get IOFSwitchBackend setFeaturesReply(storedSwitch.getFeaturesReply(sw.getOFFactory()));
+			if (!key.equals(storedSwitch.getFeaturesReply(sw.getOFFactory()).getDatapathId())) {
+				log.error("Inconsistent DPIDs from switch sync store: " +
+						"key is {} but sw.getId() says {}. Ignoring",
+						key.toString(), sw.getId());
+				continue;
+			}
+			switchAddedToStore(sw);
+		}
+	}
+	
+	/**
+     * Called when we receive a store notification about a switch that
+     * has been removed from the sync store
+     * @param dpid
+     */
+    private synchronized void switchRemovedFromStore(DatapathId dpid) {
+        if (floodlightProvider.getRole() != HARole.STANDBY) {
+            return; // only read from store if slave
+        }
+        IOFSwitch oldSw = syncedSwitches.remove(dpid);
+        if (oldSw != null) {
+            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?
+        }
+    }
+    
+    /**
+     * Called when we receive a store notification about a new or updated
+     * switch.
+     * @param sw
+     */
+    private synchronized void switchAddedToStore(IOFSwitch sw) {
+        if (floodlightProvider.getRole() != HARole.STANDBY) {
+            return; // only read from store if slave
+        }
+        DatapathId dpid = sw.getId();
+
+        IOFSwitch oldSw = syncedSwitches.put(dpid, sw);
+        if (oldSw == null)  {
+            addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.ADDED));
+        } else {
+            // The switch already exists in storage, see if anything
+            // has changed
+            sendNotificationsIfSwitchDiffers(oldSw, sw);
+        }
+    }
+
+    /**
+     * 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) {
+        /*TODO @Ryan 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);
+        }*/
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java b/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java
index 82a3c67d658ddee3b20f702f2019117a044ccb4b..23f3f01413dbf4926f431ae7ce113f11ef39310f 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.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
@@ -17,61 +17,106 @@
 
 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;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
 
 /**
  * Creates a ChannelPipeline for a server-side openflow channel
- * @author readams
+ * @author readams, sovietaced
  */
-public class OpenflowPipelineFactory 
+public class OpenflowPipelineFactory
     implements ChannelPipelineFactory, ExternalResourceReleasable {
 
-    protected Controller controller;
-    protected ThreadPoolExecutor pipelineExecutor;
+    protected IOFSwitchManager switchManager;
+    protected INewOFConnectionListener connectionListener;
     protected Timer timer;
     protected IdleStateHandler idleHandler;
     protected ReadTimeoutHandler readTimeoutHandler;
-    
-    public OpenflowPipelineFactory(Controller controller,
-                                   ThreadPoolExecutor pipelineExecutor) {
+    protected IDebugCounterService debugCounters;
+
+    public OpenflowPipelineFactory(IOFSwitchManager switchManager, Timer timer,
+                                   INewOFConnectionListener connectionListener,
+                                  IDebugCounterService debugCounters) {
         super();
-        this.controller = controller;
-        this.pipelineExecutor = pipelineExecutor;
-        this.timer = new HashedWheelTimer();
-        this.idleHandler = new IdleStateHandler(timer, 20, 25, 0);
+        this.switchManager = switchManager;
+        this.connectionListener = connectionListener;
+        this.timer = timer;
+        this.debugCounters = debugCounters;
+        this.idleHandler = new IdleStateHandler(
+                                                timer,
+                                                PipelineIdleReadTimeout.MAIN,
+                                                PipelineIdleWriteTimeout.MAIN,
+                                                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);
+        OFChannelHandler handler = new OFChannelHandler(switchManager,
+                                                        connectionListener,
+                                                        pipeline,
+                                                        debugCounters,
+                                                        timer);
+
+        pipeline.addLast(PipelineHandler.OF_MESSAGE_DECODER,
+                         new OFMessageDecoder());
+        pipeline.addLast(PipelineHandler.OF_MESSAGE_ENCODER,
+                         new OFMessageEncoder());
+        pipeline.addLast(PipelineHandler.MAIN_IDLE, idleHandler);
+        pipeline.addLast(PipelineHandler.READ_TIMEOUT, readTimeoutHandler);
+        pipeline.addLast(PipelineHandler.CHANNEL_HANDSHAKE_TIMEOUT,
+                         new HandshakeTimeoutHandler(
+                                                     handler,
+                                                     timer,
+                                                     PipelineHandshakeTimeout.CHANNEL));
+        pipeline.addLast(PipelineHandler.CHANNEL_HANDLER, handler);
         return pipeline;
     }
 
     @Override
     public void releaseExternalResources() {
-        timer.stop();        
+        timer.stop();
+    }
+
+    public static class PipelineHandler {
+        final static String CHANNEL_HANDSHAKE_TIMEOUT = "channelhandshaketimeout";
+        final static String SWITCH_HANDSHAKE_TIMEOUT = "switchhandshaketimeout";
+        final static String CHANNEL_HANDLER = "channelhandler";
+        final static String MAIN_IDLE = "mainidle";
+        final static String AUX_IDLE = "auxidle";
+        final static String OF_MESSAGE_DECODER = "ofmessagedecoder";
+        final static String OF_MESSAGE_ENCODER = "ofmessageencoder";
+        final static String READ_TIMEOUT = "readtimeout";
+    }
+
+    /**
+     * Timeouts for parts of the handshake, in seconds
+     */
+    public static class PipelineHandshakeTimeout {
+        final static int CHANNEL = 10;
+        final static int SWITCH = 30;
+    }
+
+    /**
+     * Timeouts for writes on connections, in seconds
+     */
+    public static class PipelineIdleWriteTimeout {
+        final static int MAIN = 2;
+        final static int AUX = 15;
+    }
+
+    /**
+     * Timeouts for reads on connections, in seconds
+     */
+    public static class PipelineIdleReadTimeout {
+        final static int MAIN = 3 * PipelineIdleWriteTimeout.MAIN;
+        final static int AUX = 3 * PipelineIdleWriteTimeout.AUX;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/PluginResult.java b/src/main/java/net/floodlightcontroller/core/internal/PluginResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..e11a527de0a4df91c500bfd5e421fae6c9dd94c9
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/PluginResult.java
@@ -0,0 +1,40 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..92a106307f6c85b4a7e3b322826f1258d893f677
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/RoleManager.java
@@ -0,0 +1,254 @@
+package net.floodlightcontroller.core.internal;
+
+import java.util.Map.Entry;
+
+import javax.annotation.Nonnull;
+
+import java.util.Date;
+import net.floodlightcontroller.core.HARole;
+import net.floodlightcontroller.core.IHAListener;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitchBackend;
+import net.floodlightcontroller.core.IShutdownService;
+import net.floodlightcontroller.core.RoleInfo;
+import net.floodlightcontroller.core.internal.Controller.IUpdate;
+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;
+
+/**
+ * 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 IShutdownService shutdownService;
+    private final RoleManagerCounters counters;
+
+    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 IShutdownService shutdownService,
+            @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");
+        Preconditions.checkNotNull(shutdownService, "shutdownService must not be null");
+
+        this.currentRoleInfo = new RoleInfo(role,
+                                       roleChangeDescription,
+                                       new Date());
+        this.controller = controller;
+        this.shutdownService = shutdownService;
+        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");
+         }
+     }
+
+    /**
+     * 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(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());
+               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
new file mode 100644
index 0000000000000000000000000000000000000000..04d948339ecedc0c487a57384481f155591eb328
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/RoleManagerCounters.java
@@ -0,0 +1,32 @@
+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/ShutdownServiceImpl.java b/src/main/java/net/floodlightcontroller/core/internal/ShutdownServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c1c8c6d25b28fd4bf5c3fb9c0e85399bd95ce6c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/ShutdownServiceImpl.java
@@ -0,0 +1,170 @@
+package net.floodlightcontroller.core.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.floodlightcontroller.core.IShutdownListener;
+import net.floodlightcontroller.core.IShutdownService;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+public class ShutdownServiceImpl implements IFloodlightModule,
+    IShutdownService {
+    private static final Logger logger =
+            LoggerFactory.getLogger(ShutdownServiceImpl.class);
+
+    /** Maximum amount of time for IShutdownListeners to complete before
+     * floodlight terminates in any case
+     */
+    private static final int MAX_SHUTDOWN_WAIT_MS = 5_000;
+
+    private final CopyOnWriteArrayList<IShutdownListener> shutdownListeners =
+            new CopyOnWriteArrayList<>();
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l =
+                new ArrayList<>();
+        l.add(IShutdownService.class);
+        return l;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService>
+    getServiceImpls() {
+        Map<Class<? extends IFloodlightService>, IFloodlightService> m =
+                new HashMap<>();
+        m.put(IShutdownService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+    getModuleDependencies() {
+        return new ArrayList<>();
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+        // do nothing
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+        // do nothing
+    }
+
+    @Override
+    public void registerShutdownListener(@Nonnull IShutdownListener listener) {
+        if (listener == null) {
+            throw new NullPointerException("listener must not be null");
+        }
+        shutdownListeners.add(listener);
+    }
+
+    @SuppressFBWarnings(value="DM_EXIT", justification="exit by design")
+    @Override
+    public void terminate(@Nullable final String reason, final int exitCode) {
+        final String paddedReason;
+        if (reason == null) {
+            paddedReason = "";
+        } else {
+            paddedReason = " due to " + reason;
+        }
+        // A safety valve to make sure we really do indeed terminate floodlight
+        // We are using a Thread rather than a task to make sure nothing can
+        // cancel the shutdown (e.g., if an ExecutorService was already
+        // shutdown
+        Thread shutdownForHungListeners =  new Thread(new Runnable() {
+            // Suppress findbugs warning that we call system.exit
+            @SuppressFBWarnings(value="DM_EXIT", justification="exit by design")
+            @Override
+            public void run() {
+                try {
+                    Thread.sleep(MAX_SHUTDOWN_WAIT_MS);
+                } catch (InterruptedException e) {
+                    // do nothing, we are about to exit anyways
+                }
+                logger.error("**************************************************");
+                logger.error("* Floodlight is terminating {}", paddedReason);
+                logger.error("* ShutdownListeners failed to complete in time");
+                logger.error("**************************************************");
+                System.exit(exitCode);
+            }
+        }, "ShutdownSafetyValve");
+        shutdownForHungListeners.start();
+        logger.info("Floodlight about to terminate. Calling shutdown listeners");
+        for (IShutdownListener listener: shutdownListeners) {
+            listener.floodlightIsShuttingDown();
+        }
+        if (exitCode == 0) {
+            logger.info("**************************************************");
+            logger.info("* Floodlight is terminating normally{}", paddedReason);
+            logger.info("**************************************************");
+        } else {
+            logger.error("**************************************************");
+            logger.error("* Floodlight is terminating abnormally{}", paddedReason);
+            logger.error("**************************************************");
+        }
+        // Game Over.
+        System.exit(exitCode);
+    }
+
+    @SuppressFBWarnings(value="DM_EXIT", justification="exit by design")
+    @Override
+    public void terminate(final String reason, final Throwable e, final int exitCode) {
+        final String paddedReason;
+        if (reason == null) {
+            paddedReason = "";
+        } else {
+            paddedReason = " due to " + reason;
+        }
+        // A safety valve to make sure we really do indeed terminate floodlight
+        // We are using a Thread rather than a task to make sure nothing can
+        // cancel the shutdown (e.g., if an ExecutorService was already
+        // shutdown
+        Thread shutdownForHungListeners =  new Thread(new Runnable() {
+            // Suppress findbugs warning that we call system.exit
+            @SuppressFBWarnings(value="DM_EXIT", justification="exit by design")
+            @Override
+            public void run() {
+                try {
+                    Thread.sleep(MAX_SHUTDOWN_WAIT_MS);
+                } catch (InterruptedException e) {
+                    // do nothing, we are about to exit anyways
+                }
+                logger.error("**************************************************");
+                logger.error("Floodlight is terminating{}", paddedReason, e);
+                logger.error("ShutdownListeners failed to complete in time");
+                logger.error("**************************************************");
+                System.exit(exitCode);
+            }
+        }, "ShutdownSafetyValve");
+        shutdownForHungListeners.start();
+        logger.info("Floodlight about to terminate. Calling shutdown listeners");
+        for (IShutdownListener listener: shutdownListeners) {
+            listener.floodlightIsShuttingDown();
+        }
+        logger.error("**************************************************");
+        logger.error("Floodlight is terminating abnormally{}", paddedReason, e);
+        logger.error("**************************************************");
+        // Game Over.
+        System.exit(exitCode);
+
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/SwitchEvent.java b/src/main/java/net/floodlightcontroller/core/internal/SwitchEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a4f36b37cc54e5c9c5d7698ffc04b9ac7adba2d
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/SwitchEvent.java
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..942809cd45d4a060c865a9355442830e713ae318
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/SwitchManagerCounters.java
@@ -0,0 +1,208 @@
+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
deleted file mode 100644
index f56dfa996e90f9550a09fb3ae817ed4685431046..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/module/ApplicationLoader.java
+++ /dev/null
@@ -1,179 +0,0 @@
-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
new file mode 100644
index 0000000000000000000000000000000000000000..e20d1e06f74d572590ca63d4660c799b4278a2fd
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleConfigFileNotFoundException.java
@@ -0,0 +1,10 @@
+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
index 27c1f968ac0534ecf1bfcd293ce471669016719e..9772ee4456693b7924865963f42c6f19897fa13e 100644
--- a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleContext.java
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleContext.java
@@ -16,7 +16,6 @@
 
 package net.floodlightcontroller.core.module;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
@@ -28,31 +27,33 @@ import java.util.Map;
 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;
+    private final FloodlightModuleLoader moduleLoader;
     
     /**
      * Creates the ModuleContext for use with this IFloodlightProvider.
      * This will be used as a module registry for all IFloodlightModule(s).
      */
-    public FloodlightModuleContext() {
+    public FloodlightModuleContext(FloodlightModuleLoader moduleLoader) {
         serviceMap = 
                 new HashMap<Class<? extends IFloodlightService>,
                                       IFloodlightService>();
         configParams =
                 new HashMap<Class<? extends IFloodlightModule>,
                                 Map<String, String>>();
+        this.moduleLoader = moduleLoader;
     }
-    
+
     /**
-     * Adds a IFloodlightModule for this Context.
-     * @param clazz the service class
-     * @param service The IFloodlightService to add to the registry
+     * Allocate a module context without a module loader; useful for testing
      */
-    public void addService(Class<? extends IFloodlightService> clazz, 
-                           IFloodlightService service) {
-        serviceMap.put(clazz, service);
+    public FloodlightModuleContext() {
+        this(null);
     }
-    
+
+    // ************************
+    // IFloodlightModuleContext
+    // ************************
+
     @SuppressWarnings("unchecked")
     @Override
     public <T extends IFloodlightService> T getServiceImpl(Class<T> service) {
@@ -64,17 +65,6 @@ public class FloodlightModuleContext implements IFloodlightModuleContext {
     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) {
@@ -106,7 +96,11 @@ public class FloodlightModuleContext implements IFloodlightModuleContext {
 
         return retMap;
     }
-    
+
+    // ***********************
+    // FloodlightModuleContext
+    // ***********************
+
     /**
      * Adds a configuration parameter for a module
      * @param mod The fully qualified module name to add the parameter to
@@ -121,4 +115,22 @@ public class FloodlightModuleContext implements IFloodlightModuleContext {
         }
         moduleParams.put(key, value);
     }
+
+    /**
+     * Get the module loader associated with this context
+     * @return the {@link FloodlightModuleLoader} object
+     */
+    public FloodlightModuleLoader getModuleLoader() {
+        return moduleLoader;
+    }
+    
+    /**
+     * 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);
+    }
  }
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleException.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleException.java
index 5cddd37fccb8564ae7e31b6f2418a2339ce354c7..c496911c25fa6da121c2dfcc516b0e5782c4506b 100644
--- a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleException.java
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleException.java
@@ -17,11 +17,11 @@
 package net.floodlightcontroller.core.module;
 
 public class FloodlightModuleException extends Exception {
-	private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = 1L;
 
-	public FloodlightModuleException(String error) {
-		super(error);
-	}
+    public FloodlightModuleException(String error) {
+        super(error);
+    }
 
     public FloodlightModuleException() {
         super();
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
index 32e4fc031e26eafee38bd282e0a1b21e0b73ebfb..ded7b6d34b0a952de765d4713a83cc13ddd81ff2 100644
--- a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
@@ -18,142 +18,185 @@ package net.floodlightcontroller.core.module;
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.List;
 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 net.floodlightcontroller.core.module.FloodlightModulePriority.Priority;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
 /**
  * Finds all Floodlight modules in the class path and loads/starts them.
  * @author alexreimers
  *
  */
-public class FloodlightModuleLoader implements IModuleService {
-    protected static Logger logger = 
+public class FloodlightModuleLoader {
+    protected static final Logger logger =
             LoggerFactory.getLogger(FloodlightModuleLoader.class);
 
-    protected static Map<Class<? extends IFloodlightService>,
+    private Map<Class<? extends IFloodlightService>,
                   Collection<IFloodlightModule>> serviceMap;
-    protected static Map<IFloodlightModule,
-                  Collection<Class<? extends 
+    private 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 = 
+    private Map<String, IFloodlightModule> moduleNameMap;
+    private List<IFloodlightModule> loadedModuleList;
+
+    private final FloodlightModuleContext floodlightModuleContext;
+
+    protected boolean startupModules;
+
+    private static URI configFile;
+
+    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);
+        loadedModuleList = Collections.emptyList();
+        floodlightModuleContext = new FloodlightModuleContext(this);
+        startupModules = true;
+    }
+
+    /**
+     * Gets the map of modules and their names.
+     * @return An UNMODIFIABLE map of the modules and their names.
+     */
+    public synchronized Map<String, IFloodlightModule> getModuleNameMap() {
+        if(moduleNameMap == null)
+            return ImmutableMap.of();
+        else
+            return Collections.unmodifiableMap(moduleNameMap);
+    }
+
+    /**
+     * Gets the list of modules in the order that they will be/were initialized
+     * @return An UNMODIFIABLE list of loaded modules, or null if
+     * not initialized.
+     */
+    public List<IFloodlightModule> getModuleList() {
+        if (loadedModuleList == null)
+            return Collections.emptyList();
+        else
+            return Collections.unmodifiableList(loadedModuleList);
+    }
+
+    /**
+     * Return the location of the config file that was used to initialize
+     * floodlight. If no config file was specified (i.e. floodlight was
+     * configured from the default resource), then the return value is null.
+     * @return location of the config file or null if no config file was
+     * specified
+     */
+    public static URI getConfigFileURI() {
+        return configFile;
     }
-    
+
     /**
      * 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.
+     * @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());
-                }
+    protected synchronized void findAllModules(Collection<String> mList)
+            throws FloodlightModuleException {
+        if (serviceMap != null)
+            return;
 
-                // 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);
+        serviceMap = new HashMap<>();
+        moduleServiceMap = new HashMap<>();
+        moduleNameMap = new HashMap<>();
+
+        // 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;
+            }
+            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) {
+                        StringBuilder sb = new StringBuilder();
+                        for (IFloodlightModule mod : mods) {
+                            sb.append(mod.getClass().getCanonicalName());
+                            sb.append(", ");
                         }
+                        String duplicateMods = sb.toString();
+                        String mess = "ERROR! The configuration 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;
+                        throw new FloodlightModuleException(mess);
                     }
                 }
             }
         }
     }
-    
+
     /**
      * Loads the modules from a specified configuration file.
      * @param fName The configuration file path
@@ -162,9 +205,10 @@ public class FloodlightModuleLoader implements IModuleService {
      */
     @LogMessageDocs({
         @LogMessageDoc(level="INFO",
-                message="Loading modules from file {file name}",
+                message="Loading modules from {file name}",
                 explanation="The controller is initializing its module " +
-                        "configuration from the specified properties file"),
+                        "configuration from the specified properties " +
+                        "file or directory"),
         @LogMessageDoc(level="INFO",
                 message="Loading default modules",
                 explanation="The controller is initializing its module " +
@@ -181,206 +225,217 @@ public class FloodlightModuleLoader implements IModuleService {
                         "module configuration",
                 recommendation=LogMessageDoc.CHECK_CONTROLLER)
     })
-    public IFloodlightModuleContext loadModulesFromConfig(String fName) 
+    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 {
+        Collection<String> configMods = new ArrayList<>();
+
+        if (fName == null) {
             logger.info("Loading default modules");
             InputStream is = this.getClass().getClassLoader().
                                     getResourceAsStream(COMPILED_CONF_FILE);
-            configMods = loadProperties(is, null, prop);
-        }
+            mergeProperties(is, null, configMods, prop);
+        } else {
+            File confFile = new File(fName);
+            if (! confFile.exists())
+                throw new FloodlightModuleConfigFileNotFoundException(fName);
+            logger.info("Loading modules from {}", confFile.getPath());
+            if (confFile.isFile()) {
+                mergeProperties(null, confFile,
+                                configMods, prop);
+            } else {
+                File[] files = confFile.listFiles();
+                Arrays.sort(files);
+                for (File f : files) {
+                    logger.debug("Loading conf.d file {}", f.getPath());
 
+                    if (f.isFile() &&
+                        f.getName().matches(".*\\.properties$")) {
+                        mergeProperties(null, f, configMods, prop);
+                    }
+                }
+            }
+        }
         return loadModulesFromList(configMods, prop);
     }
-    
-    private Collection<String> loadProperties(InputStream is, 
-                                              File confFile, 
-                                              Properties prop) {
+
+    private void mergeProperties(InputStream is,
+                                 File confFile,
+                                 Collection<String> configMods,
+                                 Properties prop)
+                                         throws FloodlightModuleException {
         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));
+                try (FileInputStream fis = new FileInputStream(confFile)) {
+                    fprop.load(fis);
                 }
             }
-        }
+            String moduleList = fprop.getProperty(FLOODLIGHT_MODULES_KEY);
+            if (moduleList != null) {
+                moduleList = moduleList.replaceAll("\\s", "");
+                configMods.addAll(Arrays.asList(moduleList.split(",")));
+            }
+            fprop.remove(FLOODLIGHT_MODULES_KEY);
 
-        return configMods;
+            prop.putAll(fprop);
+        } catch (IOException e) {
+            throw new FloodlightModuleException(e);
+        }
     }
-    
+
     /**
      * 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.
+     * @param configMods The fully-qualified module names
      * @return The ModuleContext containing all the loaded modules
      * @throws FloodlightModuleException
      */
-    protected IFloodlightModuleContext loadModulesFromList(Collection<String> configMods, Properties prop, 
-            Collection<IFloodlightService> ignoreList) throws FloodlightModuleException {
+    public synchronized IFloodlightModuleContext
+            loadModulesFromList(Collection<String> configMods,
+                                Properties prop)
+                                        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>();
+
+        ArrayList<IFloodlightModule> moduleList = new ArrayList<>();
         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;
+                new HashMap<>();
+        HashSet<String> modsVisited = new HashSet<>();
+
+        ArrayDeque<String> modsToLoad = new ArrayDeque<>(configMods);
+        while (!modsToLoad.isEmpty()) {
+            String moduleName = modsToLoad.removeFirst();
+            traverseDeps(moduleName, modsToLoad,
+                         moduleList, moduleMap, modsVisited);
+        }
+
+        parseConfigParameters(prop);
+
+        loadedModuleList = moduleList;
+
+        initModules(moduleList);
+        if(startupModules)
+            startupModules(moduleList);
+
+        return floodlightModuleContext;
+    }
+
+    private void traverseDeps(String moduleName,
+                              Collection<String> modsToLoad,
+                              ArrayList<IFloodlightModule> moduleList,
+                              Map<Class<? extends IFloodlightService>,
+                                  IFloodlightModule> moduleMap,
+                              Set<String> modsVisited)
+                                      throws FloodlightModuleException {
+        if (modsVisited.contains(moduleName)) return;
+        modsVisited.add(moduleName);
+        IFloodlightModule module = moduleNameMap.get(moduleName);
+        if (module == null) {
+            throw new FloodlightModuleException("Module " +
+                    moduleName + " not found");
+        }
+
+        // Add its dependencies to the stack
+        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();
+                        traverseDeps(mod.getClass().getCanonicalName(),
+                                     modsToLoad, moduleList,
+                                     moduleMap, modsVisited);
+                    } else {
+                        boolean found = false;
+                        for (IFloodlightModule moduleDep : mods) {
+                            String d = moduleDep.getClass().getCanonicalName();
+                            if (modsToLoad.contains(d)) {
+                                modsToLoad.remove(d);
+                                traverseDeps(d,
+                                             modsToLoad, moduleList,
+                                             moduleMap, modsVisited);
+                                found = true;
+                                break;
+                            }
                         }
-                        //}
-                    }
-                }
-            }
-            
-            // 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;
+                        if (!found) {
+                            Priority maxp = Priority.MINIMUM;
+                            ArrayList<IFloodlightModule> curMax = new ArrayList<>();
                             for (IFloodlightModule moduleDep : mods) {
-                                if (configMods.contains(moduleDep.getClass().getCanonicalName())) {
-                                    // Module will be loaded, we can continue
-                                    found = true;
-                                    break;
+                                FloodlightModulePriority fmp =
+                                        moduleDep.getClass().
+                                        getAnnotation(FloodlightModulePriority.class);
+                                Priority curp = Priority.NORMAL;
+                                if (fmp != null) {
+                                    curp = fmp.value();
+                                }
+                                if (curp.value() > maxp.value()) {
+                                    curMax.clear();
+                                    curMax.add(moduleDep);
+                                    maxp = curp;
+                                } else if  (curp.value() == maxp.value()) {
+                                    curMax.add(moduleDep);
                                 }
                             }
-                            if (!found) {
-                                String duplicateMods = "";
-                                for (IFloodlightModule mod : mods) {
-                                    duplicateMods += mod.getClass().getCanonicalName() + ", ";
+
+                            if (curMax.size() == 1) {
+                                traverseDeps(curMax.get(0).
+                                             getClass().getCanonicalName(),
+                                             modsToLoad, moduleList,
+                                             moduleMap, modsVisited);
+                            } else {
+                                StringBuilder sb = new StringBuilder();
+                                for (IFloodlightModule mod : curMax) {
+                                    sb.append(mod.getClass().getCanonicalName());
+                                    sb.append(", ");
                                 }
-                                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);
+                                String duplicateMods = sb.toString();
+
+                                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 the module to be loaded
+        addModule(moduleMap, moduleList, module);
     }
-    
+
     /**
      * 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 moduleList the module set
      * @param module the module to add
      */
-    protected void addModule(Map<Class<? extends IFloodlightService>, 
+    protected void addModule(Map<Class<? extends IFloodlightService>,
                                            IFloodlightModule> moduleMap,
-                            Collection<IFloodlightModule> moduleSet,
+                            Collection<IFloodlightModule> moduleList,
                             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);
+        Collection<Class<? extends IFloodlightService>> servs =
+                moduleServiceMap.get(module);
+        if (servs != null) {
+            for (Class<? extends IFloodlightService> c : servs)
+                moduleMap.put(c, module);
         }
+        moduleList.add(module);
     }
 
     /**
@@ -388,23 +443,20 @@ public class FloodlightModuleLoader implements IModuleService {
      * @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) 
+    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>, 
+            Map<Class<? extends IFloodlightService>,
                 IFloodlightService> simpls = module.getServiceImpls();
 
             // add its services to the context
             if (simpls != null) {
-                for (Entry<Class<? extends IFloodlightService>, 
+                for (Entry<Class<? extends IFloodlightService>,
                         IFloodlightService> s : simpls.entrySet()) {
                     if (logger.isDebugEnabled()) {
-                        logger.debug("Setting " + s.getValue() + 
-                                     "  as provider for " + 
+                        logger.debug("Setting " + s.getValue() +
+                                     "  as provider for " +
                                      s.getKey().getCanonicalName());
                     }
                     if (floodlightModuleContext.getServiceImpl(s.getKey()) == null) {
@@ -422,40 +474,86 @@ public class FloodlightModuleLoader implements IModuleService {
                 }
             }
         }
-        
+
         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 " + 
+                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 
+     * @throws FloodlightModuleException
      */
-    protected void startupModules(Collection<IFloodlightModule> moduleSet) 
+    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);
         }
     }
-    
+
+    /** Tuple of floodlight module and run method */
+    private static class RunMethod {
+        private final IFloodlightModule module;
+        private final Method method;
+        public RunMethod(IFloodlightModule module, Method method) {
+            this.module = module;
+            this.method = method;
+        }
+
+        public void run() throws FloodlightModuleException {
+            try {
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Running {}", this);
+                }
+                method.invoke(module);
+            } catch (IllegalAccessException | IllegalArgumentException
+                    | InvocationTargetException e) {
+                throw new FloodlightModuleException("Failed to invoke "
+                        + "module Run method " + this, e);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return module.getClass().getCanonicalName() + "." + method;
+        }
+
+
+    }
+
+    public void runModules() throws FloodlightModuleException {
+        List<RunMethod> mainLoopMethods = Lists.newArrayList();
+
+        for (IFloodlightModule m : getModuleList()) {
+            for (Method method : m.getClass().getDeclaredMethods()) {
+                Run runAnnotation = method.getAnnotation(Run.class);
+                if (runAnnotation != null) {
+                    RunMethod runMethod = new RunMethod(m, method);
+                    if(runAnnotation.mainLoop()) {
+                        mainLoopMethods.add(runMethod);
+                    } else {
+                        runMethod.run();
+                    }
+                }
+            }
+        }
+        if(mainLoopMethods.size() == 1) {
+            mainLoopMethods.get(0).run();
+        } else if (mainLoopMethods.size() > 1) {
+            throw new FloodlightModuleException("Invalid module configuration -- "
+                    + "multiple run methods annotated with mainLoop detected: " + mainLoopMethods);
+        }
+    }
+
     /**
      * Parses configuration parameters for each module
      * @param prop The properties file to use
@@ -467,15 +565,11 @@ public class FloodlightModuleLoader implements IModuleService {
                         "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);
@@ -487,15 +581,25 @@ public class FloodlightModuleLoader implements IModuleService {
             } else {
                 configValue = prop.getProperty(key);
             }
-            
+
             IFloodlightModule mod = moduleNameMap.get(moduleName);
             if (mod == null) {
-                logger.warn("Module {} not found or loaded. " +
-                            "Not adding configuration option {} = {}", 
+                logger.debug("Module {} not found or loaded. " +
+                            "Not adding configuration option {} = {}",
                             new Object[]{moduleName, configKey, configValue});
             } else {
+            	logger.debug("Adding configuration option {} = {} for module {}",
+                        new Object[]{configKey, configValue, moduleName});
                 floodlightModuleContext.addConfigParam(mod, configKey, configValue);
             }
         }
     }
+
+    public boolean isStartupModules() {
+        return startupModules;
+    }
+
+    public void setStartupModules(boolean startupModules) {
+        this.startupModules = startupModules;
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModulePriority.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModulePriority.java
new file mode 100644
index 0000000000000000000000000000000000000000..d2e561fbf435049f16fe80c885941c3e50deae40
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModulePriority.java
@@ -0,0 +1,58 @@
+/**
+ *    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
new file mode 100644
index 0000000000000000000000000000000000000000..c5d24b72313ee1234ca5beea1a7c9cafef229f38
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightServices.java
@@ -0,0 +1,5 @@
+package net.floodlightcontroller.core.module;
+
+public @interface FloodlightServices {
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java b/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java
index 982e4be26a7e073dd700599a96a4393697088ed3..8387e5d092c0a95f59426b493b20a982cba07716 100644
--- a/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java
+++ b/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java
@@ -19,7 +19,6 @@ package net.floodlightcontroller.core.module;
 import java.util.Collection;
 import java.util.Map;
 
-
 /**
  * Defines an interface for loadable Floodlight modules.
  * 
@@ -27,7 +26,7 @@ import java.util.Map;
  * <ol>
  * <li> getServices() : what services does this module provide
  * <li> getDependencies() : list the dependencies
- * <li> init() : internal initializations (don't touch other modules)
+ * <li> init() : internal initializations (<em>don't</em> touch other modules)
  * <li> startUp() : external initializations (<em>do</em> touch other modules)
  * </ol>
  * 
@@ -50,8 +49,7 @@ public interface IFloodlightModule {
      * 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();
+    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls();
     
     /**
      * Get a list of Modules that this module depends on.  The module system
@@ -87,6 +85,5 @@ public interface IFloodlightModule {
      * @throws FloodlightModuleException 
      */
     
-    void startUp(FloodlightModuleContext 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
index 46dea092c2eaa20b180b2176ddd3babbb2d24b26..d6780f6cf476a27c71786540b1f1bdfd830f4d36 100644
--- a/src/main/java/net/floodlightcontroller/core/module/IFloodlightModuleContext.java
+++ b/src/main/java/net/floodlightcontroller/core/module/IFloodlightModuleContext.java
@@ -19,8 +19,8 @@ package net.floodlightcontroller.core.module;
 import java.util.Collection;
 import java.util.Map;
 
-	
-public interface IFloodlightModuleContext {	
+    
+public interface IFloodlightModuleContext {    
     /**
      * Retrieves a casted version of a module from the registry.
      * @param name The IFloodlightService object type
@@ -36,12 +36,6 @@ public interface IFloodlightModuleContext {
      */
     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
diff --git a/src/main/java/net/floodlightcontroller/core/module/IModuleService.java b/src/main/java/net/floodlightcontroller/core/module/IModuleService.java
deleted file mode 100644
index 440ad2de6240709ef9e8a068e4b557f6b1444d82..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/module/IModuleService.java
+++ /dev/null
@@ -1,18 +0,0 @@
-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
index b4406117effee39794485dcedac4885fbea0a3ad..bc1b74cd15a5671fd87dfc3d6646c85e80786308 100644
--- a/src/main/java/net/floodlightcontroller/core/module/ModuleLoaderResource.java
+++ b/src/main/java/net/floodlightcontroller/core/module/ModuleLoaderResource.java
@@ -22,7 +22,6 @@ 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;
@@ -53,6 +52,9 @@ public class ModuleLoaderResource extends ServerResource {
      */
     public Map<String, Object> retrieveInternal(boolean loadedOnly) {    
         Map<String, Object> model = new HashMap<String, Object>();
+        FloodlightModuleLoader floodlightModuleLoader =
+                (FloodlightModuleLoader) getContext().getAttributes().
+                get(FloodlightModuleLoader.class.getCanonicalName());
 
         Set<String> loadedModules = new HashSet<String>();
         for (Object val : getContext().getAttributes().values()) {
@@ -63,13 +65,11 @@ public class ModuleLoaderResource extends ServerResource {
         	}
         }
 
-        for (String moduleName : 
-        				FloodlightModuleLoader.moduleNameMap.keySet() ) {
+        for (String moduleName : floodlightModuleLoader.getModuleNameMap().keySet() ) {
         	Map<String,Object> moduleInfo = new HashMap<String, Object>();
 
         	IFloodlightModule module = 
-        				FloodlightModuleLoader.moduleNameMap.get(
-        						moduleName);
+        			floodlightModuleLoader.getModuleNameMap().get(moduleName);
         		
         	Collection<Class<? extends IFloodlightService>> deps = 
         			module.getModuleDependencies();
@@ -117,4 +117,4 @@ public class ModuleLoaderResource extends ServerResource {
         }            
         return model;
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/module/Run.java b/src/main/java/net/floodlightcontroller/core/module/Run.java
new file mode 100644
index 0000000000000000000000000000000000000000..4bf8a2ed41d270282b5dbda582a8ac7c32ec448f
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/module/Run.java
@@ -0,0 +1,20 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..3d0fe680e544ffa5a7701ad42f0037fe8de9037c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/rest/AggregateStatistics.java
@@ -0,0 +1,39 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..03a46f462b68300c61639052b03a7931bfcc4861
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/rest/SwitchRepresentation.java
@@ -0,0 +1,116 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..480ff2004e0eae6f133fb79a94adc318b6b57cf4
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/rest/TableStatistics.java
@@ -0,0 +1,45 @@
+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/MacVlanPair.java b/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java
index 7a44f1d29f9c501bdbb55c0c64479e50a2f60573..ed7da2dff8d2ee9d33c7121a9a17ca651deca78d 100644
--- a/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java
+++ b/src/main/java/net/floodlightcontroller/core/types/MacVlanPair.java
@@ -17,20 +17,23 @@
 
 package net.floodlightcontroller.core.types;
 
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.VlanVid;
+
 public class MacVlanPair {
-    public Long mac;
-    public Short vlan;
-    public MacVlanPair(Long mac, Short vlan) {
-        this.mac = mac;
-        this.vlan = vlan;
+    public MacAddress mac;
+    public VlanVid vlan;
+    public MacVlanPair(MacAddress mac2, VlanVid vlan2) {
+        this.mac = mac2;
+        this.vlan = vlan2;
     }
     
-    public long getMac() {
-        return mac.longValue();
+    public MacAddress getMac() {
+        return mac;
     }
     
-    public short getVlan() {
-        return vlan.shortValue();
+    public VlanVid getVlan() {
+        return vlan;
     }
     
     public boolean equals(Object o) {
diff --git a/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java b/src/main/java/net/floodlightcontroller/core/types/SwitchMessagePair.java
index 0e91bc9b488d6009eaaac15641aba1b0cde5a998..2f40532961b5912b2981f4ce5fbd75d668b1beb8 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.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFMessage;
 
 import net.floodlightcontroller.core.IOFSwitch;
 
diff --git a/src/main/java/net/floodlightcontroller/core/util/AppCookie.java b/src/main/java/net/floodlightcontroller/core/util/AppCookie.java
index 48ff7d9beb31921b2bfee97f52a85fc82bd94ae5..5406bbd8c9a6a2b92b423db0598d225713b83fa4 100644
--- a/src/main/java/net/floodlightcontroller/core/util/AppCookie.java
+++ b/src/main/java/net/floodlightcontroller/core/util/AppCookie.java
@@ -20,6 +20,8 @@ package net.floodlightcontroller.core.util;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import org.projectfloodlight.openflow.types.U64;
+
 /***
  * A static utility class to register flow cookiue AppIds and generating
  * flow cookies for a particular App`
@@ -76,13 +78,13 @@ public class AppCookie {
      * @throws IllegalStateException if the application has not been registered
      */
 
-    static public long makeCookie(int application, int user) {
+    static public U64 makeCookie(int application, int user) {
         if (!appIdMap.containsKey(application)) {
             throw new AppIDNotRegisteredException(application);
         }
         long longApp = application;
         long longUser = user & USER_MASK; // mask to prevent sign extend
-        return (longApp << APP_ID_SHIFT) | longUser;
+        return U64.of((longApp << APP_ID_SHIFT) | longUser);
     }
 
     /**
@@ -91,54 +93,54 @@ public class AppCookie {
      * @param cookie
      * @return
      */
-    static public int extractApp(long cookie) {
-        return (int)((cookie >>> APP_ID_SHIFT) & APP_ID_MASK);
+    static public int extractApp(U64 cookie) {
+        return (int)((cookie.getValue() >>> APP_ID_SHIFT) & APP_ID_MASK);
     }
 
-    static public int extractUser(long cookie) {
-        return (int)(cookie & USER_MASK);
+    static public int extractUser(U64 cookie) {
+        return (int)(cookie.getValue() & USER_MASK);
     }
 
-    static public boolean isRewriteFlagSet(long cookie) {
-        if ((cookie & REWRITE_MASK) !=0L)
+    static public boolean isRewriteFlagSet(U64 cookie) {
+        if ((cookie.getValue() & REWRITE_MASK) !=0L)
             return true;
         return false;
     }
-    static public boolean isSrcMacRewriteFlagSet(long cookie) {
-        if ((cookie & (1L << (SRC_MAC_REWRITE_BIT-1))) !=0L)
+    static public boolean isSrcMacRewriteFlagSet(U64 cookie) {
+        if ((cookie.getValue() & (1L << (SRC_MAC_REWRITE_BIT-1))) !=0L)
             return true;
         return false;
     }
-    static public boolean isDestMacRewriteFlagSet(long cookie) {
-        if ((cookie & (1L << (DEST_MAC_REWRITE_BIT-1))) !=0L)
+    static public boolean isDestMacRewriteFlagSet(U64 cookie) {
+        if ((cookie.getValue() & (1L << (DEST_MAC_REWRITE_BIT-1))) !=0L)
             return true;
         return false;
     }
-    static public boolean isSrcIpRewriteFlagSet(long cookie) {
-        if ((cookie & (1L << (SRC_IP_REWRITE_BIT-1))) !=0L)
+    static public boolean isSrcIpRewriteFlagSet(U64 cookie) {
+        if ((cookie.getValue() & (1L << (SRC_IP_REWRITE_BIT-1))) !=0L)
             return true;
         return false;
     }
-    static public boolean isDestIpRewriteFlagSet(long cookie) {
-        if ((cookie & (1L << (DEST_IP_REWRITE_BIT-1))) !=0L)
+    static public boolean isDestIpRewriteFlagSet(U64 cookie) {
+        if ((cookie.getValue() & (1L << (DEST_IP_REWRITE_BIT-1))) !=0L)
             return true;
         return false;
     }
-    static public long setSrcMacRewriteFlag(long cookie) {
-        return cookie | (1L << (SRC_MAC_REWRITE_BIT-1));
+    static public U64 setSrcMacRewriteFlag(U64 cookie) {
+        return U64.of(cookie.getValue() | (1L << (SRC_MAC_REWRITE_BIT-1)));
     }
-    static public long setDestMacRewriteFlag(long cookie) {
-        return cookie | (1L << (DEST_MAC_REWRITE_BIT-1));
+    static public U64 setDestMacRewriteFlag(U64 cookie) {
+        return U64.of(cookie.getValue() | (1L << (DEST_MAC_REWRITE_BIT-1)));
     }
-    static public long setSrcIpRewriteFlag(long cookie) {
-        return cookie | (1L << (SRC_IP_REWRITE_BIT-1));
+    static public U64 setSrcIpRewriteFlag(U64 cookie) {
+        return U64.of(cookie.getValue() | (1L << (SRC_IP_REWRITE_BIT-1)));
     }
-    static public long setDestIpRewriteFlag(long cookie) {
-        return cookie | (1L << (DEST_IP_REWRITE_BIT-1));
+    static public U64 setDestIpRewriteFlag(U64 cookie) {
+        return U64.of(cookie.getValue() | (1L << (DEST_IP_REWRITE_BIT-1)));
     }
     /**
      * A lame attempt to prevent duplicate application ID.
-     * TODO: Once bigdb is merged, we should expose appID->appName map
+     * TODO: We should expose appID->appName map
      *       via REST API so CLI doesn't need a separate copy of the map.
      *
      * @param application
diff --git a/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java b/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java
index da3c16444582e01c2c93108c0e5678c9138db6fe..4a6b978c55e6f5c7a2eec59ccd984ab010f462d9 100644
--- a/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java
+++ b/src/main/java/net/floodlightcontroller/core/util/ListenerDispatcher.java
@@ -21,11 +21,10 @@ import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import net.floodlightcontroller.core.IListener;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Maintain lists of listeners ordered by dependency.
@@ -34,7 +33,8 @@ import net.floodlightcontroller.core.annotations.LogMessageDoc;
  *
  */
 public class ListenerDispatcher<U, T extends IListener<U>> {
-    protected static Logger logger = LoggerFactory.getLogger(ListenerDispatcher.class);
+    protected static final Logger logger = 
+            LoggerFactory.getLogger(ListenerDispatcher.class);
     volatile List<T> listeners = new ArrayList<T>();
 
     private void visit(List<T> newlisteners, U type, HashSet<T> visited,
@@ -64,10 +64,10 @@ public class ListenerDispatcher<U, T extends IListener<U>> {
                    message="No listener dependency solution: " +
                            "No listeners without incoming dependencies",
                    explanation="The set of listeners installed " +
-                   		"have dependencies with no solution",
+                           "have dependencies with no solution",
                    recommendation="Install a different set of listeners " +
-                   		"or install all dependencies.  This is a defect in " +
-                   		"the controller installation.")
+                           "or install all dependencies.  This is a defect in " +
+                           "the controller installation.")
     public void addListener(U type, T listener) {
         List<T> newlisteners = new ArrayList<T>();
         if (listeners != null)
@@ -91,7 +91,7 @@ public class ListenerDispatcher<U, T extends IListener<U>> {
 
         if (terminals.size() == 0) {
             logger.error("No listener dependency solution: " +
-            		     "No listeners without incoming dependencies");
+                         "No listeners without incoming dependencies");
             listeners = newlisteners;
             return;
         }
diff --git a/src/main/java/net/floodlightcontroller/core/util/OFUtils.java b/src/main/java/net/floodlightcontroller/core/util/OFUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f39289fc2b2752bc58db5f6efe8891a40dcfdeb
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/util/OFUtils.java
@@ -0,0 +1,151 @@
+package net.floodlightcontroller.core.util;
+
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.ArpOpcode;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.ICMPv4Code;
+import org.projectfloodlight.openflow.types.ICMPv4Type;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IpDscp;
+import org.projectfloodlight.openflow.types.IpEcn;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U8;
+import org.projectfloodlight.openflow.types.VlanPcp;
+
+public class OFUtils {
+    public static Match loadFromPacket(byte[] packetData, OFPort inputPort,
+            OFFactory factory) {
+        short scratch;
+        int transportOffset = 34;
+        ByteBuffer packetDataBB = ByteBuffer.wrap(packetData);
+        int limit = packetDataBB.limit();
+        assert (limit >= 14);
+
+        Match.Builder builder = factory.buildMatch();
+
+        if (!Objects.equals(inputPort, OFPort.ALL))
+            builder.setExact(MatchField.IN_PORT, inputPort);
+
+        // dl dst
+        byte[] dataLayerDestination = new byte[6];
+        packetDataBB.get(dataLayerDestination);
+        builder.setExact(MatchField.ETH_DST, MacAddress.of(dataLayerDestination));
+        // dl src
+        byte[] dataLayerSource = new byte[6];
+        packetDataBB.get(dataLayerSource);
+        builder.setExact(MatchField.ETH_SRC, MacAddress.of(dataLayerSource));
+        // dl type
+        short dataLayerType = packetDataBB.getShort();
+        builder.setExact(MatchField.ETH_TYPE, EthType.of(dataLayerType));
+
+        if (dataLayerType != (short) 0x8100) { // need cast to avoid signed
+            // bug
+            builder.setExact(MatchField.VLAN_VID, OFVlanVidMatch.UNTAGGED);
+            builder.setExact(MatchField.VLAN_PCP, VlanPcp.NONE);
+        } else {
+            // has vlan tag
+            scratch = packetDataBB.getShort();
+            builder.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(0xfff & scratch));
+            builder.setExact(MatchField.VLAN_PCP, VlanPcp.of((byte)((0xe000 & scratch) >> 13)));
+            dataLayerType = packetDataBB.getShort();
+        }
+
+        short networkProtocol;
+        int networkSource;
+        int networkDestination;
+
+        switch (dataLayerType) {
+        case 0x0800:
+            // ipv4
+            // check packet length
+            scratch = packetDataBB.get();
+            scratch = (short) (0xf & scratch);
+            transportOffset = (packetDataBB.position() - 1) + (scratch * 4);
+            // nw tos (dscp+ecn)
+            scratch = packetDataBB.get();
+            builder.setExact(MatchField.IP_ECN, IpEcn.of((byte)(scratch & 0x03)));
+            builder.setExact(MatchField.IP_DSCP, IpDscp.of((byte) ((0xfc & scratch) >> 2)));
+            // nw protocol
+            packetDataBB.position(packetDataBB.position() + 7);
+            networkProtocol = packetDataBB.get();
+            builder.setExact(MatchField.IP_PROTO, IpProtocol.of(networkProtocol));
+            // nw src
+            packetDataBB.position(packetDataBB.position() + 2);
+            networkSource = packetDataBB.getInt();
+            builder.setExact(MatchField.IPV4_SRC, IPv4Address.of(networkSource));
+            // nw dst
+            networkDestination = packetDataBB.getInt();
+            builder.setExact(MatchField.IPV4_DST, IPv4Address.of(networkDestination));
+            packetDataBB.position(transportOffset);
+
+            int port;
+            switch (networkProtocol) {
+            case 0x01:
+                // icmp
+                // type
+                short type = U8.f(packetDataBB.get());
+                builder.setExact(MatchField.ICMPV4_TYPE, ICMPv4Type.of(type));
+                // code
+                short code = U8.f(packetDataBB.get());
+                builder.setExact(MatchField.ICMPV4_CODE, ICMPv4Code.of(code));
+                break;
+            case 0x06:
+                // tcp
+                // tcp src
+                port = packetDataBB.getShort();
+                builder.setExact(MatchField.TCP_SRC, TransportPort.of(port));
+                // tcp dest
+                port = packetDataBB.getShort();
+                builder.setExact(MatchField.TCP_DST, TransportPort.of(port));
+                break;
+            case 0x11:
+                // udp
+                // udp src
+                port = packetDataBB.getShort();
+                builder.setExact(MatchField.UDP_SRC, TransportPort.of(port));
+                // udp dest
+                port = packetDataBB.getShort();
+                builder.setExact(MatchField.UDP_DST, TransportPort.of(port));
+                break;
+            default:
+                // Unknown network proto.
+                break;
+            }
+            break;
+        case 0x0806:
+            // arp
+            int arpPos = packetDataBB.position();
+            // opcode
+            scratch = packetDataBB.getShort(arpPos + 6);
+            builder.setExact(MatchField.ARP_OP, ArpOpcode.of(0xff & scratch));
+
+            scratch = packetDataBB.getShort(arpPos + 2);
+            // if ipv4 and addr len is 4
+            if (scratch == 0x800 && packetDataBB.get(arpPos + 5) == 4) {
+                networkSource = packetDataBB.getInt(arpPos + 14);
+                networkDestination = packetDataBB.getInt(arpPos + 24);
+            } else {
+                networkSource = 0;
+                networkDestination = 0;
+            }
+            builder.setExact(MatchField.ARP_SPA, IPv4Address.of(networkSource));
+            builder.setExact(MatchField.ARP_TPA, IPv4Address.of(networkDestination));
+            break;
+        default:
+            // Not ARP or IP.
+            // Don't specify any network fields
+            break;
+        }
+
+        return builder.build();
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/util/SingletonTask.java b/src/main/java/net/floodlightcontroller/core/util/SingletonTask.java
index 07729e533cacda933365652113f9a5ad1516a6aa..7a145f82f1f668b0415d353c8d04cc4ecc8a97a8 100644
--- a/src/main/java/net/floodlightcontroller/core/util/SingletonTask.java
+++ b/src/main/java/net/floodlightcontroller/core/util/SingletonTask.java
@@ -21,7 +21,6 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,7 +36,8 @@ import org.slf4j.LoggerFactory;
  * * If the task has begun, set a bit to restart it after the current task finishes
  */
 public class SingletonTask {
-    protected static Logger logger = LoggerFactory.getLogger(SingletonTask.class);
+    protected static final Logger logger = 
+            LoggerFactory.getLogger(SingletonTask.class);
             
     protected static class SingletonTaskContext  {
         protected boolean taskShouldRun = false;
@@ -74,6 +74,10 @@ public class SingletonTask {
             } catch (Exception e) {
                 logger.error("Exception while executing task", e);
             }
+            catch (Error e) {
+                logger.error("Error while executing task", e);
+                throw e;
+            }
 
             synchronized (parent.context) {
                 parent.context.taskRunning = false;
@@ -134,6 +138,7 @@ public class SingletonTask {
                         long then = 
                             now + TimeUnit.NANOSECONDS.convert(delay, unit);
                         context.waitingTask.nextschedule = then;
+//                        logger.debug("rescheduled task " + this + " for " + TimeUnit.SECONDS.convert(then, TimeUnit.NANOSECONDS) + "s. A bunch of these messages -may- indicate you have a blocked task.");
                     } else {
                         context.waitingTask.nextschedule = 0;
                     }
@@ -153,10 +158,10 @@ public class SingletonTask {
         }
 
         if (needQueue) {
-            if (delay <= 0)
+            if (delay <= 0) 
                 ses.execute(stw);
             else
                 ses.schedule(stw, delay, unit);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/floodlightcontroller/core/util/URIUtil.java b/src/main/java/net/floodlightcontroller/core/util/URIUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..01a44ccf0cda6782ebbcaef9c5874361c4c272b0
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/util/URIUtil.java
@@ -0,0 +1,10 @@
+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 c957e6356ba9833bb2b40e331881cccd528b40a1..169faaf9c1ca8f04630d1b885e1bff47cba09611 100644
--- a/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/AllSwitchStatisticsResource.java
@@ -24,11 +24,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import org.openflow.protocol.OFFeaturesReply;
-import org.openflow.protocol.statistics.OFStatistics;
-import org.openflow.protocol.statistics.OFStatisticsType;
-import org.openflow.util.HexString;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
+
+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.restlet.resource.Get;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,26 +52,26 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
     public Map<String, Object> retrieveInternal(String statType) {
         HashMap<String, Object> model = new HashMap<String, Object>();
 
-        OFStatisticsType type = null;
+        OFStatsType type = null;
         REQUESTTYPE rType = null;
 
         if (statType.equals("port")) {
-            type = OFStatisticsType.PORT;
+            type = OFStatsType.PORT;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("queue")) {
-            type = OFStatisticsType.QUEUE;
+            type = OFStatsType.QUEUE;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("flow")) {
-            type = OFStatisticsType.FLOW;
+            type = OFStatsType.FLOW;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("aggregate")) {
-            type = OFStatisticsType.AGGREGATE;
+            type = OFStatsType.AGGREGATE;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("desc")) {
-            type = OFStatisticsType.DESC;
+            type = OFStatsType.DESC;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("table")) {
-            type = OFStatisticsType.TABLE;
+            type = OFStatsType.TABLE;
             rType = REQUESTTYPE.OFSTATS;
         } else if (statType.equals("features")) {
             rType = REQUESTTYPE.OFFEATURES;
@@ -77,14 +79,14 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
             return model;
         }
 
-        IFloodlightProviderService floodlightProvider =
-                (IFloodlightProviderService)getContext().getAttributes().
-                    get(IFloodlightProviderService.class.getCanonicalName());
-        Set<Long> switchDpids = floodlightProvider.getAllSwitchDpids();
+        IOFSwitchService switchService =
+                (IOFSwitchService) getContext().getAttributes().
+                    get(IOFSwitchService.class.getCanonicalName());
+        Set<DatapathId> switchDpids = switchService.getAllSwitchDpids();
         List<GetConcurrentStatsThread> activeThreads = new ArrayList<GetConcurrentStatsThread>(switchDpids.size());
         List<GetConcurrentStatsThread> pendingRemovalThreads = new ArrayList<GetConcurrentStatsThread>();
         GetConcurrentStatsThread t;
-        for (Long l : switchDpids) {
+        for (DatapathId l : switchDpids) {
             t = new GetConcurrentStatsThread(l, rType, type);
             activeThreads.add(t);
             t.start();
@@ -98,9 +100,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()), curThread.getStatisticsReply());
+                        model.put(HexString.toHexString(curThread.getSwitchId().getLong()), curThread.getStatisticsReply());
                     } else if (rType == REQUESTTYPE.OFFEATURES) {
-                        model.put(HexString.toHexString(curThread.getSwitchId()), curThread.getFeaturesReply());
+                        model.put(HexString.toHexString(curThread.getSwitchId().getLong()), curThread.getFeaturesReply());
                     }
                     pendingRemovalThreads.add(curThread);
                 }
@@ -130,13 +132,13 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
     }
 
     protected class GetConcurrentStatsThread extends Thread {
-        private List<OFStatistics> switchReply;
-        private long switchId;
-        private OFStatisticsType statType;
+        private List<OFStatsReply> switchReply;
+        private DatapathId switchId;
+        private OFStatsType statType;
         private REQUESTTYPE requestType;
         private OFFeaturesReply featuresReply;
 
-        public GetConcurrentStatsThread(long switchId, REQUESTTYPE requestType, OFStatisticsType statType) {
+        public GetConcurrentStatsThread(DatapathId switchId, REQUESTTYPE requestType, OFStatsType statType) {
             this.switchId = switchId;
             this.requestType = requestType;
             this.statType = statType;
@@ -144,7 +146,7 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
             this.featuresReply = null;
         }
 
-        public List<OFStatistics> getStatisticsReply() {
+        public List<OFStatsReply> getStatisticsReply() {
             return switchReply;
         }
 
@@ -152,7 +154,7 @@ public class AllSwitchStatisticsResource extends SwitchResourceBase {
             return featuresReply;
         }
 
-        public long getSwitchId() {
+        public DatapathId getSwitchId() {
             return switchId;
         }
 
diff --git a/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java b/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java
index 9ad593788f05401a717e32cfa5943ca1b508f909..9da5c493bc4be59c3443ec82db58d389f746bc9e 100644
--- a/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java
@@ -21,7 +21,7 @@ import org.restlet.resource.ServerResource;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.RoleInfo;
-import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.HARole;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
 
 import org.restlet.resource.Get;
@@ -49,9 +49,9 @@ public class ControllerRoleResource extends ServerResource {
                    recommendation=LogMessageDoc.CHECK_CONTROLLER)
     public void setRole(RoleInfo roleInfo) {
         //Role role = Role.lookupRole(roleInfo.getRole());
-        Role role = null;
+        HARole role = null;
         try {
-            role = Role.valueOf(roleInfo.getRole().toUpperCase());
+            role = roleInfo.getRole();
         }
         catch (IllegalArgumentException e) {
             // The role value in the REST call didn't match a valid
diff --git a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java
index eeaebe22c38aafb04834f2bac82e51be991e21be..d8564f5703ec17b30cf53642e3225dd7f549e9ca 100644
--- a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java
@@ -23,14 +23,17 @@ 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.HARole;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.ImmutablePort;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.util.FilterIterator;
 
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.util.HexString;
+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.restlet.data.Form;
 import org.restlet.data.Status;
 import org.restlet.resource.Get;
@@ -52,7 +55,7 @@ public class ControllerSwitchesResource extends ServerResource {
             this.sw = sw;
         }
 
-        public int getActions() {
+        public Set<OFActionType> getActions() {
             return sw.getActions();
         }
 
@@ -62,7 +65,7 @@ public class ControllerSwitchesResource extends ServerResource {
 
         public Map<String,String> getDescription() {
             Map<String,String> rv = new HashMap<String, String>();
-            if (sw.getDescriptionStatistics() == null) {
+            if (sw.getSwitchDescription() == null) {
                 rv.put("manufacturer", "");
                 rv.put("hardware", "");
                 rv.put("software", "");
@@ -70,24 +73,24 @@ public class ControllerSwitchesResource extends ServerResource {
                 rv.put("datapath", "");
             } else {
                 rv.put("manufacturer",
-                       sw.getDescriptionStatistics().getManufacturerDescription());
+                       sw.getSwitchDescription().getManufacturerDescription());
                 rv.put("hardware",
-                       sw.getDescriptionStatistics().getHardwareDescription());
+                       sw.getSwitchDescription().getHardwareDescription());
                 rv.put("software",
-                       sw.getDescriptionStatistics().getSoftwareDescription());
+                       sw.getSwitchDescription().getSoftwareDescription());
                 rv.put("serialNum",
-                       sw.getDescriptionStatistics().getSerialNumber());
+                       sw.getSwitchDescription().getSerialNumber());
                 rv.put("datapath",
-                       sw.getDescriptionStatistics().getDatapathDescription());
+                       sw.getSwitchDescription().getDatapathDescription());
             }
             return rv;
         }
 
-        public int getBuffers() {
+        public long getBuffers() {
             return sw.getBuffers();
         }
 
-        public int getCapabilities() {
+        public Set<OFCapabilities> getCapabilities() {
             return sw.getCapabilities();
         }
 
@@ -98,13 +101,13 @@ public class ControllerSwitchesResource extends ServerResource {
         }
 
         public String getDpid() {
-            return sw.getStringId();
+            return sw.getId().toString();
         }
 
         public String getHarole() {
-            if (sw.getHARole() == null)
+            if (sw.getControllerRole() == null)
                 return "null";
-            return sw.getHARole().toString();
+            return HARole.ofOFRole(sw.getControllerRole()).toString();
         }
 
         public String getInetAddress() {
@@ -114,8 +117,8 @@ public class ControllerSwitchesResource extends ServerResource {
             return addr.toString();
         }
 
-        public Collection<OFPhysicalPort> getPorts() {
-            return ImmutablePort.ofPhysicalPortListOf(sw.getPorts());
+        public Collection<OFPortDesc> getPorts() {
+            return sw.getPorts();
         }
     }
 
@@ -154,17 +157,17 @@ public class ControllerSwitchesResource extends ServerResource {
 
     @Get("json")
     public Iterator<SwitchJsonSerializerWrapper> retrieve() {
-        IFloodlightProviderService floodlightProvider =
-                (IFloodlightProviderService)getContext().getAttributes().
-                    get(IFloodlightProviderService.class.getCanonicalName());
+        IOFSwitchService switchService =
+                (IOFSwitchService) getContext().getAttributes().
+                    get(IOFSwitchService.class.getCanonicalName());
 
-        Long switchDPID = null;
+        DatapathId switchDPID = null;
 
         Form form = getQuery();
         String dpid = form.getFirstValue("dpid", true);
         if (dpid != null) {
             try {
-                switchDPID = HexString.toLong(dpid);
+                switchDPID = DatapathId.of(dpid);
             } catch (Exception e) {
                 setStatus(Status.CLIENT_ERROR_BAD_REQUEST, DPID_ERROR);
                 return null;
@@ -172,7 +175,7 @@ public class ControllerSwitchesResource extends ServerResource {
         }
         if (switchDPID != null) {
             IOFSwitch sw =
-                    floodlightProvider.getSwitch(switchDPID);
+                    switchService.getSwitch(switchDPID);
             if (sw != null) {
                 SwitchJsonSerializerWrapper wrappedSw =
                         new SwitchJsonSerializerWrapper(sw);
@@ -184,7 +187,7 @@ public class ControllerSwitchesResource extends ServerResource {
                 form.getFirstValue("dpid__startswith", true);
 
         Iterator<IOFSwitch> iofSwitchIter =
-                floodlightProvider.getAllSwitchMap().values().iterator();
+                switchService.getAllSwitchMap().values().iterator();
         Iterator<SwitchJsonSerializerWrapper> switer =
                 new SwitchJsonSerializerWrapperIterator(iofSwitchIter);
         if (dpidStartsWith != null) {
diff --git a/src/main/java/net/floodlightcontroller/core/web/CounterResource.java b/src/main/java/net/floodlightcontroller/core/web/CounterResource.java
index fb680d7c94b4a6af0cfdad5fd288c095e2c3ffd1..c08e5b3aa4026a580d9e99abc162e92aeb9d7589 100644
--- a/src/main/java/net/floodlightcontroller/core/web/CounterResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/CounterResource.java
@@ -19,40 +19,36 @@ package net.floodlightcontroller.core.web;
 
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import net.floodlightcontroller.counter.CounterValue;
-import net.floodlightcontroller.counter.ICounter;
+import net.floodlightcontroller.debugcounter.DebugCounterResource;
+import net.floodlightcontroller.debugcounter.IDebugCounter;
 
 import org.restlet.resource.Get;
 
 public class CounterResource extends CounterResourceBase {
     @Get("json")
     public Map<String, Object> retrieve() {
-        String counterTitle = 
+        /*TODO @Ryan String counterTitle = 
             (String) getRequestAttributes().get("counterTitle");
         Map<String, Object> model = new HashMap<String,Object>();
-        CounterValue v;
+        long dc;
         if (counterTitle.equalsIgnoreCase("all")) {
-            Map<String, ICounter> counters = this.counterStore.getAll();
+            List<DebugCounterResource> counters = this.debugCounterService.getAllCounterValues();
             if (counters != null) {
-                Iterator<Map.Entry<String, ICounter>> it = 
-                    counters.entrySet().iterator();
+                Iterator<DebugCounterResource> it = counters.iterator();
                 while (it.hasNext()) {
-                    Entry<String, ICounter> entry = it.next();
-                    String counterName = entry.getKey();
-                    v = entry.getValue().getCounterValue();
-
-                    if (CounterValue.CounterType.LONG == v.getType()) {
-                        model.put(counterName, v.getLong());
-                    } else if (v.getType() == CounterValue.CounterType.DOUBLE) {
-                        model.put(counterName, v.getDouble());
-                    }   
+                    DebugCounterResource dcr = it.next();
+                    String counterName = dcr.getCounterHierarchy();
+                    dc = dcr.getCounterValue();
+                    model.put(counterName, dc);
                 }   
             }   
         } else {
-            ICounter counter = this.counterStore.getCounter(counterTitle);
+            List<DebugCounterResource> counter = this.debugCounterService.getCounterHierarchy(???, counterTitle));
+            long v = 0;
             if (counter != null) {
                 v = counter.getCounterValue();
             } else {
@@ -65,6 +61,6 @@ public class CounterResource extends CounterResourceBase {
                 model.put(counterTitle, v.getDouble());
             }   
         }
-        return model;
+        return model;*/ return null;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/CounterResourceBase.java b/src/main/java/net/floodlightcontroller/core/web/CounterResourceBase.java
index 70e90ed231431b7c88e1377183671698686b5f75..ecf3935f313d6b8e520640ce4aa118f9ecb74148 100644
--- a/src/main/java/net/floodlightcontroller/core/web/CounterResourceBase.java
+++ b/src/main/java/net/floodlightcontroller/core/web/CounterResourceBase.java
@@ -17,19 +17,18 @@
 
 package net.floodlightcontroller.core.web;
 
-import net.floodlightcontroller.counter.ICounterStoreService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
 
 import org.restlet.resource.ResourceException;
 import org.restlet.resource.ServerResource;
 
 public class CounterResourceBase extends ServerResource {
-    protected ICounterStoreService counterStore;
+    protected IDebugCounterService debugCounterService;
     
     @Override
     protected void doInit() throws ResourceException {
         super.doInit();
-        counterStore = 
-            (ICounterStoreService)getContext().getAttributes().
-                get(ICounterStoreService.class.getCanonicalName());
+        debugCounterService = (IDebugCounterService) getContext().getAttributes().
+                get(IDebugCounterService.class.getCanonicalName());
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/LoadedModuleLoaderResource.java b/src/main/java/net/floodlightcontroller/core/web/LoadedModuleLoaderResource.java
index ad3ea5640cf61a20f4698363410a76dce26106d4..1afa6e470bd4ee2df8d6523295b7f2a8eb3d44ed 100644
--- a/src/main/java/net/floodlightcontroller/core/web/LoadedModuleLoaderResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/LoadedModuleLoaderResource.java
@@ -30,6 +30,6 @@ public class LoadedModuleLoaderResource extends ModuleLoaderResource {
 	 */
     @Get("json")
     public Map<String, Object> retrieve() {
-    	return retrieveInternal(true);
+    	return retrieveInternal(false);
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java
index 34aa2eaa763f2953fa6b03ad95a82c25683add11..66ba78641b569aacb6a4dedae26de4c2bf2551a2 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java
@@ -23,12 +23,10 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
 import org.restlet.resource.Get;
 
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.counter.CounterStore.NetworkLayer;
-import net.floodlightcontroller.counter.ICounterStoreService;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 
 /**
  * Get the counter categories for a particular switch
@@ -37,9 +35,9 @@ import net.floodlightcontroller.counter.ICounterStoreService;
 public class SwitchCounterCategoriesResource extends CounterResourceBase {
     @Get("json")
     public Map<String, Object> retrieve() {
-        IFloodlightProviderService floodlightProvider =
-                (IFloodlightProviderService)getContext().getAttributes().
-                    get(IFloodlightProviderService.class.getCanonicalName());
+        IOFSwitchService switchService =
+                (IOFSwitchService)getContext().getAttributes().
+                    get(IOFSwitchService.class.getCanonicalName());
         HashMap<String,Object> model = new HashMap<String,Object>();
 
         String switchID = (String) getRequestAttributes().get("switchId");
@@ -47,8 +45,8 @@ public class SwitchCounterCategoriesResource extends CounterResourceBase {
         String layer = (String) getRequestAttributes().get("layer");
 
         if (switchID.equalsIgnoreCase("all")) {
-            for (Long dpid : floodlightProvider.getAllSwitchDpids()) {
-                switchID = HexString.toHexString(dpid);
+            for (DatapathId dpid : switchService.getAllSwitchDpids()) {
+                switchID = dpid.toString();
 
                 getOneSwitchCounterCategoriesJson(model, switchID, counterName, layer);
             }
@@ -63,7 +61,7 @@ public class SwitchCounterCategoriesResource extends CounterResourceBase {
                                                      String switchID,
                                                      String counterName,
                                                      String layer) {
-        String fullCounterName = "";
+        /*TODO @Ryan String fullCounterName = "";
         NetworkLayer nl = NetworkLayer.L3;
 
         try {
@@ -80,6 +78,6 @@ public class SwitchCounterCategoriesResource extends CounterResourceBase {
         List<String> categories = this.counterStore.getAllCategories(fullCounterName, nl);
         if (categories != null) {
             model.put(fullCounterName + "." + layer, categories);
-        }
+        }*/
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java
index 34755ea083536a430652842a231fd22944e27552..8f33337d8f696028bba9c2b3e930556c8b0abb97 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java
@@ -22,12 +22,10 @@ import java.net.URLDecoder;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
 import org.restlet.resource.Get;
 
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.counter.ICounter;
-import net.floodlightcontroller.counter.ICounterStoreService;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 
 /**
  * Get counters for a particular switch
@@ -36,9 +34,9 @@ import net.floodlightcontroller.counter.ICounterStoreService;
 public class SwitchCounterResource extends CounterResourceBase {
     @Get("json")
     public Map<String, Object> retrieve() {
-        IFloodlightProviderService floodlightProvider =
-                (IFloodlightProviderService)getContext().getAttributes().
-                    get(IFloodlightProviderService.class.getCanonicalName());
+        /*TODO @Ryan IOFSwitchService switchService =
+                (IOFSwitchService)getContext().getAttributes().
+                    get(IOFSwitchService.class.getCanonicalName());
         HashMap<String,Object> model = new HashMap<String,Object>();
 
         String switchID = (String) getRequestAttributes().get("switchId");
@@ -46,20 +44,20 @@ public class SwitchCounterResource extends CounterResourceBase {
 
         if (switchID.equalsIgnoreCase("all")) {
             getOneSwitchCounterJson(model, ICounterStoreService.CONTROLLER_NAME, counterName);
-            for (Long dpid : floodlightProvider.getAllSwitchDpids()) {
-                switchID = HexString.toHexString(dpid);
+            for (DatapathId dpid : switchService.getAllSwitchDpids()) {
+                switchID = dpid.toString();
 
                 getOneSwitchCounterJson(model, switchID, counterName);
             }
         } else {
             getOneSwitchCounterJson(model, switchID, counterName);
         }
-        return model;
+        return model;*/ return null;
     }
 
     protected void getOneSwitchCounterJson(Map<String, Object> model,
                                            String switchID, String counterName) {
-        String fullCounterName = "";
+        /*TODO @Ryan String fullCounterName = "";
 
         try {
             counterName = URLDecoder.decode(counterName, "UTF-8");
@@ -75,7 +73,7 @@ public class SwitchCounterResource extends CounterResourceBase {
             sample.put(counter.getCounterDate().toString(),
                        counter.getCounterValue().getLong());
             model.put(switchID, sample);
-        }
+        } */
     }
 
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
index 6b4a46318fb7dbac07fd628ed23fcc44b8fb146a..9730a82b80ef14184371fff8f77792bf289b1582 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
@@ -25,23 +25,33 @@ import java.util.concurrent.TimeUnit;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
-
-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 net.floodlightcontroller.core.internal.IOFSwitchService;
+
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.queueprop.OFQueueProp;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
+import org.projectfloodlight.openflow.protocol.OFFeaturesRequest;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
+import org.projectfloodlight.openflow.protocol.OFQueueProperties;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFAggregateStatsRequest;
+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.util.HexString;
 import org.restlet.resource.ResourceException;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.primitives.UnsignedLong;
+import com.google.common.util.concurrent.ListenableFuture;
+
 /**
  * Base class for server resources related to switches
  * @author readams
@@ -67,58 +77,52 @@ public class SwitchResourceBase extends ServerResource {
                    		"from the switch",
                    recommendation=LogMessageDoc.CHECK_SWITCH + " " +
                    		LogMessageDoc.GENERIC_ACTION)
-    protected List<OFStatistics> getSwitchStatistics(long switchId,
-                                                     OFStatisticsType statType) {
-        IFloodlightProviderService floodlightProvider =
-                (IFloodlightProviderService)getContext().getAttributes().
-                    get(IFloodlightProviderService.class.getCanonicalName());
-
-        IOFSwitch sw = floodlightProvider.getSwitch(switchId);
-        Future<List<OFStatistics>> future;
-        List<OFStatistics> values = null;
+    protected List<OFStatsReply> getSwitchStatistics(DatapathId switchId,
+                                                     OFStatsType statType) {
+        IOFSwitchService switchService =
+                (IOFSwitchService) getContext().getAttributes().
+                    get(IOFSwitchService.class.getCanonicalName());
+
+        IOFSwitch sw = switchService.getSwitch(switchId);
+        ListenableFuture<?> future;
+        List<OFStatsReply> values = null;
         if (sw != null) {
-            OFStatisticsRequest req = new OFStatisticsRequest();
-            req.setStatisticType(statType);
-            int requestLength = req.getLengthU();
-            if (statType == OFStatisticsType.FLOW) {
-                OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest();
-                OFMatch match = new OFMatch();
-                match.setWildcards(0xffffffff);
-                specificReq.setMatch(match);
-                specificReq.setOutPort(OFPort.OFPP_NONE.getValue());
-                specificReq.setTableId((byte) 0xff);
-                req.setStatistics(Collections.singletonList((OFStatistics)specificReq));
-                requestLength += specificReq.getLength();
-            } else if (statType == OFStatisticsType.AGGREGATE) {
-                OFAggregateStatisticsRequest specificReq = new OFAggregateStatisticsRequest();
-                OFMatch match = new OFMatch();
-                match.setWildcards(0xffffffff);
-                specificReq.setMatch(match);
-                specificReq.setOutPort(OFPort.OFPP_NONE.getValue());
-                specificReq.setTableId((byte) 0xff);
-                req.setStatistics(Collections.singletonList((OFStatistics)specificReq));
-                requestLength += specificReq.getLength();
-            } else if (statType == OFStatisticsType.PORT) {
-                OFPortStatisticsRequest specificReq = new OFPortStatisticsRequest();
-                specificReq.setPortNumber(OFPort.OFPP_NONE.getValue());
-                req.setStatistics(Collections.singletonList((OFStatistics)specificReq));
-                requestLength += specificReq.getLength();
-            } else if (statType == OFStatisticsType.QUEUE) {
-                OFQueueStatisticsRequest specificReq = new OFQueueStatisticsRequest();
-                specificReq.setPortNumber(OFPort.OFPP_ALL.getValue());
-                // LOOK! openflowj does not define OFPQ_ALL! pulled this from openflow.h
-                // note that I haven't seen this work yet though...
-                specificReq.setQueueId(0xffffffff);
-                req.setStatistics(Collections.singletonList((OFStatistics)specificReq));
-                requestLength += specificReq.getLength();
-            } else if (statType == OFStatisticsType.DESC ||
-                       statType == OFStatisticsType.TABLE) {
+        	OFStatsRequest<?> req;
+            if (statType == OFStatsType.FLOW) {
+            	Match match = sw.getOFFactory().buildMatch().build();
+                req = sw.getOFFactory().buildFlowStatsRequest()
+                		.setMatch(match)
+                		.setOutPort(OFPort.ANY)
+                		.setTableId(TableId.ALL)
+                		.build();
+            } else if (statType == OFStatsType.AGGREGATE) {
+            	Match match = sw.getOFFactory().buildMatch().build();
+                req = sw.getOFFactory().buildAggregateStatsRequest()
+                		.setMatch(match)
+                		.setOutPort(OFPort.ANY)
+                		.setTableId(TableId.ALL)
+                		.build();
+            } else if (statType == OFStatsType.PORT) {
+                req = sw.getOFFactory().buildPortStatsRequest()
+                		.setPortNo(OFPort.ANY)
+                		.build();
+            } else if (statType == OFStatsType.QUEUE) {
+            	req = sw.getOFFactory().buildQueueStatsRequest()
+                		.setPortNo(OFPort.ANY)
+                		.setQueueId(UnsignedLong.MAX_VALUE.longValue())
+                		.build();
+            } else if (statType == OFStatsType.DESC ||
+                       statType == OFStatsType.TABLE) {
                 // pass - nothing todo besides set the type above
+            	req = sw.getOFFactory().buildDescStatsRequest()
+            			.build();
+            } else {
+            	//TODO @Ryan what to do about no matches in the if...elseif statements?
+            	req = sw.getOFFactory().buildDescStatsRequest().build();
             }
-            req.setLengthU(requestLength);
             try {
-                future = sw.queryStatistics(req);
-                values = future.get(10, TimeUnit.SECONDS);
+                future = sw.writeStatsRequest(req);
+                values = (List<OFStatsReply>) future.get(10, TimeUnit.SECONDS);
             } catch (Exception e) {
                 log.error("Failure retrieving statistics from switch " + sw, e);
             }
@@ -126,21 +130,24 @@ public class SwitchResourceBase extends ServerResource {
         return values;
     }
 
-    protected List<OFStatistics> getSwitchStatistics(String switchId, OFStatisticsType statType) {
-        return getSwitchStatistics(HexString.toLong(switchId), statType);
+    protected List<OFStatsReply> getSwitchStatistics(String switchId, OFStatsType statType) {
+        return getSwitchStatistics(DatapathId.of(switchId), statType);
     }
 
-    protected OFFeaturesReply getSwitchFeaturesReply(long switchId) {
-        IFloodlightProviderService floodlightProvider =
-                (IFloodlightProviderService)getContext().getAttributes().
-                get(IFloodlightProviderService.class.getCanonicalName());
+    protected OFFeaturesReply getSwitchFeaturesReply(DatapathId switchId) {
+        IOFSwitchService switchService =
+                (IOFSwitchService) getContext().getAttributes().
+                get(IOFSwitchService.class.getCanonicalName());
 
-        IOFSwitch sw = floodlightProvider.getSwitch(switchId);
+        IOFSwitch sw = switchService.getSwitch(switchId);
         Future<OFFeaturesReply> future;
         OFFeaturesReply featuresReply = null;
+        //TODO @Ryan The only thing to set in an OFFeaturesRequest is the XID. I'm not sure
+        // if it matters what I set it to. Will it have a default value of the next available?
+        OFFeaturesRequest featuresRequest = sw.getOFFactory().buildFeaturesRequest().build();
         if (sw != null) {
             try {
-                future = sw.querySwitchFeaturesReply();
+                future = sw.writeRequest(featuresRequest);
                 featuresReply = future.get(10, TimeUnit.SECONDS);
             } catch (Exception e) {
                 log.error("Failure getting features reply from switch" + sw, e);
@@ -151,7 +158,7 @@ public class SwitchResourceBase extends ServerResource {
     }
 
     protected OFFeaturesReply getSwitchFeaturesReply(String switchId) {
-        return getSwitchFeaturesReply(HexString.toLong(switchId));
+        return getSwitchFeaturesReply(DatapathId.of(switchId));
     }
 
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
index e6d66e2c24db29bad055be5d9a0132778e7ffe87..45d9bc12fefcf6c10dd683cb1e4f6bdc066bd9a0 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
@@ -18,12 +18,13 @@ package net.floodlightcontroller.core.web;
 
 import java.util.HashMap;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
 import org.restlet.resource.ServerResource;
 
-import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.HARole;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.RoleInfo;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 
 import org.restlet.resource.Get;
 import org.slf4j.Logger;
@@ -35,9 +36,9 @@ public class SwitchRoleResource extends ServerResource {
 
     @Get("json")
     public Object getRole() {
-        IFloodlightProviderService floodlightProvider =
-                (IFloodlightProviderService)getContext().getAttributes().
-                    get(IFloodlightProviderService.class.getCanonicalName());
+    	IOFSwitchService switchService =
+                (IOFSwitchService)getContext().getAttributes().
+                    get(IOFSwitchService.class.getCanonicalName());
 
         String switchId = (String) getRequestAttributes().get("switchId");
 
@@ -45,19 +46,21 @@ public class SwitchRoleResource extends ServerResource {
 
         if (switchId.equalsIgnoreCase("all")) {
             HashMap<String,RoleInfo> model = new HashMap<String,RoleInfo>();
-            for (IOFSwitch sw: floodlightProvider.getAllSwitchMap().values()) {
-                switchId = sw.getStringId();
-                roleInfo = new RoleInfo(sw.getHARole(), null);
+            for (IOFSwitch sw: switchService.getAllSwitchMap().values()) {
+                switchId = sw.getId().toString();
+                //TODO @Ryan not sure what the changeDescription string should be here.
+                roleInfo = new RoleInfo(HARole.ofOFRole(sw.getControllerRole()), "", null);
                 model.put(switchId, roleInfo);
             }
             return model;
         }
 
-        Long dpid = HexString.toLong(switchId);
-        IOFSwitch sw = floodlightProvider.getSwitch(dpid);
+        DatapathId dpid = DatapathId.of(switchId);
+        IOFSwitch sw = switchService.getSwitch(dpid);
         if (sw == null)
             return null;
-        roleInfo = new RoleInfo(sw.getHARole(), null);
+        //TODO @Ryan not sure what the changeDescription string should be here.
+        roleInfo = new RoleInfo(HARole.ofOFRole(sw.getControllerRole()), "", null);
         return roleInfo;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
index 57771f718bfa51295220deb2a3d9e0e88c4223e3..a70d120ae59ff618d8ae57a3b59601cb2e66bbec 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
@@ -20,7 +20,8 @@ package net.floodlightcontroller.core.web;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.openflow.protocol.statistics.OFStatisticsType;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.types.DatapathId;
 import org.restlet.resource.Get;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,17 +43,17 @@ public class SwitchStatisticsResource extends SwitchResourceBase {
         String statType = (String) getRequestAttributes().get("statType");
         
         if (statType.equals("port")) {
-            values = getSwitchStatistics(switchId, OFStatisticsType.PORT);
+            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.PORT);
         } else if (statType.equals("queue")) {
-            values = getSwitchStatistics(switchId, OFStatisticsType.QUEUE);
+            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.QUEUE);
         } else if (statType.equals("flow")) {
-            values = getSwitchStatistics(switchId, OFStatisticsType.FLOW);
+            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.FLOW);
         } else if (statType.equals("aggregate")) {
-            values = getSwitchStatistics(switchId, OFStatisticsType.AGGREGATE);
+            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.AGGREGATE);
         } else if (statType.equals("desc")) {
-            values = getSwitchStatistics(switchId, OFStatisticsType.DESC);
+            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.DESC);
         } else if (statType.equals("table")) {
-            values = getSwitchStatistics(switchId, OFStatisticsType.TABLE);
+            values = getSwitchStatistics(DatapathId.of(switchId), OFStatsType.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 ce4d3ba3c51480ad3ab3b488c398727efb6d85b4..f5f3aea8c93f9a5769ad3eb8aa536755cf83e802 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.openflow.util.HexString;
+import org.projectfloodlight.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 6df067ead245a209b12ce20347c237913a8f7b29..d07a254680074dc53bcd4095bf7dca98b39253e0 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.openflow.util.HexString;
+import org.projectfloodlight.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 c797681edf2e8779365293188e89f51b9b4c30a1..c7ea09b8364fa9b6e740da82b2a3f55ec6458fb8 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.openflow.util.HexString;
+import org.projectfloodlight.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
deleted file mode 100644
index bfe3b963f82b61bc0529005e4edd5b1f0b4d5164..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/counter/CounterStore.java
+++ /dev/null
@@ -1,579 +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.counter;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-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;
-import net.floodlightcontroller.core.module.IFloodlightModule;
-import net.floodlightcontroller.core.module.IFloodlightService;
-import net.floodlightcontroller.counter.CounterValue.CounterType;
-import net.floodlightcontroller.packet.Ethernet;
-import net.floodlightcontroller.packet.IPv4;
-
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Implements a central store for system counters. These counters include
- * overall packet-in, packet-out, and flow-mod counters. Additional packet-in
- * counters are maintained for bcast/unicast/multicast traffic, as well as counters
- * for traffic types based on ethertype and ip-proto (maintained on a per switch
- * and controller level). These counters are maintained without the involvement of
- * any other module in the system. For per-module counters and other detailed
- * debug services, consider IDebugCounterService.
- *
- *  @authors Kyle, Kanzhe, Mandeep and Saurav
- */
-public class CounterStore implements IFloodlightModule, ICounterStoreService {
-    protected static Logger log = LoggerFactory.getLogger(CounterStore.class);
-
-    public enum NetworkLayer {
-        L2, L3, L4
-    }
-
-    protected class CounterEntry {
-        protected ICounter counter;
-        String title;
-    }
-
-    protected class MutableInt {
-          int value = 0;
-          public void increment() { value += 1; }
-          public int get() { return value; }
-          public void set(int val) { value = val; }
-        }
-
-    protected class CounterKeyTuple {
-        byte msgType;
-        long dpid;
-        short l3type;
-        byte l4type;
-
-        public CounterKeyTuple(byte msgType, long dpid, short l3type, byte l4type){
-            this.msgType = msgType;
-            this.dpid = dpid;
-            this.l3type = l3type;
-            this.l4type = l4type;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) return true;
-            if (obj == null) return false;
-            if (!(obj instanceof CounterKeyTuple)) return false;
-            CounterKeyTuple other = (CounterKeyTuple) obj;
-            if (this.msgType == other.msgType &&
-                this.dpid == other.dpid &&
-                this.l3type == other.l3type &&
-                this.l4type == other.l4type)
-                    return true;
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 283;
-            int result = 1;
-            result = prime * result + msgType;
-            result = prime * result + (int) (dpid ^ (dpid >>> 32));
-            result = prime * result + l3type;
-            result = prime * result + l4type;
-            return result;
-        }
-    }
-
-    /**
-     * Counter storage across all threads. These are periodically updated from the
-     * local per thread counters by the updateFlush method.
-     */
-    protected ConcurrentHashMap<CounterKeyTuple, List<ICounter>>
-        pktinCounters = new ConcurrentHashMap<CounterKeyTuple, List<ICounter>>();
-    protected ConcurrentHashMap<CounterKeyTuple, List<ICounter>>
-        pktoutCounters = new ConcurrentHashMap<CounterKeyTuple, List<ICounter>>();
-
-    /**
-     * Thread local counter stores
-     */
-    protected final ThreadLocal<Map<CounterKeyTuple,MutableInt>> pktin_local_buffer =
-        new ThreadLocal<Map<CounterKeyTuple,MutableInt>>() {
-        @Override
-        protected Map<CounterKeyTuple,MutableInt> initialValue() {
-            return new HashMap<CounterKeyTuple,MutableInt>();
-        }
-    };
-
-    protected final ThreadLocal<Map<CounterKeyTuple,MutableInt>> pktout_local_buffer =
-        new ThreadLocal<Map<CounterKeyTuple,MutableInt>>() {
-        @Override
-        protected Map<CounterKeyTuple,MutableInt> initialValue() {
-            return new HashMap<CounterKeyTuple,MutableInt>();
-        }
-    };
-
-    /**
-     * A cache of counterName --> Counter used to retrieve counters quickly via
-     * string-counter-keys
-     */
-    protected ConcurrentHashMap<String, CounterEntry> nameToCEIndex =
-            new ConcurrentHashMap<String, CounterEntry>();
-
-    /**
-     * Counter Categories grouped by network layers
-     * NetworkLayer -> CounterToCategories
-     */
-    protected static Map<NetworkLayer, Map<String, List<String>>> layeredCategories =
-            new ConcurrentHashMap<NetworkLayer, Map<String, List<String>>> ();
-
-    //*******************************
-    //   ICounterStoreService
-    //*******************************
-
-    @Override
-    public void updatePacketInCountersLocal(IOFSwitch sw, OFMessage m, Ethernet eth) {
-        if (((OFPacketIn)m).getPacketData().length <= 0) {
-            return;
-        }
-        CounterKeyTuple countersKey = this.getCountersKey(sw, m, eth);
-        Map<CounterKeyTuple, MutableInt> pktin_buffer = this.pktin_local_buffer.get();
-        MutableInt currval = pktin_buffer.get(countersKey);
-
-        if (currval == null) {
-            this.createPacketInCounters(sw, m, eth); // create counters as side effect (if required)
-            currval = new MutableInt();
-            pktin_buffer.put(countersKey, currval);
-        }
-        currval.increment();
-        return;
-    }
-
-    @Override
-    public void updatePktOutFMCounterStoreLocal(IOFSwitch sw, OFMessage m) {
-        CounterKeyTuple countersKey = this.getCountersKey(sw, m, null);
-        Map<CounterKeyTuple, MutableInt> pktout_buffer = this.pktout_local_buffer.get();
-        MutableInt currval = pktout_buffer.get(countersKey);
-
-        if (currval == null) {
-            this.getPktOutFMCounters(sw, m); // create counters as side effect (if required)
-            currval = new MutableInt();
-            pktout_buffer.put(countersKey, currval);
-        }
-        currval.increment();
-        return;
-    }
-
-    @Override
-    public void updateFlush() {
-        Date date = new Date();
-        Map<CounterKeyTuple, MutableInt> pktin_buffer = this.pktin_local_buffer.get();
-        for (CounterKeyTuple key : pktin_buffer.keySet()) {
-                MutableInt currval = pktin_buffer.get(key);
-                int delta = currval.get();
-
-                if (delta > 0) {
-                    List<ICounter> counters = this.pktinCounters.get(key);
-                    if (counters != null) {
-                        for (ICounter c : counters) {
-                            c.increment(date, delta);
-                        }
-                    }
-                }
-        }
-        // We could do better "GC" of counters that have not been update "recently"
-        pktin_buffer.clear();
-
-        Map<CounterKeyTuple, MutableInt> pktout_buffer = this.pktout_local_buffer.get();
-        for (CounterKeyTuple key : pktout_buffer.keySet()) {
-                MutableInt currval = pktout_buffer.get(key);
-                int delta = currval.get();
-
-                if (delta > 0) {
-                    List<ICounter> counters = this.pktoutCounters.get(key);
-                    if (counters != null) {
-                        for (ICounter c : counters) {
-                            c.increment(date, delta);
-                        }
-                    }
-                }
-        }
-        // We could do better "GC" of counters that have not been update "recently"
-        pktout_buffer.clear();
-    }
-
-    @Override
-    public ICounter createCounter(String key, CounterValue.CounterType type) {
-        CounterEntry ce;
-        ICounter c;
-
-        c = SimpleCounter.createCounter(new Date(), type);
-        ce = new CounterEntry();
-        ce.counter = c;
-        ce.title = key;
-        nameToCEIndex.putIfAbsent(key, ce);
-
-        return nameToCEIndex.get(key).counter;
-    }
-
-    @Override
-    public ICounter getCounter(String key) {
-        CounterEntry counter = nameToCEIndex.get(key);
-        if (counter != null) {
-            return counter.counter;
-        } else {
-            return null;
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see net.floodlightcontroller.counter.ICounterStoreService#getAll()
-     */
-    @Override
-    public Map<String, ICounter> getAll() {
-        Map<String, ICounter> ret = new ConcurrentHashMap<String, ICounter>();
-        for(Map.Entry<String, CounterEntry> counterEntry : this.nameToCEIndex.entrySet()) {
-            String key = counterEntry.getKey();
-            ICounter counter = counterEntry.getValue().counter;
-            ret.put(key, counter);
-        }
-        return ret;
-    }
-
-    @Override
-    public List<String> getAllCategories(String counterName, NetworkLayer layer) {
-        if (layeredCategories.containsKey(layer)) {
-            Map<String, List<String>> counterToCategories = layeredCategories.get(layer);
-            if (counterToCategories.containsKey(counterName)) {
-                return counterToCategories.get(counterName);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Create a title based on switch ID, portID, vlanID, and counterName
-     * If portID is -1, the title represents the given switch only
-     * If portID is a non-negative number, the title represents the port on the given switch
-     */
-    public static String createCounterName(String switchID, int portID, String counterName) {
-        if (portID < 0) {
-            return switchID + TitleDelimitor + counterName;
-        } else {
-            return switchID + TitleDelimitor + portID + TitleDelimitor + counterName;
-        }
-    }
-
-    //*******************************
-    //   Internal Methods
-    //*******************************
-
-    protected CounterKeyTuple getCountersKey(IOFSwitch sw, OFMessage m, Ethernet eth) {
-        byte mtype = m.getType().getTypeValue();
-        short l3type = 0;
-        byte l4type = 0;
-
-        if (eth != null) {
-            l3type = eth.getEtherType();
-            if (eth.getPayload() instanceof IPv4) {
-                IPv4 ipV4 = (IPv4)eth.getPayload();
-                l4type = ipV4.getProtocol();
-            }
-        }
-        return new CounterKeyTuple(mtype, sw.getId(), l3type, l4type);
-    }
-
-    protected List<ICounter> createPacketInCounters(IOFSwitch sw, OFMessage m, Ethernet eth) {
-        /* If possible, find and return counters for this tuple */
-        CounterKeyTuple countersKey = this.getCountersKey(sw, m, eth);
-        List<ICounter> counters =
-                this.pktinCounters.get(countersKey);
-        if (counters != null) {
-                return counters;
-        }
-
-        /*
-         *  Create the required counters
-         */
-        counters = new ArrayList<ICounter>();
-
-        int l3type = eth.getEtherType() & 0xffff;
-        String switchIdHex = sw.getStringId();
-        String etherType = String.format("%04x", eth.getEtherType());
-        String packetName = m.getType().toClass().getName();
-        packetName = packetName.substring(packetName.lastIndexOf('.')+1);
-
-        // L2 Type
-        String l2Type = null;
-        if (eth.isBroadcast()) {
-            l2Type = BROADCAST;
-        }
-        else if (eth.isMulticast()) {
-            l2Type = MULTICAST;
-        }
-        else {
-            l2Type = UNICAST;
-        }
-
-        /*
-         * Use alias for L3 type
-         * Valid EtherType must be greater than or equal to 0x0600
-         * It is V1 Ethernet Frame if EtherType < 0x0600
-         */
-        if (l3type < 0x0600) {
-            etherType = "0599";
-        }
-        if (TypeAliases.l3TypeAliasMap != null &&
-            TypeAliases.l3TypeAliasMap.containsKey(etherType)) {
-            etherType = TypeAliases.l3TypeAliasMap.get(etherType);
-        }
-        else {
-            etherType = "L3_" + etherType;
-        }
-
-        // overall controller packet counter names
-        String controllerCounterName =
-            CounterStore.createCounterName(
-                CONTROLLER_NAME,
-                -1,
-                packetName);
-        counters.add(createCounter(controllerCounterName,
-                                   CounterType.LONG));
-
-        String switchCounterName =
-            CounterStore.createCounterName(
-                switchIdHex,
-                -1,
-                packetName);
-        counters.add(createCounter(switchCounterName,
-                                   CounterType.LONG));
-
-        // L2 counter names
-            String controllerL2CategoryCounterName =
-                CounterStore.createCounterName(
-                    CONTROLLER_NAME,
-                    -1,
-                    packetName,
-                    l2Type,
-                    NetworkLayer.L2);
-            counters.add(createCounter(controllerL2CategoryCounterName,
-                                       CounterType.LONG));
-
-            String switchL2CategoryCounterName =
-                CounterStore.createCounterName(
-                    switchIdHex,
-                    -1,
-                    packetName,
-                    l2Type,
-                    NetworkLayer.L2);
-            counters.add(createCounter(switchL2CategoryCounterName,
-                                       CounterType.LONG));
-
-        // L3 counter names
-            String controllerL3CategoryCounterName =
-                CounterStore.createCounterName(
-                    CONTROLLER_NAME,
-                    -1,
-                    packetName,
-                    etherType,
-                    NetworkLayer.L3);
-            counters.add(createCounter(controllerL3CategoryCounterName,
-                                       CounterType.LONG));
-
-            String switchL3CategoryCounterName =
-                CounterStore.createCounterName(
-                    switchIdHex,
-                    -1,
-                    packetName,
-                    etherType,
-                    NetworkLayer.L3);
-            counters.add(createCounter(switchL3CategoryCounterName,
-                                       CounterType.LONG));
-
-        // L4 counters
-        if (eth.getPayload() instanceof IPv4) {
-
-            // resolve protocol alias
-            IPv4 ipV4 = (IPv4)eth.getPayload();
-            String l4name = String.format("%02x", ipV4.getProtocol());
-            if (TypeAliases.l4TypeAliasMap != null &&
-                TypeAliases.l4TypeAliasMap.containsKey(l4name)) {
-                l4name = TypeAliases.l4TypeAliasMap.get(l4name);
-            }
-            else {
-                l4name = "L4_" + l4name;
-            }
-
-            // create counters
-            String controllerL4CategoryCounterName =
-                CounterStore.createCounterName(
-                    CONTROLLER_NAME,
-                    -1,
-                    packetName,
-                    l4name,
-                    NetworkLayer.L4);
-            counters.add(createCounter(controllerL4CategoryCounterName,
-                                       CounterType.LONG));
-
-            String switchL4CategoryCounterName =
-                CounterStore.createCounterName(
-                    switchIdHex,
-                    -1,
-                    packetName,
-                    l4name,
-                    NetworkLayer.L4);
-            counters.add(createCounter(switchL4CategoryCounterName,
-                                       CounterType.LONG));
-
-        }
-
-        /* Add to map and return */
-        this.pktinCounters.putIfAbsent(countersKey, counters);
-        return this.pktinCounters.get(countersKey);
-    }
-
-    protected List<ICounter> getPktOutFMCounters(IOFSwitch sw, OFMessage m) {
-        /* If possible, find and return counters for this tuple */
-        CounterKeyTuple countersKey = this.getCountersKey(sw, m, null);
-        List<ICounter> counters =
-            this.pktoutCounters.get(countersKey);
-        if (counters != null) {
-            return counters;
-        }
-
-        /*
-         *  Create the required counters
-         */
-        counters = new ArrayList<ICounter>();
-
-        /* String values for names */
-        String switchIdHex = sw.getStringId();
-        String packetName = m.getType().toClass().getName();
-        packetName = packetName.substring(packetName.lastIndexOf('.')+1);
-
-        String controllerFMCounterName =
-            CounterStore.createCounterName(
-                CONTROLLER_NAME,
-                -1,
-                packetName);
-        counters.add(createCounter(controllerFMCounterName,
-                                   CounterValue.CounterType.LONG));
-
-        String switchFMCounterName =
-            CounterStore.createCounterName(
-                switchIdHex,
-                -1,
-                packetName);
-        counters.add(createCounter(switchFMCounterName,
-                                   CounterValue.CounterType.LONG));
-
-        /* Add to map and return */
-        this.pktoutCounters.putIfAbsent(countersKey, counters);
-        return this.pktoutCounters.get(countersKey);
-
-    }
-
-    /**
-     * Create a title based on switch ID, portID, vlanID, counterName, and subCategory
-     * If portID is -1, the title represents the given switch only
-     * If portID is a non-negative number, the title represents the port on the given switch
-     * For example: PacketIns can be further categorized based on L2 etherType or L3 protocol
-     */
-    protected static String createCounterName(String switchID, int portID, String counterName,
-            String subCategory, NetworkLayer layer) {
-        String fullCounterName = "";
-        String groupCounterName = "";
-
-        if (portID < 0) {
-            groupCounterName = switchID + TitleDelimitor + counterName;
-            fullCounterName = groupCounterName + TitleDelimitor + subCategory;
-        } else {
-            groupCounterName = switchID + TitleDelimitor + portID + TitleDelimitor + counterName;
-            fullCounterName = groupCounterName + TitleDelimitor + subCategory;
-        }
-
-        Map<String, List<String>> counterToCategories;
-        if (layeredCategories.containsKey(layer)) {
-            counterToCategories = layeredCategories.get(layer);
-        } else {
-            counterToCategories = new ConcurrentHashMap<String, List<String>> ();
-            layeredCategories.put(layer, counterToCategories);
-        }
-
-        List<String> categories;
-        if (counterToCategories.containsKey(groupCounterName)) {
-            categories = counterToCategories.get(groupCounterName);
-        } else {
-            categories = new ArrayList<String>();
-            counterToCategories.put(groupCounterName, categories);
-        }
-
-        if (!categories.contains(subCategory)) {
-            categories.add(subCategory);
-        }
-        return fullCounterName;
-    }
-
-    //*******************************
-    //   IFloodlightProvider
-    //*******************************
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> services =
-                new ArrayList<Class<? extends IFloodlightService>>(1);
-        services.add(ICounterStoreService.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(ICounterStoreService.class, this);
-        return m;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
-        // no-op, no dependencies
-        return null;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context)
-                                 throws FloodlightModuleException {
-        // no-op for now
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        // no-op for now
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/counter/CounterValue.java b/src/main/java/net/floodlightcontroller/counter/CounterValue.java
deleted file mode 100644
index 1852d5cc5b7a4dc9e7fcd841c4c9764e67f66084..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/counter/CounterValue.java
+++ /dev/null
@@ -1,102 +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.counter;
-
-/**
- * The class defines the counter value type and value
- * 
- * @author Kanzhe
- *
- */
-public class CounterValue { 
-  public enum CounterType {
-      LONG,
-      DOUBLE
-  }
-  
-  protected CounterType type; 
-  protected long longValue;
-  protected double doubleValue;
-  
-  public CounterValue(CounterType type) {
-    this.type = CounterType.LONG;
-    this.longValue = 0;    
-    this.doubleValue = 0.0;
-  }
-  
-  /**
-   * This method is only applicable to type long.
-   * Setter() should be used for type double
-   */
-  public void increment(long delta) {
-      if (this.type == CounterType.LONG) {
-          this.longValue += delta;
-      } else {
-          throw new IllegalArgumentException("Invalid counter type. This counter is not a long type.");
-      }
-  }
-  
-  public void setLongValue(long value) {
-      if (this.type == CounterType.LONG) {
-          this.longValue = value;
-      } else {
-          throw new IllegalArgumentException("Invalid counter type. This counter is not a long type.");
-      }
-  }
-  
-  public void setDoubleValue(double value) {
-      if (this.type == CounterType.DOUBLE) {
-          this.doubleValue = value;
-      } else {
-          throw new IllegalArgumentException("Invalid counter type. This counter is not a double type.");
-      }
-  }
-  
-  public long getLong() {
-      if (this.type == CounterType.LONG) {
-          return this.longValue;
-      } else {
-          throw new IllegalArgumentException("Invalid counter type. This counter is not a long type.");
-      }
-  }
-  
-  public double getDouble() {
-      if (this.type == CounterType.DOUBLE) {
-          return this.doubleValue;
-      } else {
-          throw new IllegalArgumentException("Invalid counter type. This counter is not a double type.");
-      }
-  }
-  
-
-  public CounterType getType() {
-    return this.type;
-  }
-  
-  public String toString() {
-    String ret = "{type: ";
-    if (this.type == CounterType.DOUBLE) {
-        ret += "Double" + ", value: " + this.doubleValue + "}";
-    } else {
-        ret += "Long" + ", value: " + this.longValue + "}";
-    }
-    return ret;
-  }
-
-
-}
diff --git a/src/main/java/net/floodlightcontroller/counter/ICounter.java b/src/main/java/net/floodlightcontroller/counter/ICounter.java
deleted file mode 100644
index 0e31fdecd6a75419b9ccab92cd4a94e33f6f8cda..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/counter/ICounter.java
+++ /dev/null
@@ -1,71 +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.
-**/
-
-/**
- * Simple interface for a counter whose value can be retrieved in several different
- * time increments (last x seconds, minutes, hours, days)
- */
-package net.floodlightcontroller.counter;
-
-import java.util.Date;
-
-/**
- * @author kyle
- *
- */
-public interface ICounter {
-
-  /**
-   * Most commonly used method
-   */
-  public void increment();
-
-  /**
-   * Used primarily for flushing thread local updates
-   */
-  public void increment(Date d, long delta);
-
-  /**
-   * Counter value setter
-   */
-  public void setCounter(Date d, CounterValue value);
-
-  /**
-   * Return the most current value
-   */
-  public Date getCounterDate();
-
-  /**
-   * Return the most current value
-   */
-  public CounterValue getCounterValue();
-
-  /**
-   * Reset the value
-   */
-  public void reset(Date d);
-
-
-  public static enum DateSpan {
-    REALTIME,
-    SECONDS,
-    MINUTES,
-    HOURS,
-    DAYS,
-    WEEKS
-  }
-}
diff --git a/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java b/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java
deleted file mode 100644
index c0cbd55916086103bb4df820ca1b33974ed3dcca..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/counter/ICounterStoreService.java
+++ /dev/null
@@ -1,93 +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.counter;
-
-import java.util.List;
-import java.util.Map;
-
-import org.openflow.protocol.OFMessage;
-
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.module.IFloodlightService;
-import net.floodlightcontroller.counter.CounterStore.NetworkLayer;
-import net.floodlightcontroller.packet.Ethernet;
-
-public interface ICounterStoreService extends IFloodlightService {
-
-	public final static String CONTROLLER_NAME = "controller";
-    public final static String TitleDelimitor = "__";
-
-    /** Broadcast and multicast */
-    public final static String BROADCAST = "broadcast";
-    public final static String MULTICAST = "multicast";
-    public final static String UNICAST = "unicast";
-
-    /** L2 EtherType subCategories */
-    public final static String L3ET_IPV4 = "L3_IPv4";
-
-    /**
-     * Update packetIn counters
-     *
-     * @param sw
-     * @param m
-     * @param eth
-     */
-    public void updatePacketInCountersLocal(IOFSwitch sw, OFMessage m, Ethernet eth);
-
-    /**
-     * This method can only be used to update packetOut and flowmod counters
-     *
-     * @param sw
-     * @param ofMsg
-     */
-    public void updatePktOutFMCounterStoreLocal(IOFSwitch sw, OFMessage ofMsg);
-
-    /**
-     * Flush Local Counter Updates
-     *
-     */
-    public void updateFlush();
-
-    /**
-     * Retrieve a list of subCategories by counterName.
-     * null if nothing.
-     */
-    public List<String> getAllCategories(String counterName,
-                                         NetworkLayer layer);
-
-    /**
-     * Create a new ICounter and set the title.  Note that the title must be
-     * unique, otherwise this will throw an IllegalArgumentException.
-     *
-     * @param key
-     * @param type
-     * @return
-     */
-    public ICounter createCounter(String key, CounterValue.CounterType type);
-
-    /**
-     * Retrieves a counter with the given title, or null if none can be found.
-     */
-    public ICounter getCounter(String key);
-
-    /**
-     * Returns an immutable map of title:counter with all of the counters in the store.
-     *
-     * (Note - this method may be slow - primarily for debugging/UI)
-     */
-    public Map<String, ICounter> getAll();
-}
diff --git a/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java b/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java
deleted file mode 100644
index bdcc690b349c4497d8ca7b645b23a03d3af2ce85..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/counter/NullCounterStore.java
+++ /dev/null
@@ -1,125 +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.counter;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.openflow.protocol.OFMessage;
-
-import net.floodlightcontroller.core.IOFSwitch;
-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.counter.CounterStore.NetworkLayer;
-import net.floodlightcontroller.counter.CounterValue.CounterType;
-import net.floodlightcontroller.packet.Ethernet;
-
-/**
- * An ICounsterStoreService implementation that does nothing.
- * This is used mainly for performance testing or if you don't
- * want to use the counterstore.
- * @author alexreimers
- *
- */
-public class NullCounterStore implements IFloodlightModule,
-        ICounterStoreService {
-
-    private ICounter emptyCounter;
-    private List<String> emptyList;
-    private Map<String, ICounter> emptyMap;
-
-    @Override
-    public void updatePacketInCountersLocal(IOFSwitch sw, OFMessage m, Ethernet eth) {
-        // no-op
-    }
-
-    @Override
-    public void updatePktOutFMCounterStoreLocal(IOFSwitch sw, OFMessage ofMsg) {
-        // no-op
-    }
-
-    @Override
-    public void updateFlush() {
-        // no-op
-    }
-
-    @Override
-    public List<String>
-            getAllCategories(String counterName, NetworkLayer layer) {
-        return emptyList;
-    }
-
-    @Override
-    public ICounter createCounter(String key, CounterType type) {
-        return emptyCounter;
-    }
-
-    @Override
-    public ICounter getCounter(String key) {
-        return emptyCounter;
-    }
-
-    @Override
-    public Map<String, ICounter> getAll() {
-        return emptyMap;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> services =
-                new ArrayList<Class<? extends IFloodlightService>>(1);
-        services.add(ICounterStoreService.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(ICounterStoreService.class, this);
-        return m;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleDependencies() {
-        // None, return null
-        return null;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context)
-                             throws FloodlightModuleException {
-        emptyCounter = new SimpleCounter(new Date(), CounterType.LONG);
-        emptyList = new ArrayList<String>();
-        emptyMap = new HashMap<String, ICounter>();
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        // no-op
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/counter/SimpleCounter.java b/src/main/java/net/floodlightcontroller/counter/SimpleCounter.java
deleted file mode 100644
index dd0daf31797ace63ad0d1c8004ec8b016cb19dc9..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/counter/SimpleCounter.java
+++ /dev/null
@@ -1,129 +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.counter;
-
-import java.util.Date;
-
-
-
-/**
- * This is a simple counter implementation that doesn't support data series.
- * The idea is that floodlight only keeps the realtime value for each counter,
- * statd, a statistics collection daemon, samples counters at a user-defined interval
- * and pushes the values to a database, which keeps time-based data series.
- * @author Kanzhe
- *
- */
-public class SimpleCounter implements ICounter {
-
-  protected CounterValue counter;
-  protected Date samplingTime;
-  protected Date startDate;
-
-  /**
-   * Factory method to create a new counter instance.
-   *
-   * @param startDate
-   * @return
-   */
-  public static ICounter createCounter(Date startDate, CounterValue.CounterType type) {
-    SimpleCounter cc = new SimpleCounter(startDate, type);
-    return cc;
-  }
-
-  /**
-   * Factory method to create a copy of a counter instance.
-   *
-   * @param startDate
-   * @return
-   */
-  public static ICounter createCounter(ICounter copy) {
-    if (copy == null ||
-        copy.getCounterDate() == null ||
-        copy.getCounterValue() == null) {
-        return null;
-    }
-
-     SimpleCounter cc = new SimpleCounter(copy.getCounterDate(),
-            copy.getCounterValue().getType());
-     cc.setCounter(copy.getCounterDate(), copy.getCounterValue());
-     return cc;
-  }
-
-  /**
-   * Protected constructor - use createCounter factory method instead
-   * @param startDate
-   */
-  protected SimpleCounter(Date startDate, CounterValue.CounterType type) {
-    init(startDate, type);
-  }
-
-  protected void init(Date startDate, CounterValue.CounterType type) {
-    this.startDate = startDate;
-    this.samplingTime = new Date();
-    this.counter = new CounterValue(type);
-  }
-
-  /**
-   * This is the key method that has to be both fast and very thread-safe.
-   */
-  @Override
-  synchronized public void increment() {
-    this.increment(new Date(), 1);
-  }
-
-  @Override
-  synchronized public void increment(Date d, long delta) {
-    this.samplingTime = d;
-    this.counter.increment(delta);
-  }
-
-  @Override
-synchronized public void setCounter(Date d, CounterValue value) {
-      this.samplingTime = d;
-      this.counter = value;
-  }
-
-  /**
-   * This is the method to retrieve the current value.
-   */
-  @Override
-  synchronized public CounterValue getCounterValue() {
-    return this.counter;
-  }
-
-  /**
-   * This is the method to retrieve the last sampling time.
-   */
-  @Override
-  synchronized public Date getCounterDate() {
-    return this.samplingTime;
-  }
-
-  /**
-   * Reset value.
-   */
-  @Override
-  synchronized public void reset(Date startDate) {
-    init(startDate, this.counter.getType());
-  }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/counter/TypeAliases.java b/src/main/java/net/floodlightcontroller/counter/TypeAliases.java
deleted file mode 100644
index b88c50256be82274bd1cb4aaf68392ed315a87b3..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/counter/TypeAliases.java
+++ /dev/null
@@ -1,206 +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.counter;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Class to contain some statically initialized data
- * @author readams
- *
- */
-public class TypeAliases {
-    protected static final Map<String,String> l3TypeAliasMap = 
-            new HashMap<String, String>();
-    static {
-        l3TypeAliasMap.put("0599", "L3_V1Ether");
-        l3TypeAliasMap.put("0800", "L3_IPv4");
-        l3TypeAliasMap.put("0806", "L3_ARP");
-        l3TypeAliasMap.put("8035", "L3_RARP");
-        l3TypeAliasMap.put("809b", "L3_AppleTalk");
-        l3TypeAliasMap.put("80f3", "L3_AARP");
-        l3TypeAliasMap.put("8100", "L3_802_1Q");
-        l3TypeAliasMap.put("8137", "L3_Novell_IPX");
-        l3TypeAliasMap.put("8138", "L3_Novell");
-        l3TypeAliasMap.put("86dd", "L3_IPv6");
-        l3TypeAliasMap.put("8847", "L3_MPLS_uni");
-        l3TypeAliasMap.put("8848", "L3_MPLS_multi");
-        l3TypeAliasMap.put("8863", "L3_PPPoE_DS");
-        l3TypeAliasMap.put("8864", "L3_PPPoE_SS");
-        l3TypeAliasMap.put("886f", "L3_MSFT_NLB");
-        l3TypeAliasMap.put("8870", "L3_Jumbo");
-        l3TypeAliasMap.put("889a", "L3_HyperSCSI");
-        l3TypeAliasMap.put("88a2", "L3_ATA_Ethernet");
-        l3TypeAliasMap.put("88a4", "L3_EtherCAT");
-        l3TypeAliasMap.put("88a8", "L3_802_1ad");
-        l3TypeAliasMap.put("88ab", "L3_Ether_Powerlink");
-        l3TypeAliasMap.put("88cc", "L3_LLDP");
-        l3TypeAliasMap.put("88cd", "L3_SERCOS_III");
-        l3TypeAliasMap.put("88e5", "L3_802_1ae");
-        l3TypeAliasMap.put("88f7", "L3_IEEE_1588");
-        l3TypeAliasMap.put("8902", "L3_802_1ag_CFM");
-        l3TypeAliasMap.put("8906", "L3_FCoE");
-        l3TypeAliasMap.put("9000", "L3_Loop");
-        l3TypeAliasMap.put("9100", "L3_Q_in_Q");
-        l3TypeAliasMap.put("cafe", "L3_LLT");
-    }
-    
-    protected static final Map<String,String> l4TypeAliasMap = 
-            new HashMap<String, String>();
-    static {
-        l4TypeAliasMap.put("00", "L4_HOPOPT");
-        l4TypeAliasMap.put("01", "L4_ICMP");
-        l4TypeAliasMap.put("02", "L4_IGAP_IGMP_RGMP");
-        l4TypeAliasMap.put("03", "L4_GGP");
-        l4TypeAliasMap.put("04", "L4_IP");
-        l4TypeAliasMap.put("05", "L4_ST");
-        l4TypeAliasMap.put("06", "L4_TCP");
-        l4TypeAliasMap.put("07", "L4_UCL");
-        l4TypeAliasMap.put("08", "L4_EGP");
-        l4TypeAliasMap.put("09", "L4_IGRP");
-        l4TypeAliasMap.put("0a", "L4_BBN");
-        l4TypeAliasMap.put("0b", "L4_NVP");
-        l4TypeAliasMap.put("0c", "L4_PUP");
-        l4TypeAliasMap.put("0d", "L4_ARGUS");
-        l4TypeAliasMap.put("0e", "L4_EMCON");
-        l4TypeAliasMap.put("0f", "L4_XNET");
-        l4TypeAliasMap.put("10", "L4_Chaos");
-        l4TypeAliasMap.put("11", "L4_UDP");
-        l4TypeAliasMap.put("12", "L4_TMux");
-        l4TypeAliasMap.put("13", "L4_DCN");
-        l4TypeAliasMap.put("14", "L4_HMP");
-        l4TypeAliasMap.put("15", "L4_Packet_Radio");
-        l4TypeAliasMap.put("16", "L4_XEROX_NS_IDP");
-        l4TypeAliasMap.put("17", "L4_Trunk_1");
-        l4TypeAliasMap.put("18", "L4_Trunk_2");
-        l4TypeAliasMap.put("19", "L4_Leaf_1");
-        l4TypeAliasMap.put("1a", "L4_Leaf_2");
-        l4TypeAliasMap.put("1b", "L4_RDP");
-        l4TypeAliasMap.put("1c", "L4_IRTP");
-        l4TypeAliasMap.put("1d", "L4_ISO_TP4");
-        l4TypeAliasMap.put("1e", "L4_NETBLT");
-        l4TypeAliasMap.put("1f", "L4_MFE");
-        l4TypeAliasMap.put("20", "L4_MERIT");
-        l4TypeAliasMap.put("21", "L4_DCCP");
-        l4TypeAliasMap.put("22", "L4_Third_Party_Connect");
-        l4TypeAliasMap.put("23", "L4_IDPR");
-        l4TypeAliasMap.put("24", "L4_XTP");
-        l4TypeAliasMap.put("25", "L4_Datagram_Delivery");
-        l4TypeAliasMap.put("26", "L4_IDPR");
-        l4TypeAliasMap.put("27", "L4_TP");
-        l4TypeAliasMap.put("28", "L4_ILTP");
-        l4TypeAliasMap.put("29", "L4_IPv6_over_IPv4");
-        l4TypeAliasMap.put("2a", "L4_SDRP");
-        l4TypeAliasMap.put("2b", "L4_IPv6_RH");
-        l4TypeAliasMap.put("2c", "L4_IPv6_FH");
-        l4TypeAliasMap.put("2d", "L4_IDRP");
-        l4TypeAliasMap.put("2e", "L4_RSVP");
-        l4TypeAliasMap.put("2f", "L4_GRE");
-        l4TypeAliasMap.put("30", "L4_DSR");
-        l4TypeAliasMap.put("31", "L4_BNA");
-        l4TypeAliasMap.put("32", "L4_ESP");
-        l4TypeAliasMap.put("33", "L4_AH");
-        l4TypeAliasMap.put("34", "L4_I_NLSP");
-        l4TypeAliasMap.put("35", "L4_SWIPE");
-        l4TypeAliasMap.put("36", "L4_NARP");
-        l4TypeAliasMap.put("37", "L4_Minimal_Encapsulation");
-        l4TypeAliasMap.put("38", "L4_TLSP");
-        l4TypeAliasMap.put("39", "L4_SKIP");
-        l4TypeAliasMap.put("3a", "L4_ICMPv6");
-        l4TypeAliasMap.put("3b", "L4_IPv6_No_Next_Header");
-        l4TypeAliasMap.put("3c", "L4_IPv6_Destination_Options");
-        l4TypeAliasMap.put("3d", "L4_Any_host_IP");
-        l4TypeAliasMap.put("3e", "L4_CFTP");
-        l4TypeAliasMap.put("3f", "L4_Any_local");
-        l4TypeAliasMap.put("40", "L4_SATNET");
-        l4TypeAliasMap.put("41", "L4_Kryptolan");
-        l4TypeAliasMap.put("42", "L4_MIT_RVDP");
-        l4TypeAliasMap.put("43", "L4_Internet_Pluribus");
-        l4TypeAliasMap.put("44", "L4_Distributed_FS");
-        l4TypeAliasMap.put("45", "L4_SATNET");
-        l4TypeAliasMap.put("46", "L4_VISA");
-        l4TypeAliasMap.put("47", "L4_IP_Core");
-        l4TypeAliasMap.put("4a", "L4_Wang_Span");
-        l4TypeAliasMap.put("4b", "L4_Packet_Video");
-        l4TypeAliasMap.put("4c", "L4_Backroom_SATNET");
-        l4TypeAliasMap.put("4d", "L4_SUN_ND");
-        l4TypeAliasMap.put("4e", "L4_WIDEBAND_Monitoring");
-        l4TypeAliasMap.put("4f", "L4_WIDEBAND_EXPAK");
-        l4TypeAliasMap.put("50", "L4_ISO_IP");
-        l4TypeAliasMap.put("51", "L4_VMTP");
-        l4TypeAliasMap.put("52", "L4_SECURE_VMTP");
-        l4TypeAliasMap.put("53", "L4_VINES");
-        l4TypeAliasMap.put("54", "L4_TTP");
-        l4TypeAliasMap.put("55", "L4_NSFNET_IGP");
-        l4TypeAliasMap.put("56", "L4_Dissimilar_GP");
-        l4TypeAliasMap.put("57", "L4_TCF");
-        l4TypeAliasMap.put("58", "L4_EIGRP");
-        l4TypeAliasMap.put("59", "L4_OSPF");
-        l4TypeAliasMap.put("5a", "L4_Sprite_RPC");
-        l4TypeAliasMap.put("5b", "L4_Locus_ARP");
-        l4TypeAliasMap.put("5c", "L4_MTP");
-        l4TypeAliasMap.put("5d", "L4_AX");
-        l4TypeAliasMap.put("5e", "L4_IP_within_IP");
-        l4TypeAliasMap.put("5f", "L4_Mobile_ICP");
-        l4TypeAliasMap.put("61", "L4_EtherIP");
-        l4TypeAliasMap.put("62", "L4_Encapsulation_Header");
-        l4TypeAliasMap.put("64", "L4_GMTP");
-        l4TypeAliasMap.put("65", "L4_IFMP");
-        l4TypeAliasMap.put("66", "L4_PNNI");
-        l4TypeAliasMap.put("67", "L4_PIM");
-        l4TypeAliasMap.put("68", "L4_ARIS");
-        l4TypeAliasMap.put("69", "L4_SCPS");
-        l4TypeAliasMap.put("6a", "L4_QNX");
-        l4TypeAliasMap.put("6b", "L4_Active_Networks");
-        l4TypeAliasMap.put("6c", "L4_IPPCP");
-        l4TypeAliasMap.put("6d", "L4_SNP");
-        l4TypeAliasMap.put("6e", "L4_Compaq_Peer_Protocol");
-        l4TypeAliasMap.put("6f", "L4_IPX_in_IP");
-        l4TypeAliasMap.put("70", "L4_VRRP");
-        l4TypeAliasMap.put("71", "L4_PGM");
-        l4TypeAliasMap.put("72", "L4_0_hop");
-        l4TypeAliasMap.put("73", "L4_L2TP");
-        l4TypeAliasMap.put("74", "L4_DDX");
-        l4TypeAliasMap.put("75", "L4_IATP");
-        l4TypeAliasMap.put("76", "L4_ST");
-        l4TypeAliasMap.put("77", "L4_SRP");
-        l4TypeAliasMap.put("78", "L4_UTI");
-        l4TypeAliasMap.put("79", "L4_SMP");
-        l4TypeAliasMap.put("7a", "L4_SM");
-        l4TypeAliasMap.put("7b", "L4_PTP");
-        l4TypeAliasMap.put("7c", "L4_ISIS");
-        l4TypeAliasMap.put("7d", "L4_FIRE");
-        l4TypeAliasMap.put("7e", "L4_CRTP");
-        l4TypeAliasMap.put("7f", "L4_CRUDP");
-        l4TypeAliasMap.put("80", "L4_SSCOPMCE");
-        l4TypeAliasMap.put("81", "L4_IPLT");
-        l4TypeAliasMap.put("82", "L4_SPS");
-        l4TypeAliasMap.put("83", "L4_PIPE");
-        l4TypeAliasMap.put("84", "L4_SCTP");
-        l4TypeAliasMap.put("85", "L4_Fibre_Channel");
-        l4TypeAliasMap.put("86", "L4_RSVP_E2E_IGNORE");
-        l4TypeAliasMap.put("87", "L4_Mobility_Header");
-        l4TypeAliasMap.put("88", "L4_UDP_Lite");
-        l4TypeAliasMap.put("89", "L4_MPLS");
-        l4TypeAliasMap.put("8a", "L4_MANET");
-        l4TypeAliasMap.put("8b", "L4_HIP");
-        l4TypeAliasMap.put("8c", "L4_Shim6");
-        l4TypeAliasMap.put("8d", "L4_WESP");
-        l4TypeAliasMap.put("8e", "L4_ROHC");
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java b/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..f44ea7a17b06556cd60e360c254ba9c1e1003279
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugcounter/CounterNode.java
@@ -0,0 +1,334 @@
+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 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
deleted file mode 100644
index 5bb1ce16757a4faa363205c346887ad1fbbc0d3e..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java
+++ /dev/null
@@ -1,741 +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.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
new file mode 100644
index 0000000000000000000000000000000000000000..c0aa316d953dc90a65c565f1d34719c8d19ddd5f
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterImpl.java
@@ -0,0 +1,141 @@
+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
new file mode 100644
index 0000000000000000000000000000000000000000..941802c31d4bd2b536002f0a094b6b781af78e32
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResource.java
@@ -0,0 +1,119 @@
+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
deleted file mode 100644
index 9edd47473a75564334c217b240002612d31e6219..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterResourceBase.java
+++ /dev/null
@@ -1,16 +0,0 @@
-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
new file mode 100644
index 0000000000000000000000000000000000000000..ae245deb872bdafa03f0b94a19091618ac76c4fc
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounterServiceImpl.java
@@ -0,0 +1,256 @@
+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 net.floodlightcontroller.core.IShutdownListener;
+import net.floodlightcontroller.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) {
+            try {
+				throw new Exception("counterDescription must not be null");
+			} catch (Exception e) {
+				e.printStackTrace();
+				logger.error(e.getMessage());
+			}
+        }
+        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.getCounterValue(),
+                            counter.getModuleName(),
+                            counter.getCounterHierarchy());
+            }
+        }
+    }
+
+
+   //*******************************
+   //   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
index dbde1854e9c6f7707e983eedf5bfe6fef299d7ec..00f259a54064db154011ce124ad39e4ce5a7d995 100644
--- a/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounter.java
+++ b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounter.java
@@ -1,38 +1,28 @@
 package net.floodlightcontroller.debugcounter;
 
+/**
+ * A concurrent counter.
+ * The counter returned when registering a counter. The counter value
+ * is a positive long. The counter cannot be decremented, but it can be
+ * reset to 0. The counter does not protect against overflow. If the
+ * value exceeds MAX_LONG it will silently overflow to MIN_LONG
+ * @author gregor
+ *
+ */
 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.
+     * Increment this counter by 1.
      */
-    void updateCounterWithFlush();
+    void increment();
 
     /**
-     * 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.
+     * Add the given increment to this counter
+     * @param incr
      */
-    void updateCounterNoFlush();
+    void add(long incr);
 
     /**
-     * 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
+     * Retrieve the value of the counter.
      */
     long getCounterValue();
 }
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java
index 538e60dad148c600e3802b53271ed6e111d8f6b9..524e7cea0e9968868704d95c490b693946cf137d 100644
--- a/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java
+++ b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java
@@ -1,88 +1,26 @@
 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;
-        }
-    }
+import net.floodlightcontroller.core.module.IFloodlightService;
 
-    public class CounterException extends Exception {
-        private static final long serialVersionUID = 2219781500857866035L;
+public interface IDebugCounterService extends IFloodlightService {
+    public enum MetaData {
+        WARN,
+        DROP,
+        ERROR
     }
 
     /**
-     *  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"
+     * All modules that wish to have the DebugCounterService count for them, must
+     * register themselves. If a module is registered multiple times subsequent
+     * registrations will reset all counter in the module.
+     *
+     * @param moduleName
+     * @return true if the module is registered for the first time, false if
+     * the modue was previously registered
      */
-    public static final int MAX_HIERARCHY = 3;
+    public boolean registerModule(String moduleName);
 
     /**
      * All modules that wish to have the DebugCounterService count for them, must
@@ -105,32 +43,15 @@ public interface IDebugCounterService extends IFloodlightService {
      *                             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;
+    public IDebugCounter
+    registerCounter(String moduleName, String counterHierarchy,
+                    String counterDescription, MetaData... metaData);
 
-    /**
-     * 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
@@ -142,8 +63,10 @@ public interface IDebugCounterService extends IFloodlightService {
      *              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.
+     * @return false if the given moduleName, counterHierarchy
+     * does not exist
      */
-    void resetCounterHierarchy(String moduleName, String counterHierarchy);
+    public boolean resetCounterHierarchy(String moduleName, String counterHierarchy);
 
     /**
      * Resets the values of all counters in the system.
@@ -153,38 +76,10 @@ public interface IDebugCounterService extends IFloodlightService {
     /**
      * Resets the values of all counters belonging
      * to a module with the given 'moduleName'.
+     * @return false if the given module name does not exists
      */
-    public void resetAllModuleCounters(String moduleName);
+    public boolean 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.
@@ -197,11 +92,13 @@ public interface IDebugCounterService extends IFloodlightService {
      * 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
+     * If the module or hierarchy is not registered, returns an empty list
+     *
+     * @return A list of DebugCounterResource or an empty list if the counter
      *         could not be found
      */
-    public List<DebugCounterInfo> getCounterHierarchy(String moduleName,
-                                                      String counterHierarchy);
+    public List<DebugCounterResource>
+    getCounterHierarchy(String moduleName, String counterHierarchy);
 
     /**
      * Get counter values and associated information for all counters in the
@@ -209,51 +106,16 @@ public interface IDebugCounterService extends IFloodlightService {
      *
      * @return the list of values/info or an empty list
      */
-    public  List<DebugCounterInfo> getAllCounterValues();
+    public List<DebugCounterResource> getAllCounterValues();
 
     /**
      * Get counter values and associated information for all counters associated
      * with a module.
+     * If the module is not registered, returns an empty list
      *
      * @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);
-
+    public  List<DebugCounterResource> getModuleCounterValues(String moduleName);
 
 }
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java b/src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java
similarity index 50%
rename from src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java
rename to src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java
index 5dc7b319219de1acb202ffdf3df1b347127bb10c..36a19d548fe60bda68455064224fdb4574ad089d 100644
--- a/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java
+++ b/src/main/java/net/floodlightcontroller/debugcounter/MockDebugCounterService.java
@@ -11,9 +11,8 @@ 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 {
+public class MockDebugCounterService implements IFloodlightModule, IDebugCounterService {
 
 
     @Override
@@ -53,110 +52,64 @@ public class NullDebugCounter implements IFloodlightModule, IDebugCounterService
 
     }
 
-
     @Override
-    public void flushCounters() {
-
+    public boolean registerModule(String moduleName) {
+        return true;
     }
 
     @Override
-    public void resetAllCounters() {
-
+    public IDebugCounter registerCounter(String moduleName,
+                                         String counterHierarchy,
+                                         String counterDescription,
+                                         MetaData... metaData) {
+        return new MockCounterImpl();
     }
 
     @Override
-    public void resetAllModuleCounters(String moduleName) {
-
+    public boolean
+    resetCounterHierarchy(String moduleName, String counterHierarchy) {
+        return true;
     }
 
-
     @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();
+    public void resetAllCounters() {
     }
 
     @Override
-    public List<DebugCounterInfo> getAllCounterValues() {
-        return Collections.emptyList();
+    public boolean resetAllModuleCounters(String moduleName) {
+        return true;
     }
 
     @Override
-    public List<DebugCounterInfo> getModuleCounterValues(String moduleName) {
+    public List<DebugCounterResource>
+    getCounterHierarchy(String moduleName, String counterHierarchy) {
         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() {
+    public List<DebugCounterResource> getAllCounterValues() {
         return Collections.emptyList();
     }
 
     @Override
-    public List<String> getModuleCounterList(String moduleName) {
+    public List<DebugCounterResource>
+    getModuleCounterValues(String moduleName) {
         return Collections.emptyList();
     }
 
-    public class NullCounterImpl implements IDebugCounter {
-
+    public static class MockCounterImpl implements IDebugCounter {
         @Override
-        public void updateCounterWithFlush() {
-
+        public void increment() {
         }
 
         @Override
-        public void updateCounterNoFlush() {
-
-        }
-
-        @Override
-        public void updateCounterWithFlush(int incr) {
-        }
-
-        @Override
-        public void updateCounterNoFlush(int incr) {
-
+        public void add(long incr) {
         }
 
         @Override
         public long getCounterValue() {
             return -1;
         }
-
     }
+
 }
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResource.java b/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResource.java
deleted file mode 100644
index 3dd35bc07502d4db5f9b16ebe4da8978379b5497..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResource.java
+++ /dev/null
@@ -1,382 +0,0 @@
-package net.floodlightcontroller.debugcounter.web;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-
-import org.restlet.resource.Get;
-import org.restlet.resource.Post;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import net.floodlightcontroller.debugcounter.DebugCounter.DebugCounterInfo;
-import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
-
-/**
- * Web interface for Debug Counters
- *
- * @author Saurav
- */
-public class DebugCounterResource extends DebugCounterResourceBase {
-    protected static Logger logger =
-            LoggerFactory.getLogger(DebugCounterResource.class);
-
-    /**
-     * The output JSON model that contains the counter information
-     */
-    public class DebugCounterInfoOutput {
-        protected class DCInfo {
-            private final Long counterValue;
-            private final CounterType counterType;
-            private final String counterDesc;
-            private final boolean enabled;
-            private final String counterHierarchy;
-            private final String moduleName;
-            private final String[] metaData;
-
-            DCInfo(DebugCounterInfo dci) {
-                this.moduleName = dci.getCounterInfo().getModuleName();
-                this.counterHierarchy = dci.getCounterInfo().getCounterHierarchy();
-                this.counterDesc = dci.getCounterInfo().getCounterDesc();
-                this.metaData = dci.getCounterInfo().getMetaData();
-                this.enabled = dci.getCounterInfo().isEnabled();
-                this.counterType = dci.getCounterInfo().getCtype();
-                this.counterValue = dci.getCounterValue();
-            }
-
-            public Long getCounterValue() {
-                return counterValue;
-            }
-            public CounterType getCounterType() {
-                return counterType;
-            }
-
-            public String getCounterDesc() {
-                return counterDesc;
-            }
-
-            public boolean isEnabled() {
-                return enabled;
-            }
-
-            public String getCounterHierarchy() {
-                return counterHierarchy;
-            }
-
-            public String getModuleName() {
-                return moduleName;
-            }
-
-            public String[] getMetaData() {
-                return metaData;
-            }
-
-        }
-        // complete counter information - null if only names are requested or
-        // if an error occurs
-        public Map<String, DCInfo> counterMap;
-        // list of names could be just moduleNames or counter hierarchical names
-        // for a specific module
-        public List<String> names;
-
-        public String error;
-
-        DebugCounterInfoOutput(boolean getList) {
-            if (!getList) {
-                counterMap = new HashMap<String, DCInfo>();
-            }
-            error = null;
-        }
-        public Map<String, DCInfo> getCounterMap() {
-            return counterMap;
-        }
-
-        public String getError() {
-            return error;
-        }
-
-        public List<String> getNames() {
-            return names;
-        }
-
-    }
-
-    public enum Option {
-        ALL, ONE_MODULE, MODULE_COUNTER_HIERARCHY, ERROR_BAD_MODULE_NAME,
-        ERROR_BAD_PARAM,
-        ERROR_BAD_MODULE_COUNTER_NAME
-    }
-
-    public static class CounterPost {
-        public Boolean reset;
-        public Boolean enable;
-
-        public Boolean getReset() {
-            return reset;
-        }
-        public void setReset(Boolean reset) {
-            this.reset = reset;
-        }
-        public Boolean getEnable() {
-            return enable;
-        }
-        public void setEnable(Boolean enable) {
-            this.enable = enable;
-        }
-    }
-
-    public static class ResetOutput {
-        String error = null;
-
-        public String getError() {
-            return error;
-        }
-        public void setError(String error) {
-            this.error = error;
-        }
-    }
-
-    /**
-     * Reset or enable/disable counters
-     *
-     * If using curl:
-     * curl -X POST -d DATA -H "Content-Type: application/json" URL
-     * where  DATA must be one of the following:
-     *    {\"reset\":true}   to reset counters
-     *    {\"enable\":true}  to enable counter
-     *    {\"enable\":false} to disable counter
-     * and URL must be in one of the following forms:
-     *    "http://{controller-hostname}:8080/wm/debugcounter/{param1}/{param2}/{param3}/{param4}
-     *
-     * {param1} can be null, 'all' or the name of a module {moduleName}.
-     * {param2}/{param3}/{param4} refer to hierarchical counter names.
-     *
-     * The Reset command will reset the counter specified as well as all counters
-     * in the hierarchical levels below. For example, if a counter hierarchy exists
-     * as switch/00:00:00:00:01:02:03:04/pktin/drops, then a reset command with just
-     * the moduleName (param1=switch) and counterHierarchy (param2=00:00:00:00:01:02:03:04)
-     * will reset all counters for that switch. Continuing the example -
-     * for a counterHierarchy (param2=00:00:00:00:01:02:03:04 and param3=pktin), the reset
-     * command will remove all pktin counters for that switch.
-     *
-     * The enable/disable command will ONLY disable a specific counter (and only if
-     * that counter is of CounterType.ON_DEMAND)
-     * It will not enable/disable counters at any other hierarchical level.
-     *
-     */
-    @Post
-    public ResetOutput postHandler(CounterPost postData) {
-        ResetOutput output = new ResetOutput();
-        Option choice = Option.ERROR_BAD_PARAM;
-        String param1 = (String)getRequestAttributes().get("param1");
-        String param2 = (String)getRequestAttributes().get("param2");
-        String param3 = (String)getRequestAttributes().get("param3");
-        String param4 = (String)getRequestAttributes().get("param4");
-        String moduleName = "";
-
-        if (param1 == null) {
-             moduleName = "all";
-            choice = Option.ALL;
-        } else if (param1.equals("all")) {
-            moduleName = "all";
-            choice = Option.ALL;
-        } else {
-            moduleName = param1;
-        }
-
-        String counterHierarchy = "";
-        if (param2 != null) {
-            counterHierarchy += param2;
-            if (param3 != null) {
-                counterHierarchy += "/" + param3;
-                if (param4 != null) {
-                    counterHierarchy += "/" + param4;
-                }
-            }
-        }
-
-        if (!moduleName.equals("all") && counterHierarchy.equals("")) {
-            // only module name specified
-            boolean isRegistered = debugCounter.containsModuleName(param1);
-            if (isRegistered) {
-                choice = Option.ONE_MODULE;
-            } else {
-                choice = Option.ERROR_BAD_MODULE_NAME;
-            }
-        } else if (!moduleName.equals("all") && !counterHierarchy.equals("")) {
-            // both module and counter names specified
-            boolean isRegistered = debugCounter.
-                    containsModuleCounterHierarchy(moduleName, counterHierarchy);
-            if (isRegistered) {
-                choice = Option.MODULE_COUNTER_HIERARCHY;
-            } else {
-                choice = Option.ERROR_BAD_MODULE_COUNTER_NAME;
-            }
-        }
-
-        boolean reset = false;
-        boolean turnOnOff = false;
-        if (postData.getReset() != null && postData.getReset()) {
-            reset = true;
-        }
-        if (postData.getEnable() != null) {
-            turnOnOff = true;
-        }
-
-        switch (choice) {
-            case ALL:
-                if (reset) debugCounter.resetAllCounters();
-                break;
-            case ONE_MODULE:
-                if (reset) debugCounter.resetAllModuleCounters(moduleName);
-                break;
-            case MODULE_COUNTER_HIERARCHY:
-                if (reset)
-                    debugCounter.resetCounterHierarchy(moduleName, counterHierarchy);
-                else if (turnOnOff && postData.getEnable())
-                    debugCounter.enableCtrOnDemand(moduleName, counterHierarchy);
-                else if (turnOnOff && !postData.getEnable())
-                    debugCounter.disableCtrOnDemand(moduleName, counterHierarchy);
-                break;
-            case ERROR_BAD_MODULE_NAME:
-                output.error = "Module name has no corresponding registered counters";
-                break;
-            case ERROR_BAD_MODULE_COUNTER_NAME:
-                output.error = "Counter not registered";
-                break;
-            case ERROR_BAD_PARAM:
-                output.error = "Bad param";
-        }
-
-        return output;
-    }
-
-    /**
-     * Return the debug counter data for the get rest-api call
-     *
-     * URI must be in one of the following forms:
-     * "http://{controller-hostname}:8080/wm/debugcounter/{param1}/{param2}/{param3}/{param4}"
-     *
-     *  where {param1} must be one of (no quotes):
-     *       null                   if nothing is given then by default all
-     *                              module names are returned for which counters
-     *                              have been registered
-     *       "all"                  returns value/info on all counters.
-     *       "{moduleName}"         returns value/info on all counters for
-     *                              the specified module 'moduelName'.
-     * & {param2}/{param3}/{param4} refer to hierarchical counter names.
-     *                              eg. 00:00:00:00:01:02:03:04/pktin/drops
-     *                              where leaving out any of the params returns
-     *                              all counters in the hierarchical level below.
-     *                              So giving just the switch dpid will fetch
-     *                              all counters for that switch.
-     *                              A special case => if param2 is null, then
-     *                              all hierarchical counterNames are returned
-     *                              for the given moduleName (in param1)
-     */
-    @Get
-    public DebugCounterInfoOutput handleCounterInfoQuery() {
-        DebugCounterInfoOutput output;
-        Option choice = Option.ERROR_BAD_PARAM;
-        String param1 = (String)getRequestAttributes().get("param1");
-        String param2 = (String)getRequestAttributes().get("param2");
-        String param3 = (String)getRequestAttributes().get("param3");
-        String param4 = (String)getRequestAttributes().get("param4");
-
-        if (param1 == null) {
-            output = new DebugCounterInfoOutput(true);
-            return listCounters(output);
-        } else if (param1.equals("all")) {
-            output = new DebugCounterInfoOutput(false);
-            populateCounters(debugCounter.getAllCounterValues(), output);
-            return output;
-        }
-
-        output = new DebugCounterInfoOutput(false);
-        String counterHierarchy = "";
-        if (param2 == null) {
-            // param2 is null -- return list of counternames for param1
-            boolean isRegistered = debugCounter.containsModuleName(param1);
-            output = new DebugCounterInfoOutput(true);
-            if (isRegistered) {
-                return listCounters(param1, output);
-            } else {
-                choice = Option.ERROR_BAD_MODULE_NAME;
-            }
-        } else if (param2.equals("all")) {
-            // get all counter info for a single module
-            boolean isRegistered = debugCounter.containsModuleName(param1);
-            if (isRegistered) {
-                choice = Option.ONE_MODULE;
-            } else {
-                choice = Option.ERROR_BAD_MODULE_NAME;
-            }
-        } else {
-            counterHierarchy += param2;
-            if (param3 != null) {
-                counterHierarchy += "/" + param3;
-                if (param4 != null) {
-                    counterHierarchy += "/" + param4;
-                }
-            }
-            boolean isRegistered = debugCounter.
-                    containsModuleCounterHierarchy(param1, counterHierarchy);
-            if (isRegistered) {
-                choice = Option.MODULE_COUNTER_HIERARCHY;
-            } else {
-                choice = Option.ERROR_BAD_MODULE_COUNTER_NAME;
-            }
-        }
-
-        switch (choice) {
-            case ONE_MODULE:
-                populateCounters(debugCounter.getModuleCounterValues(param1), output);
-                break;
-            case MODULE_COUNTER_HIERARCHY:
-                populateCounters(debugCounter.getCounterHierarchy(param1, counterHierarchy),
-                                      output);
-                break;
-            case ERROR_BAD_MODULE_NAME:
-                output.error = "Module name is not registered for debug-counters";
-                break;
-            case ERROR_BAD_MODULE_COUNTER_NAME:
-                output.error = "Counter not registered";
-                break;
-            case ERROR_BAD_PARAM:
-            default:
-                output.error = "Bad param";
-        }
-
-        return output;
-    }
-
-    private DebugCounterInfoOutput listCounters(String moduleName,
-                                                DebugCounterInfoOutput output) {
-        output.names = debugCounter.getModuleCounterList(moduleName);
-        return output;
-    }
-
-    private DebugCounterInfoOutput listCounters(DebugCounterInfoOutput output) {
-        output.names = debugCounter.getModuleList();
-        return output;
-    }
-
-    private void populateSingleCounter(DebugCounterInfo debugCounterInfo,
-                                       DebugCounterInfoOutput output) {
-        if (debugCounterInfo != null)
-            output.counterMap.put(debugCounterInfo.getCounterInfo().
-                                  getModuleCounterHierarchy(),
-                                  output.new DCInfo(debugCounterInfo));
-    }
-
-    private void populateCounters(List<DebugCounterInfo> counterValues,
-                                        DebugCounterInfoOutput output) {
-        for (DebugCounterInfo dci : counterValues) {
-            populateSingleCounter(dci, output);
-        }
-    }
-
-
-
-}
diff --git a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResourceBase.java b/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResourceBase.java
deleted file mode 100644
index 48e469bc689b9c3cf44c2dcdd0c80caa428796b2..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterResourceBase.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.floodlightcontroller.debugcounter.web;
-
-import net.floodlightcontroller.debugcounter.IDebugCounterService;
-
-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/web/DebugCounterRoutable.java b/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterRoutable.java
deleted file mode 100644
index 55ba5bacf95b0257556bd5483a561ca40fa0a8cb..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugcounter/web/DebugCounterRoutable.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.floodlightcontroller.debugcounter.web;
-
-import org.restlet.Context;
-import org.restlet.Restlet;
-import org.restlet.routing.Router;
-
-import net.floodlightcontroller.restserver.RestletRoutable;
-
-public class DebugCounterRoutable implements RestletRoutable {
-
-    @Override
-    public String basePath() {
-        return "/wm/debugcounter";
-    }
-
-    @Override
-    public Restlet getRestlet(Context context) {
-        Router router = new Router(context);
-        router.attach("/{param1}/{param2}/{param3}/{param4}/", DebugCounterResource.class);
-        router.attach("/{param1}/{param2}/{param3}/{param4}", DebugCounterResource.class);
-        router.attach("/{param1}/{param2}/{param3}/", DebugCounterResource.class);
-        router.attach("/{param1}/{param2}/{param3}", DebugCounterResource.class);
-        router.attach("/{param1}/{param2}/", DebugCounterResource.class);
-        router.attach("/{param1}/{param2}", DebugCounterResource.class);
-        router.attach("/{param1}/", DebugCounterResource.class);
-        router.attach("/{param1}", DebugCounterResource.class);
-        router.attach("/", DebugCounterResource.class);
-        router.attach("", DebugCounterResource.class);
-        return router;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/CircularBuffer.java b/src/main/java/net/floodlightcontroller/debugevent/CircularBuffer.java
deleted file mode 100644
index f1a6db33dd37dfb69d3635855a774e3b14ae3e5b..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/CircularBuffer.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package net.floodlightcontroller.debugevent;
-
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.concurrent.LinkedBlockingDeque;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class CircularBuffer<T> implements Iterable<T>{
-    protected static Logger log = LoggerFactory.getLogger(CircularBuffer.class);
-    private final LinkedBlockingDeque<T> buffer;
-
-    public CircularBuffer(int capacity) {
-        this.buffer = new LinkedBlockingDeque<T>(capacity);
-    }
-
-    /**
-     * Adding an element to the circular buffer implies adding the element to
-     * the tail of the deque. In doing so, if the capacity of the buffer has
-     * been exhausted, then the deque's head should be removed to preserve the
-     * circular nature of the buffer. A LinkedBlockingDeque is used because of its
-     * concurrent nature and the fact that adding to tail and removing from head are
-     * both O(1) operations. The removed head is returned to the caller for reuse.
-     *
-     * @param e    the element to be added
-     * @return     removed element (for reuse) or null
-     */
-    public T add(T e) {
-        T oldE = null;
-        while (!buffer.offerLast(e)) {
-            oldE = buffer.poll();
-        }
-        return oldE;
-    }
-
-    /**
-     * The basic idea here is that an ArrayList has been passed in, which may or may not
-     * have a size bigger that the actual number of elements that are meant to
-     * be flushed to the Circular Buffer. Thus the 'uptoIndex' parameter specifies
-     * the number of elements that need to be flushed starting from index 0.
-     * Note that after flushing, the circular buffer may return a memory unit (of type T)
-     * for reuse in the list, if the circular buffer popped off memory to preserve
-     * its circular nature. Or it may just return null if nothing was popped off.
-     * Either way, the list that is returned by this method, is of the SAME SIZE
-     * as the list passed in, as ArrayLists can hold null elements. The only difference
-     * is that the list returned will have elements that reference old popped-off memory
-     * from the circular-buffer or null.
-     *
-     * @param elist         the ArrayList to flush into the circular buffer.
-     * @param uptoIndex     flush starting from index 0 upto but not including
-     *                      index 'uptoIndex'.
-     * @return              the 'elist' passed in with members now pointing to
-     *                      to null or old-memory for reuse. The returned list
-     *                      if of the same size as 'elist'.
-     */
-    public ArrayList<T> addAll(ArrayList<T> elist, int uptoIndex) {
-        if (uptoIndex > elist.size()) {
-            log.error("uptoIndex is greater than elist size .. aborting addAll");
-            return elist;
-        }
-        for (int index=0; index < uptoIndex; index++) {
-            T e = elist.get(index);
-            if (e != null) {
-                elist.set(index, add(e));
-            }
-        }
-        return elist;
-    }
-
-    /**
-     * Returns an iterator over the elements in the circular buffer in proper sequence.
-     * The elements will be returned in order from most-recent to oldest.
-     * The returned Iterator is a "weakly consistent" iterator that will never
-     * throw ConcurrentModificationException, and guarantees to traverse elements
-     * as they existed upon construction of the iterator, and may (but is not
-     * guaranteed to) reflect any modifications subsequent to construction.
-     */
-    @Override
-    public Iterator<T> iterator() {
-        return buffer.descendingIterator();
-    }
-
-    public int size() {
-        return buffer.size();
-    }
-
-    /**
-     *  Atomically removes all elements in the circular buffer
-     */
-    public void clear() {
-        buffer.clear();
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/CustomFormatter.java b/src/main/java/net/floodlightcontroller/debugevent/CustomFormatter.java
new file mode 100644
index 0000000000000000000000000000000000000000..947a291a1f33f6e6e0611f02ef4e3f2fe1ea5c77
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/CustomFormatter.java
@@ -0,0 +1,13 @@
+package net.floodlightcontroller.debugevent;
+
+import net.floodlightcontroller.debugevent.EventResource.EventResourceBuilder;
+
+/**
+ * Format Event object based on its class and store accordingly in
+ * {@link EventResource}
+ */
+public interface CustomFormatter<T> {
+
+    public abstract EventResourceBuilder
+            customFormat(T obj, String name, EventResourceBuilder edb);
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/CustomFormatters.java b/src/main/java/net/floodlightcontroller/debugevent/CustomFormatters.java
new file mode 100644
index 0000000000000000000000000000000000000000..6685461e10a68e54d52658756eebd2c77e8a4132
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/CustomFormatters.java
@@ -0,0 +1,221 @@
+package net.floodlightcontroller.debugevent;
+
+import java.lang.ref.SoftReference;
+import java.util.Collection;
+
+import javax.annotation.Nullable;
+
+import net.floodlightcontroller.debugevent.EventResource.EventResourceBuilder;
+import net.floodlightcontroller.debugevent.EventResource.Metadata;
+import net.floodlightcontroller.devicemanager.SwitchPort;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.util.HexString;
+
+import net.floodlightcontroller.packet.IPv4;
+
+import com.google.common.base.Joiner;
+
+class CustomFormatterCollectionAttachmentPoint implements
+    CustomFormatter<Collection<SwitchPort>> {
+
+    @Override
+    public EventResourceBuilder
+            customFormat(@Nullable Collection<SwitchPort> aps2, String name,
+                         EventResourceBuilder edb) {
+        if (aps2 != null) {
+            StringBuilder apsStr2 = new StringBuilder();
+            if (aps2.size() == 0) {
+                apsStr2.append("--");
+            } else {
+                for (SwitchPort ap : aps2) {
+                    apsStr2.append(ap.getSwitchDPID().toString());
+                    apsStr2.append("/");
+                    apsStr2.append(ap.getPort());
+                    apsStr2.append(" ");
+                }
+                // remove trailing space
+                apsStr2.deleteCharAt(apsStr2.length());
+            }
+            edb.dataFields.add(new Metadata(name, apsStr2.toString()));
+        }
+        return edb;
+    }
+}
+
+class CustomFormatterCollectionIpv4 implements
+    CustomFormatter<Collection<IPv4Address>> {
+
+    @Override
+    public EventResourceBuilder
+            customFormat(@Nullable Collection<IPv4Address> ipv4Addresses2,
+                         String name, EventResourceBuilder edb) {
+        if (ipv4Addresses2 != null) {
+            String ipv4AddressesStr2 = "--";
+            if (!ipv4Addresses2.isEmpty()) {
+                ipv4AddressesStr2 = Joiner.on(" ").join(ipv4Addresses2);
+            }
+            edb.dataFields.add(new Metadata(name, ipv4AddressesStr2));
+        }
+        return edb;
+    }
+}
+
+class CustomFormatterCollectionObject implements
+    CustomFormatter<Collection<Object>> {
+
+    @Override
+    public EventResourceBuilder
+            customFormat(@Nullable Collection<Object> obl2, String name,
+                         EventResourceBuilder edb) {
+        if (obl2 != null) {
+            StringBuilder sbldr2 = new StringBuilder();
+            if (obl2.size() == 0) {
+                sbldr2.append("--");
+            } else {
+                for (Object o : obl2) {
+                    sbldr2.append(o.toString());
+                    sbldr2.append(" ");
+                }
+            }
+            edb.dataFields.add(new Metadata(name, sbldr2.toString()));
+        }
+        return edb;
+    }
+}
+
+class CustomFormatterDpid implements CustomFormatter<DatapathId> {
+
+    @Override
+    public EventResourceBuilder customFormat(@Nullable DatapathId dpid,
+                                             String name,
+                                             EventResourceBuilder edb) {
+        if (dpid != null) {
+            edb.dataFields.add(new Metadata(name, dpid.toString()));
+        }
+        return edb;
+    }
+
+}
+
+class CustomFormatterIpv4 implements CustomFormatter<Integer> {
+
+    @Override
+    public EventResourceBuilder customFormat(@Nullable Integer obj,
+                                             String name,
+                                             EventResourceBuilder edb) {
+        if (obj != null) {
+            edb.dataFields.add(new Metadata(name, IPv4.fromIPv4Address(obj)));
+        }
+        return edb;
+    }
+
+}
+
+class CustomFormatterMac implements CustomFormatter<Long> {
+
+    @Override
+    public EventResourceBuilder customFormat(@Nullable Long obj,
+                                             String name,
+                                             EventResourceBuilder edb) {
+        if (obj != null) {
+            edb.dataFields.add(new Metadata(name, HexString.toHexString(obj,
+                                                                        6)));
+        }
+        return edb;
+    }
+
+}
+
+class CustomFormatterObject implements CustomFormatter<Object> {
+
+    @Override
+    public EventResourceBuilder customFormat(@Nullable Object obj,
+                                             String name,
+                                             EventResourceBuilder edb) {
+        if (obj != null) {
+            edb.dataFields.add(new Metadata(name, obj.toString()));
+        }
+        return edb;
+    }
+
+}
+
+class CustomFormatterPrimitive implements CustomFormatter<Object> {
+
+    @Override
+    public EventResourceBuilder customFormat(@Nullable Object obj,
+                                             String name,
+                                             EventResourceBuilder edb) {
+        if (obj != null) {
+            edb.dataFields.add(new Metadata(name, obj.toString()));
+        }
+        return edb;
+    }
+
+}
+
+class CustomFormatterSrefCollectionObject implements
+    CustomFormatter<SoftReference<Collection<Object>>> {
+
+    @Override
+    public EventResourceBuilder customFormat(@Nullable
+                                         SoftReference<Collection<Object>> srefCollectionObj2,
+                                         String name, EventResourceBuilder edb) {
+        if (srefCollectionObj2 != null) {
+            Collection<Object> ol2 = srefCollectionObj2.get();
+            if (ol2 != null) {
+                StringBuilder sb = new StringBuilder();
+                if (ol2.size() == 0) {
+                    sb.append("--");
+                } else {
+                    for (Object o : ol2) {
+                        sb.append(o.toString());
+                        sb.append(" ");
+                    }
+                }
+                edb.dataFields.add(new Metadata(name, sb.toString()));
+            } else {
+                edb.dataFields.add(new Metadata(name,
+                                                "-- reference not available --"));
+            }
+        }
+        return edb;
+    }
+
+}
+
+class CustomFormatterSrefObject implements CustomFormatter<SoftReference<Object>> {
+
+    @Override
+    public EventResourceBuilder
+            customFormat(@Nullable SoftReference<Object> srefObj,
+                         String name, EventResourceBuilder edb) {
+        if (srefObj != null) {
+            Object o = srefObj.get();
+            if (o != null) {
+                edb.dataFields.add(new Metadata(name, o.toString()));
+            } else {
+                edb.dataFields.add(new Metadata(name,
+                                                "-- reference not available --"));
+            }
+        }
+        return edb;
+    }
+
+}
+
+class CustomFormatterString implements CustomFormatter<String> {
+
+    @Override
+    public EventResourceBuilder customFormat(@Nullable String string,
+                                             String name,
+                                             EventResourceBuilder edb) {
+        if (string != null) {
+            edb.dataFields.add(new Metadata(name, string));
+        }
+        return edb;
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java
deleted file mode 100644
index 36e01d7c96ed549d593dc90ad1d5927d4d7d3a87..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/DebugEvent.java
+++ /dev/null
@@ -1,513 +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.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-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.debugevent.web.DebugEventRoutable;
-import net.floodlightcontroller.restserver.IRestApiService;
-
-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 DebugEvent implements IFloodlightModule, IDebugEventService {
-    protected static Logger log = LoggerFactory.getLogger(DebugEvent.class);
-
-    /**
-     *  Every registered event type gets an event id, the value for which is obtained
-     *  while holding the lock.
-     */
-    protected int eventIdCounter = 0;
-    protected Object eventIdLock = new Object();
-
-    private static final long MIN_FLUSH_DELAY = 100; //ms
-    private static final int PCT_LOCAL_CAP = 10; // % of global capacity
-    private static final int MIN_LOCAL_CAPACITY = 10; //elements
-
-    /**
-     * Event Information
-     */
-    public class EventInfo {
-        int eventId;
-        boolean enabled;
-        int bufferCapacity;
-        EventType etype;
-        String eventDesc;
-        String eventName;
-        String moduleName;
-        String moduleEventName;
-        Class<?> eventClass;
-        String[] metaData;
-
-        public EventInfo(int eventId, boolean enabled, int bufferCapacity,
-                         EventType etype, Class<?> eventClass, String eventDesc,
-                         String eventName, String moduleName, String... metaData) {
-            this.enabled = enabled;
-            this.eventId = eventId;
-            this.bufferCapacity = bufferCapacity;
-            this.etype = etype;
-            this.eventClass = eventClass;
-            this.eventDesc = eventDesc;
-            this.eventName = eventName;
-            this.moduleName = moduleName;
-            this.moduleEventName = moduleName + "/" + eventName;
-            this.metaData = metaData;
-        }
-
-        public int getEventId() { return eventId; }
-        public boolean isEnabled() { return enabled; }
-        public int getBufferCapacity() { return bufferCapacity; }
-        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; }
-        public String[] getMetaData() { return metaData; }
-    }
-
-    //******************
-    //   Global stores
-    //******************
-
-    /**
-     * Event history for a particular event-id is stored in a circular buffer
-     */
-    protected class DebugEventHistory {
-        EventInfo einfo;
-        CircularBuffer<Event> eventBuffer;
-
-        public DebugEventHistory(EventInfo einfo, int capacity) {
-            this.einfo = einfo;
-            this.eventBuffer = new CircularBuffer<Event>(capacity);
-        }
-    }
-
-    /**
-     * Global storage for all event types and their corresponding event buffers.
-     * A particular event type is accessed by directly indexing into the array
-     * with the corresponding event-id.
-     */
-    protected DebugEventHistory[] allEvents =
-                    new DebugEventHistory[MAX_EVENTS];
-
-    /**
-     * 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 ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>>
-        moduleEvents = new ConcurrentHashMap<String,
-                                ConcurrentHashMap<String, Integer>>();
-
-    /**
-     * A collection of event ids that are currently enabled for logging
-     */
-    protected Set<Integer> currentEvents = Collections.newSetFromMap(
-                                       new ConcurrentHashMap<Integer,Boolean>());
-
-    //******************
-    // Thread local stores
-    //******************
-
-    /**
-     * Thread local storage for events
-     */
-    protected class LocalEventHistory {
-        int nextIndex;
-        int maxCapacity;
-        boolean enabled;
-        ArrayList<Event> eventList;
-        long lastFlushTime;
-        boolean flushNow;
-
-        public LocalEventHistory(boolean enabled, int maxCapacity, boolean flushNow) {
-            this.nextIndex = 0;
-            this.maxCapacity = maxCapacity;
-            this.enabled = enabled;
-            this.eventList = new ArrayList<Event>();
-            this.flushNow = flushNow;
-        }
-    }
-
-    /**
-     * 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.
-     */
-    protected final ThreadLocal<LocalEventHistory[]> threadlocalEvents =
-            new ThreadLocal<LocalEventHistory[]>() {
-        @Override
-        protected LocalEventHistory[] initialValue() {
-            return new LocalEventHistory[MAX_EVENTS];
-        }
-    };
-
-    /**
-     * 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>();
-        }
-    };
-
-    //*******************************
-    //   IEventUpdater
-    //*******************************
-
-    protected class EventUpdaterImpl<T> implements IEventUpdater<T> {
-        private final int eventId;
-
-        public EventUpdaterImpl(int evId) {
-            this.eventId = evId;
-        }
-
-        @Override
-        public void updateEventNoFlush(Object event) {
-            if (!validEventId()) return;
-            updateEvent(eventId, false, event);
-        }
-
-        @Override
-        public void updateEventWithFlush(Object event) {
-            if (!validEventId()) return;
-            updateEvent(eventId, true, event);
-        }
-
-        private boolean validEventId() {
-            if (eventId < 0 || eventId >= MAX_EVENTS) {
-                throw new IllegalStateException();
-            }
-            return true;
-        }
-
-    }
-
-    //*******************************
-    //   IDebugEventService
-    //*******************************
-
-    @Override
-    public <T> IEventUpdater<T> registerEvent(String moduleName, String eventName,
-                                              String eventDescription, EventType et,
-                                              Class<T> eventClass, int bufferCapacity,
-                                              String... metaData) throws MaxEventsRegistered {
-        int eventId = -1;
-        synchronized (eventIdLock) {
-             eventId = Integer.valueOf(eventIdCounter++);
-        }
-        if (eventId > MAX_EVENTS-1) {
-            throw new MaxEventsRegistered();
-        }
-
-        // register event id for moduleName
-        if (!moduleEvents.containsKey(moduleName)) {
-            moduleEvents.put(moduleName, new ConcurrentHashMap<String, Integer>());
-        }
-        if (!moduleEvents.get(moduleName).containsKey(eventName)) {
-            moduleEvents.get(moduleName).put(eventName, new Integer(eventId));
-        } else {
-            int existingEventId = moduleEvents.get(moduleName).get(eventName);
-            log.error("Duplicate event registration for moduleName {} eventName {}",
-                      moduleName, eventName);
-            return new EventUpdaterImpl<T>(existingEventId);
-        }
-
-        // create storage for event-type
-        boolean enabled = (et == EventType.ALWAYS_LOG) ? true : false;
-        EventInfo ei = new EventInfo(eventId, enabled, bufferCapacity,
-                                     et, eventClass, eventDescription, eventName,
-                                     moduleName, metaData);
-        allEvents[eventId] = new DebugEventHistory(ei, bufferCapacity);
-        if (enabled) {
-            currentEvents.add(eventId);
-        }
-
-        return new EventUpdaterImpl<T>(eventId);
-    }
-
-    private void updateEvent(int eventId, boolean flushNow, Object eventData) {
-        if (eventId < 0 || eventId > MAX_EVENTS-1) return;
-
-        LocalEventHistory[] thishist = this.threadlocalEvents.get();
-        if (thishist[eventId] == null) {
-            // seeing this event for the first time in this thread - create local
-            // store by consulting global store
-            DebugEventHistory de = allEvents[eventId];
-            if (de != null) {
-                boolean enabled = de.einfo.enabled;
-                int localCapacity = de.einfo.bufferCapacity * PCT_LOCAL_CAP/ 100;
-                if (localCapacity < 10)  localCapacity = MIN_LOCAL_CAPACITY;
-                thishist[eventId] = new LocalEventHistory(enabled, localCapacity,
-                                                          flushNow);
-                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[eventId];
-        if (le.enabled) {
-            long timestamp = System.currentTimeMillis();
-            long thisthread = Thread.currentThread().getId();
-            String thisthreadname = Thread.currentThread().getName();
-            if (le.nextIndex < le.eventList.size()) {
-                if (le.eventList.get(le.nextIndex) == null) {
-                    le.eventList.set(le.nextIndex, new Event(timestamp, thisthread,
-                                                             thisthreadname,
-                                                             eventData));
-                } else {
-                    Event e = le.eventList.get(le.nextIndex);
-                    e.timestamp = timestamp;
-                    e.threadId = thisthread;
-                    e.eventData = eventData;
-                }
-            } else {
-                le.eventList.add(new Event(timestamp, thisthread, thisthreadname, eventData));
-            }
-            le.nextIndex++;
-
-            if (le.nextIndex >= le.maxCapacity || le.flushNow) {
-                // flush this buffer now
-                DebugEventHistory de = allEvents[eventId];
-                if (de.einfo.enabled) {
-                    le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex);
-                } else {
-                    // global buffer is disabled - don't flush, disable locally
-                    le.enabled = false;
-                    Set<Integer> thisset = this.threadlocalCurrentEvents.get();
-                    thisset.remove(eventId);
-                }
-                le.nextIndex = 0;
-                le.lastFlushTime = timestamp;
-            }
-        }
-    }
-
-    @Override
-    public void flushEvents() {
-        LocalEventHistory[] thishist = this.threadlocalEvents.get();
-        Set<Integer> thisset = this.threadlocalCurrentEvents.get();
-        long timestamp = System.currentTimeMillis();
-        ArrayList<Integer> temp = new ArrayList<Integer>();
-
-        for (int eventId : thisset) {
-            LocalEventHistory le = thishist[eventId];
-            if (le != null && le.nextIndex > 0 &&
-                    (le.flushNow || (timestamp - le.lastFlushTime) > MIN_FLUSH_DELAY)) {
-                // flush this buffer now
-                DebugEventHistory de = allEvents[eventId];
-                if (de.einfo.enabled) {
-                    le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex);
-                } else {
-                    // global buffer is disabled - don't flush, disable locally
-                    le.enabled = false;
-                    temp.add(eventId);
-                }
-                le.nextIndex = 0;
-                le.lastFlushTime = timestamp;
-            }
-        }
-        for (int eId : temp)
-            thisset.remove(eId);
-
-        // 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[eventId] != null) {
-                thishist[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<DebugEventInfo> getAllEventHistory() {
-        List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
-        for (Map<String, Integer> modev : moduleEvents.values()) {
-            for (int eventId : modev.values()) {
-                DebugEventHistory de = allEvents[eventId];
-                if (de != null) {
-                    List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
-                    for (Event e : de.eventBuffer) {
-                        ret.add(e.getFormattedEvent(de.einfo.eventClass,
-                                                    de.einfo.moduleEventName));
-                    }
-                    moduleEventList.add(new DebugEventInfo(de.einfo, ret));
-                }
-            }
-        }
-        return moduleEventList;
-    }
-
-    @Override
-    public List<DebugEventInfo> getModuleEventHistory(String moduleName) {
-        if (!moduleEvents.containsKey(moduleName)) return Collections.emptyList();
-        List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
-        for (int eventId : moduleEvents.get(moduleName).values()) {
-            DebugEventHistory de = allEvents[eventId];
-            if (de != null) {
-                List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
-                for (Event e : de.eventBuffer) {
-                    ret.add(e.getFormattedEvent(de.einfo.eventClass,
-                                                de.einfo.moduleEventName));
-                }
-                moduleEventList.add(new DebugEventInfo(de.einfo, ret));
-            }
-        }
-        return moduleEventList;
-    }
-
-    @Override
-    public DebugEventInfo getSingleEventHistory(String moduleName, String eventName,
-                                                int last) {
-        if (!moduleEvents.containsKey(moduleName)) return null;
-        Integer eventId = moduleEvents.get(moduleName).get(eventName);
-        if (eventId == null) return null;
-        DebugEventHistory de = allEvents[eventId];
-        if (de != null) {
-            int num = 1;
-            List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
-            for (Event e : de.eventBuffer) {
-                if (num > last)
-                    break;
-                Map<String, String> temp = e.getFormattedEvent(de.einfo.eventClass,
-                                                               de.einfo.moduleEventName);
-                temp.put("#", String.valueOf(num++));
-                ret.add(temp);
-            }
-            return new DebugEventInfo(de.einfo, ret);
-        }
-        return null;
-    }
-
-    @Override
-    public void resetAllEvents() {
-        for (Map<String, Integer> eventMap : moduleEvents.values()) {
-            for (Integer evId : eventMap.values()) {
-                allEvents[evId].eventBuffer.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[evId].eventBuffer.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;
-        DebugEventHistory de = allEvents[eventId];
-        if (de != null) {
-            de.eventBuffer.clear();
-        }
-    }
-
-    @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;
-    }
-
-    //*******************************
-    //   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(IRestApiService.class);
-        return deps;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-        IRestApiService restService =
-                context.getServiceImpl(IRestApiService.class);
-        restService.addRestletRoutable(new DebugEventRoutable());
-        DebugEventAppender.setDebugEventServiceImpl(this);
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java
index 3429675d7b60829c0fa18b9e106ac1cd09b75534..ea44f9af18a800fde6e84742cf28965bb8878b89 100644
--- a/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java
+++ b/src/main/java/net/floodlightcontroller/debugevent/DebugEventAppender.java
@@ -3,28 +3,32 @@ package net.floodlightcontroller.debugevent;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
-import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
+
 import ch.qos.logback.classic.Level;
 import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.core.UnsynchronizedAppenderBase;
 
 public class DebugEventAppender<E> extends UnsynchronizedAppenderBase<E> {
     static IDebugEventService debugEvent;
-    static IEventUpdater<WarnErrorEvent> evWarnError;
-    static Thread debugEventRegistryTask = new Thread() {
-        @Override
-        public void run() {
-            while(DebugEventAppender.debugEvent == null) {
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
-                    return;
+    static IEventCategory<WarnErrorEvent> evWarnError;
+    static final Thread debugEventRegistryTask;
+    static {
+        debugEventRegistryTask = new Thread() {
+            @Override
+            public void run() {
+                while (DebugEventAppender.debugEvent == null) {
+                    try {
+                        Thread.sleep(100);
+                    } catch (InterruptedException e) {
+                        return;
+                    }
                 }
+                // safe to register debugEvent
+                registerDebugEventQueue();
             }
-            //safe to register debugEvent
-            registerDebugEventQueue();
-        }
-    };
+        };
+        debugEventRegistryTask.setDaemon(true);
+    }
 
     @Override
     public void start() {
@@ -32,16 +36,17 @@ public class DebugEventAppender<E> extends UnsynchronizedAppenderBase<E> {
         super.start();
     }
 
-    public static void setDebugEventServiceImpl(IDebugEventService debugEvent) {
+    public static void
+            setDebugEventServiceImpl(IDebugEventService debugEvent) {
         DebugEventAppender.debugEvent = debugEvent;
         // It is now ok to register an event Q - but letting this thread go
         // since it was called from a startUp() routine
     }
 
     /**
-     * The logging system calls append for every log message. This method filters
-     * out the WARN and ERROR message and adds to a debug event queue that can
-     * be accessed via cli or rest-api or gui.
+     * The logging system calls append for every log message. This method
+     * filters out the WARN and ERROR message and adds to a debug event queue
+     * that can be accessed via cli or rest-api or gui.
      */
     @Override
     protected void append(E eventObject) {
@@ -50,24 +55,26 @@ public class DebugEventAppender<E> extends UnsynchronizedAppenderBase<E> {
         }
         if (evWarnError != null) {
             ILoggingEvent ev = ((ILoggingEvent) eventObject);
-            if (ev.getLevel().equals(Level.ERROR) || ev.getLevel().equals(Level.WARN)) {
-                evWarnError.updateEventWithFlush(
-                      new WarnErrorEvent(ev.getFormattedMessage(), ev.getLevel(),
-                                         ev.getThreadName(), ev.getLoggerName()));
+            if (ev.getLevel().equals(Level.ERROR)
+                || ev.getLevel().equals(Level.WARN)) {
+                evWarnError
+                .newEventWithFlush(new WarnErrorEvent(ev.getFormattedMessage(),
+                                                      ev.getLevel(),
+                                                      ev.getThreadName(),
+                                                      ev.getLoggerName()));
             }
         }
     }
 
     private static void registerDebugEventQueue() {
-        try {
-            evWarnError = debugEvent.registerEvent("net.floodlightcontroller.core",
-                                     "warn-error-queue",
-                                     "all WARN and ERROR logs",
-                                     EventType.ALWAYS_LOG, WarnErrorEvent.class,
-                                     100);
-        } catch (MaxEventsRegistered e) {
-            e.printStackTrace();
-        }
+        evWarnError = debugEvent.buildEvent(WarnErrorEvent.class)
+                .setModuleName("net.floodlightcontroller.core")
+                .setEventName("warn-error-queue")
+                .setEventDescription("all WARN and ERROR logs")
+                .setEventType(EventType.ALWAYS_LOG)
+                .setBufferCapacity(100)
+                .setAckable(false)
+                .register();
 
     }
 
@@ -78,14 +85,15 @@ public class DebugEventAppender<E> extends UnsynchronizedAppenderBase<E> {
         @EventColumn(name = "level", description = EventFieldType.OBJECT)
         Level level;
 
-        @EventColumn(name = "threadName", description = EventFieldType.STRING)
+        @EventColumn(name = "threadName",
+                     description = EventFieldType.STRING)
         String threadName;
 
         @EventColumn(name = "logger", description = EventFieldType.OBJECT)
         String logger;
 
-        public WarnErrorEvent(String message, Level level, String threadName,
-                              String logger) {
+        public WarnErrorEvent(String message, Level level,
+                              String threadName, String logger) {
             this.message = message;
             this.level = level;
             this.threadName = threadName;
diff --git a/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java b/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff93c405e9d1ab1c274701de11bbadd3c3d21b1e
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/DebugEventResource.java
@@ -0,0 +1,196 @@
+package net.floodlightcontroller.debugevent;
+
+import java.util.List;
+
+import javax.annotation.concurrent.Immutable;
+
+import net.floodlightcontroller.debugevent.DebugEventService.EventInfo;
+import net.floodlightcontroller.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);
+        }
+
+        public boolean isEnabled() {
+            return enabled;
+        }
+
+        public int getBufferCapacity() {
+            return bufferCapacity;
+        }
+
+        public EventType getEtype() {
+            return etype;
+        }
+
+        public String getEventDesc() {
+            return eventDesc;
+        }
+
+        public String getEventName() {
+            return eventName;
+        }
+
+        public String getModuleName() {
+            return moduleName;
+        }
+
+        public int getNumOfEvents() {
+            return numOfEvents;
+        }
+
+        public boolean isAckable() {
+            return ackable;
+        }
+
+        public List<EventResource> getEvents() {
+            return events;
+        }
+
+        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
new file mode 100644
index 0000000000000000000000000000000000000000..47a4ad77bd3358f24f574056c080ddc7b7ea2139
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/DebugEventService.java
@@ -0,0 +1,712 @@
+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 net.floodlightcontroller.core.IShutdownListener;
+import net.floodlightcontroller.core.IShutdownService;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.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 3e0ac6db32eba864cb27c335553ade8a1bf5cfc6..d3a0cc2d4041e12a45025f4f503041aa4ef9d258 100644
--- a/src/main/java/net/floodlightcontroller/debugevent/Event.java
+++ b/src/main/java/net/floodlightcontroller/debugevent/Event.java
@@ -1,219 +1,122 @@
 package net.floodlightcontroller.debugevent;
 
-import java.lang.ref.SoftReference;
 import java.lang.reflect.Field;
-import java.text.SimpleDateFormat;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 
+import net.floodlightcontroller.debugevent.DebugEventService.EventCategory;
+import net.floodlightcontroller.debugevent.EventResource.EventResourceBuilder;
+import net.floodlightcontroller.debugevent.EventResource.Metadata;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
-import net.floodlightcontroller.devicemanager.SwitchPort;
-import net.floodlightcontroller.packet.IPv4;
-
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.util.HexString;
 
+/**
+ * Generic Event class used to store different categories of events.
+ * DebugEventService uses this class to store each Event instance.
+ * Each {@link EventCategory} has a different object of type <b>EventClass</b>.
+ * This is used internally for all DebugEvent processing. For display via REST
+ * and CLI, it is transformed to {@link EventResource} object.
+ */
 public class Event {
-    long timestamp;
-    long threadId;
-    String threadName;
-    Object eventData;
-    private Map<String, String> returnMap;
-    public Event(long timestamp, long threadId, String threadName, Object eventData) {
-        super();
-        this.timestamp = timestamp;
+    private final long eventInstanceId;
+    private volatile boolean acked;
+    private final long timeMs;
+    private final long threadId;
+    private final String threadName;
+    private final Object eventData;
+
+    public Event(long timeMs, long threadId, String threadName,
+                 Object eventData, long eventInstanceId) {
+        this.timeMs = timeMs;
         this.threadId = threadId;
         this.threadName = threadName;
         this.eventData = eventData;
+        this.eventInstanceId = eventInstanceId;
+        this.acked = false;
     }
 
-    public long getTimestamp() {
-        return timestamp;
-    }
-
-    public void setTimestamp(long timestamp) {
-        this.timestamp = timestamp;
+    public long getTimeMs() {
+        return timeMs;
     }
 
     public long getThreadId() {
         return threadId;
     }
 
-    public void setThreadId(long threadId) {
-        this.threadId = threadId;
-    }
-
     public String getThreadName() {
         return threadName;
     }
 
-    public void setThreadName(String threadName) {
-        this.threadName = threadName;
-    }
-
     public Object geteventData() {
         return eventData;
     }
 
-    public void seteventData(Object eventData) {
-        this.eventData = eventData;
+    public long getEventInstanceId() {
+        return eventInstanceId;
+    }
+
+    public boolean isAcked() {
+        return acked;
+    }
+
+    public void setAcked(boolean acked) {
+        this.acked = acked;
     }
 
     @Override
     public String toString() {
-        return "Event [timestamp=" + timestamp + ", threadId=" + threadId
-               + ", eventData=" + eventData.toString() + "]";
+        return "Event [eventInstanceId=" + eventInstanceId + ", acked="
+               + acked + ", timeMs=" + timeMs + ", threadId=" + threadId
+               + ", threadName=" + threadName + ", eventData=" + eventData
+               + "]";
     }
 
-    public Map<String, String> getFormattedEvent(Class<?> eventClass, String moduleEventName) {
+    public EventResource getFormattedEvent(Class<?> eventClass,
+                                           String moduleEventName) {
         if (eventClass == null || !eventClass.equals(eventData.getClass())) {
-            returnMap = new HashMap<String, String>();
-            returnMap.put("Error", "null event data or event-class does not match event-data");
-            return returnMap;
+            EventResourceBuilder edb = new EventResourceBuilder();
+            edb.dataFields.add(new Metadata("Error",
+                                            "null event data or event-class does not match event-data"));
+            return edb.build();
         }
-        // return cached value if there is one
-        if (returnMap != null)
-            return returnMap;
-
-        returnMap = new HashMap<String, String>();
-        returnMap.put("Timestamp", new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
-                                            .format(timestamp));
-        returnMap.put("Thread Id", String.valueOf(threadId));
-        returnMap.put("Thread Name", String.valueOf(threadName));
-        customFormat(eventClass, eventData, returnMap);
-        return returnMap;
+
+        EventResourceBuilder edb = new EventResourceBuilder();
+        edb.setTimeStamp(timeMs);
+        edb.setThreadId(threadId);
+        edb.setThreadName(threadName);
+        edb.setModuleEventName(moduleEventName);
+        edb.setEventInstanceId(eventInstanceId);
+        edb.setAcked(acked);
+        customFormat(eventClass, eventData, edb);
+        return edb.build();
     }
 
+    @SuppressWarnings("unchecked")
     private void customFormat(Class<?> clazz, Object eventData,
-                              Map<String, String> retMap) {
+                              EventResourceBuilder eventDataBuilder) {
         for (Field f : clazz.getDeclaredFields()) {
             EventColumn ec = f.getAnnotation(EventColumn.class);
             if (ec == null) continue;
             f.setAccessible(true);
             try {
-                Object obj =  f.get(eventData);
-
-                switch(ec.description()) {
-                    case DPID:
-                        retMap.put(ec.name(), HexString.toHexString((Long) obj));
-                        break;
-                    case MAC:
-                        retMap.put(ec.name(), HexString.toHexString((Long) obj, 6));
-                        break;
-                    case IPv4:
-                        retMap.put(ec.name(), IPv4.fromIPv4Address((Integer) obj));
-                        break;
-                    case FLOW_MOD_FLAGS:
-                        int flags = (Integer)obj;
-                        StringBuilder builder = new StringBuilder();
-                        if (flags == 0) {
-                            builder.append("None");
-                        }
-                        else {
-                            if ((flags & OFFlowMod.OFPFF_SEND_FLOW_REM) != 0) {
-                                builder.append("SEND_FLOW_REM ");
-                            }
-                            if ((flags & OFFlowMod.OFPFF_CHECK_OVERLAP) != 0) {
-                                builder.append("CHECK_OVERLAP ");
-                            }
-                            if ((flags & OFFlowMod.OFPFF_EMERG) != 0) {
-                                builder.append("EMERG ");
-                            }
-                        }
-                        retMap.put(ec.name(), builder.toString());
-                        break;
-                    case LIST_IPV4:
-                        @SuppressWarnings("unchecked")
-                        List<Integer> ipv4Addresses = (List<Integer>)obj;
-                        StringBuilder ipv4AddressesStr = new StringBuilder();
-                        if (ipv4Addresses.size() == 0) {
-                            ipv4AddressesStr.append("--");
-                        } else {
-                            for (Integer ipv4Addr : ipv4Addresses) {
-                                ipv4AddressesStr.append(IPv4.fromIPv4Address(ipv4Addr.intValue()));
-                                ipv4AddressesStr.append(" ");
-                            }
-                        }
-                        retMap.put(ec.name(), ipv4AddressesStr.toString());
-                        break;
-                    case LIST_ATTACHMENT_POINT:
-                        @SuppressWarnings("unchecked")
-                        List<SwitchPort> aps = (List<SwitchPort>)obj;
-                        StringBuilder apsStr = new StringBuilder();
-                        if (aps.size() == 0) {
-                            apsStr.append("--");
-                        } else {
-                            for (SwitchPort ap : aps) {
-                                apsStr.append(HexString.toHexString(ap.getSwitchDPID()));
-                                apsStr.append("/");
-                                apsStr.append(ap.getPort());
-                                apsStr.append(" ");
-                            }
-                        }
-                        retMap.put(ec.name(), apsStr.toString());
-                        break;
-                    case LIST_OBJECT:
-                        @SuppressWarnings("unchecked")
-                        List<Object> obl = (List<Object>)obj;
-                        StringBuilder sbldr = new StringBuilder();
-                        if (obl.size() == 0) {
-                            sbldr.append("--");
-                        } else {
-                            for (Object o : obl) {
-                                sbldr.append(o.toString());
-                                sbldr.append(" ");
-                            }
-                        }
-                        retMap.put(ec.name(), sbldr.toString());
-                        break;
-                    case SREF_LIST_OBJECT:
-                        @SuppressWarnings("unchecked")
-                        SoftReference<List<Object>> srefListObj =
-                            (SoftReference<List<Object>>)obj;
-                        List<Object> ol = srefListObj.get();
-                        if (ol != null) {
-                            StringBuilder sb = new StringBuilder();
-                            if (ol.size() == 0) {
-                                sb.append("--");
-                            } else {
-                                for (Object o : ol) {
-                                    sb.append(o.toString());
-                                    sb.append(" ");
-                                }
-                            }
-                            retMap.put(ec.name(), sb.toString());
-                        } else {
-                            retMap.put(ec.name(), "-- reference not available --");
-                        }
-                        break;
-                    case SREF_OBJECT:
-                        @SuppressWarnings("unchecked")
-                        SoftReference<Object> srefObj = (SoftReference<Object>)obj;
-                        if (srefObj == null) {
-                            retMap.put(ec.name(), "--");
-                        } else {
-                            Object o = srefObj.get();
-                            if (o != null) {
-                                retMap.put(ec.name(), o.toString());
-                            } else {
-                                retMap.put(ec.name(),
-                                           "-- reference not available --");
-                            }
-                        }
-                        break;
-                    case STRING:
-                    case OBJECT:
-                    case PRIMITIVE:
-                    default:
-                        retMap.put(ec.name(), obj.toString());
+                Object obj = f.get(eventData);
+                @SuppressWarnings("rawtypes")
+                CustomFormatter cf = DebugEventService.customFormatter.get(ec.description());
+
+                if (cf == null) {
+                    throw new IllegalArgumentException(
+                                                       "CustomFormatter for "
+                                                               + ec.description()
+                                                               + " does not exist.");
+                } else {
+                    cf.customFormat(obj, ec.name(), eventDataBuilder);
                 }
             } catch (ClassCastException e) {
-                retMap.put("Error", e.getMessage());
+                eventDataBuilder.dataFields.add(new Metadata("Error",
+                                                             e.getMessage()));
             } catch (IllegalArgumentException e) {
-                retMap.put("Error", e.getMessage());
+                eventDataBuilder.dataFields.add(new Metadata("Error",
+                                                             e.getMessage()));
             } catch (IllegalAccessException e) {
-                retMap.put("Error", e.getMessage());
+                eventDataBuilder.dataFields.add(new Metadata("Error",
+                                                             e.getMessage()));
             }
         }
     }
diff --git a/src/main/java/net/floodlightcontroller/debugevent/EventResource.java b/src/main/java/net/floodlightcontroller/debugevent/EventResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ce52b53bf55ff15c054412cc808479a857a4a29
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/EventResource.java
@@ -0,0 +1,258 @@
+package net.floodlightcontroller.debugevent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.concurrent.Immutable;
+
+import java.util.Date;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Event Instance of a particular event category. This is only for REST purpose.
+ * Actual {@link Event} class consists of Object of Event. Here we parse it into
+ * its string form using {@link getCustomFormatter} and return for REST and CLI.
+ */
+@Immutable
+public class EventResource {
+    private final Date timestamp;
+    private final long threadId;
+    private final String threadName;
+    private final String moduleEventName;
+    private final ImmutableList<Metadata> dataFields;
+    // NOTE: this is only for CLI purpose. cascaded fields show up as
+    // different tables in CLI which is not very useful
+    private final String dataString;
+    long eventInstanceId;
+    boolean acked;
+
+    private EventResource(EventResourceBuilder evInstanceBuilder) {
+        this.timestamp = evInstanceBuilder.timestamp;
+        this.threadId = evInstanceBuilder.threadId;
+        this.threadName = evInstanceBuilder.threadName;
+        this.moduleEventName = evInstanceBuilder.moduleEventName;
+        this.dataFields = ImmutableList.copyOf(evInstanceBuilder.dataFields);
+        this.dataString = this.dataFields.toString();
+        this.eventInstanceId = evInstanceBuilder.eventInstanceId;
+        this.acked = evInstanceBuilder.acked;
+    }
+
+    public Date getTimestamp() {
+        return timestamp;
+    }
+
+    public String getModuleEventName() {
+        return moduleEventName;
+    }
+
+    public List<Metadata> getDataFields() {
+        return dataFields;
+    }
+
+    public String getDataString() {
+        return dataString;
+    }
+
+    public long getEventInstanceId() {
+        return eventInstanceId;
+    }
+
+    public boolean isAcked() {
+        return acked;
+    }
+
+    public static class EventResourceBuilder {
+        private Date timestamp;
+        private long threadId;
+        private String threadName;
+        private String moduleEventName;
+        protected List<Metadata> dataFields;
+        long eventInstanceId;
+        boolean acked;
+
+        public EventResourceBuilder() {
+            this.dataFields = new ArrayList<Metadata>();
+        }
+
+        public EventResource build() {
+            return new EventResource(this);
+        }
+
+        public Date getTimestamp() {
+            return timestamp;
+        }
+
+        public void setTimeStamp(long timeMs) {
+            this.timestamp = new Date(timeMs);
+        }
+
+        public long getThreadId() {
+            return threadId;
+        }
+
+        public void setThreadId(long threadId) {
+            this.threadId = threadId;
+        }
+
+        public String getThreadName() {
+            return threadName;
+        }
+
+        public void setThreadName(String threadName) {
+            this.threadName = threadName;
+        }
+
+        public String getModuleEventName() {
+            return moduleEventName;
+        }
+
+        public void setModuleEventName(String moduleEventName) {
+            this.moduleEventName = moduleEventName;
+        }
+
+        public List<Metadata> getDataFields() {
+            return dataFields;
+        }
+
+        public void setDataFields(List<Metadata> dataFields) {
+            this.dataFields = dataFields;
+        }
+
+        public long getEventInstanceId() {
+            return eventInstanceId;
+        }
+
+        public void setEventInstanceId(long eventInstanceId) {
+            this.eventInstanceId = eventInstanceId;
+        }
+
+        public boolean isAcked() {
+            return acked;
+        }
+
+        public void setAcked(boolean acked) {
+            this.acked = acked;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result
+                 + ((dataFields == null) ? 0 : dataFields.hashCode());
+        result = prime * result
+                 + ((dataString == null) ? 0 : dataString.hashCode());
+        result = prime
+                 * result
+                 + ((moduleEventName == null) ? 0
+                                             : moduleEventName.hashCode());
+        result = prime * result + (int) (threadId ^ (threadId >>> 32));
+        result = prime * result
+                 + ((threadName == null) ? 0 : threadName.hashCode());
+        result = prime * result
+                 + ((timestamp == null) ? 0 : timestamp.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;
+        EventResource other = (EventResource) obj;
+        if (dataFields == null) {
+            if (other.dataFields != null) return false;
+        } else if (!dataFields.equals(other.dataFields)) return false;
+        if (dataString == null) {
+            if (other.dataString != null) return false;
+        } else if (!dataString.equals(other.dataString)) return false;
+        if (moduleEventName == null) {
+            if (other.moduleEventName != null) return false;
+        } else if (!moduleEventName.equals(other.moduleEventName))
+                                                                  return false;
+        if (threadId != other.threadId) return false;
+        if (threadName == null) {
+            if (other.threadName != null) return false;
+        } else if (!threadName.equals(other.threadName)) return false;
+        if (timestamp == null) {
+            if (other.timestamp != null) return false;
+        } else if (!timestamp.equals(other.timestamp)) return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(moduleEventName);
+        builder.append(" ");
+        builder.append(timestamp);
+        builder.append(", threadId=");
+        builder.append(threadId);
+        builder.append(", threadName=\"");
+        builder.append(threadName);
+        builder.append("\", dataFields=");
+        builder.append(dataFields);
+        builder.append(", eventInstanceId=");
+        builder.append(eventInstanceId);
+        builder.append(", acked=");
+        builder.append(acked);
+        return builder.toString();
+    }
+
+    /**
+     * Actual {@link Event} has Object of Event. The fields of that Object are
+     * converted to {@literal String} and returned as {@link Metadata} with
+     * {@link EventResource}
+     */
+    @Immutable
+    public static class Metadata {
+        private final String eventClass;
+        private final String eventData;
+
+        public Metadata(String eventClass, String eventData) {
+            this.eventClass = eventClass;
+            this.eventData = eventData;
+        }
+
+        public String getEventClass() {
+            return eventClass;
+        }
+
+        public String getEventData() {
+            return eventData;
+        }
+
+        @Override
+        public String toString() {
+            return this.eventClass + ":" + this.eventData;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result
+                     + ((eventClass == null) ? 0 : eventClass.hashCode());
+            result = prime * result
+                     + ((eventData == null) ? 0 : eventData.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;
+            Metadata other = (Metadata) obj;
+            if (eventClass == null) {
+                if (other.eventClass != null) return false;
+            } else if (!eventClass.equals(other.eventClass)) return false;
+            if (eventData == null) {
+                if (other.eventData != null) return false;
+            } else if (!eventData.equals(other.eventData)) return false;
+            return true;
+        }
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java b/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java
index d54e9f632af539f53ecdd9e4b2b4477cba8d79d5..c2a0fcdd95db1235614011b4d97713d31ba28162 100644
--- a/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java
+++ b/src/main/java/net/floodlightcontroller/debugevent/IDebugEventService.java
@@ -5,39 +5,47 @@ 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;
+import net.floodlightcontroller.debugevent.DebugEventResource.EventInfoResource;
+import net.floodlightcontroller.debugevent.DebugEventService.EventCategory;
+import net.floodlightcontroller.debugevent.DebugEventService.EventCategoryBuilder;
 
 public interface IDebugEventService extends IFloodlightService {
 
     /**
-     * Different event types. Events that are meant to be logged on demand
-     * need to be separately enabled/disabled.
+     * 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
+        ALWAYS_LOG, LOG_ON_DEMAND
+    }
+
+    /**
+     * Is the Event <b>ACKABLE</b> or <b>NOT_ACKABLE</b>
+     */
+    public enum AckableEvent {
+        ACKABLE, NOT_ACKABLE
     }
 
     /**
      * 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
+        DPID, IPv4, MAC, STRING, OBJECT, PRIMITIVE, COLLECTION_IPV4,
+        COLLECTION_ATTACHMENT_POINT, COLLECTION_OBJECT, SREF_COLLECTION_OBJECT,
+        SREF_OBJECT
     }
 
     /**
-     * EventColumn is the only annotation given to the fields of the event
-     * when updating an event.
+     * 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;
     }
 
@@ -48,82 +56,52 @@ public interface IDebugEventService extends IFloodlightService {
     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.
+     * Returns an {@link EventCategoryBuilder} that can be used to build a new
+     * {@link EventCategory}. Before calling the {@literal build} method, set
+     * the following parameters:
      *
-     * @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
+     * @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
      * @throws MaxEventsRegistered
      */
-    public <T> IEventUpdater<T> registerEvent(String moduleName, String eventName,
-                                              String eventDescription,
-                                              EventType eventType,
-                                              Class<T> eventClass,
-                                              int bufferCapacity,
-                                              String... metaData)
-                                                      throws MaxEventsRegistered;
+    public <T> EventCategoryBuilder<T> buildEvent(Class<T> evClass);
 
     /**
-     * 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.
+     * 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);
+    public boolean containsModuleEventName(String moduleName,
+                                           String eventName);
 
     /**
-     * Determine if any events have been registered for module of name moduleName
+     * Determine if any events have been registered for module of name
+     * moduleName
      */
     public boolean containsModuleName(String moduleName);
 
@@ -131,29 +109,35 @@ public interface IDebugEventService extends IFloodlightService {
      * 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
+     * @return a list of all event histories or an empty list if no events have
+     *         been registered
      */
-    public List<DebugEventInfo> getAllEventHistory();
+    public List<EventInfoResource> 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
+     * @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);
+    public List<EventInfoResource> 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
+     * @param moduleName
+     *            registered module name
+     * @param eventName
+     *            registered event name for moduleName
+     * @param numOfEvents
+     *            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);
+    public EventInfoResource getSingleEventHistory(String moduleName,
+                                                   String eventName,
+                                                   int numOfEvents);
 
     /**
      * Wipe out all event history for all registered events
@@ -161,16 +145,21 @@ public interface IDebugEventService extends IFloodlightService {
     public void resetAllEvents();
 
     /**
-     * Wipe out all event history for all events registered for a specific module
+     * Wipe out all event history for all events registered for a specific
+     * module
      *
-     * @param moduleName  registered module name
+     * @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
+     *
+     * @param moduleName
+     *            registered module name
+     * @param eventName
+     *            registered event name for moduleName
      */
     public void resetSingleEvent(String moduleName, String eventName);
 
@@ -181,9 +170,24 @@ public interface IDebugEventService extends IFloodlightService {
     public List<String> getModuleList();
 
     /**
-     * Returns a list of all events registered for a specific moduleName
-     * or a empty list
+     * Returns a list of all events registered for a specific moduleName or a
+     * empty list
      */
     public List<String> getModuleEventList(String moduleName);
 
+    /**
+     * Sets the 'ack' for the individual {@link DebugEventService} instance
+     * pointed by the <b>eventId</b> and <b>eventInstanceId</b> given in the
+     * PATCH request <br/>
+     * Returns void
+     *
+     * @param eventId
+     *            unique event queue identifier
+     * @param eventInstanceId
+     *            unique event identifier
+     * @param ack
+     *            boolean ack - true or false
+     */
+    public void setAck(int eventId, long eventInstanceId, boolean ack);
+
 }
diff --git a/src/main/java/net/floodlightcontroller/debugevent/IEventCategory.java b/src/main/java/net/floodlightcontroller/debugevent/IEventCategory.java
new file mode 100644
index 0000000000000000000000000000000000000000..ebd17e45e821cd07214bd838de824bac5d168f3a
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/debugevent/IEventCategory.java
@@ -0,0 +1,30 @@
+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 immediately 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/IEventUpdater.java b/src/main/java/net/floodlightcontroller/debugevent/IEventUpdater.java
deleted file mode 100644
index 7aec38f44aa1b7637c00a180226761ecc30511a7..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/IEventUpdater.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package net.floodlightcontroller.debugevent;
-
-/**
- * eventUPdater is used to log events for pre-registered events.
- */
-public interface IEventUpdater<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 updateEventNoFlush(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 updateEventWithFlush(T event);
-
-
-
-}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/NullDebugEvent.java b/src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java
similarity index 58%
rename from src/main/java/net/floodlightcontroller/debugevent/NullDebugEvent.java
rename to src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java
index 7d479ea6df9242691e7b23e9dcfc72cab8b9a340..cf43d81469f2369c48f68cae97fa9a5d3b37339d 100644
--- a/src/main/java/net/floodlightcontroller/debugevent/NullDebugEvent.java
+++ b/src/main/java/net/floodlightcontroller/debugevent/MockDebugEventService.java
@@ -11,55 +11,25 @@ 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 NullDebugEvent implements IFloodlightModule, IDebugEventService {
-
-
-    @Override
-    public void flushEvents() {
-
-    }
-
-    @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;
-    }
+public class MockDebugEventService implements IFloodlightModule, IDebugEventService {
 
     @Override
-    public void init(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-
+    public <T> EventCategoryBuilder<T> buildEvent(Class<T> evClass) {
+        DebugEventService des = new DebugEventService();
+        return des.buildEvent(evClass);
     }
 
     @Override
-    public void startUp(FloodlightModuleContext context)
-            throws FloodlightModuleException {
+    public void flushEvents() {
 
     }
 
     @Override
-    public boolean containsModuleEventName(String moduleName, String eventName) {
+    public boolean containsModuleEventName(String moduleName,
+                                           String eventName) {
         return false;
     }
 
@@ -69,18 +39,19 @@ public class NullDebugEvent implements IFloodlightModule, IDebugEventService {
     }
 
     @Override
-    public List<DebugEventInfo> getAllEventHistory() {
+    public List<EventInfoResource> getAllEventHistory() {
         return Collections.emptyList();
     }
 
     @Override
-    public List<DebugEventInfo> getModuleEventHistory(String param) {
+    public List<EventInfoResource> getModuleEventHistory(String moduleName) {
         return Collections.emptyList();
     }
 
     @Override
-    public DebugEventInfo getSingleEventHistory(String moduleName, String eventName,
-                                                int last) {
+    public EventInfoResource getSingleEventHistory(String moduleName,
+                                                   String eventName,
+                                                   int numOfEvents) {
         return null;
     }
 
@@ -100,36 +71,57 @@ public class NullDebugEvent implements IFloodlightModule, IDebugEventService {
     }
 
     @Override
-    public <T> IEventUpdater<T>
-            registerEvent(String moduleName, String eventName,
-                          String eventDescription, EventType eventType,
-                          Class<T> eventClass, int bufferCapacity,
-                          String... metaData) throws MaxEventsRegistered {
-        return new NullEventImpl<T>();
+    public List<String> getModuleList() {
+        return Collections.emptyList();
     }
 
-    public class NullEventImpl<T> implements IEventUpdater<T> {
-
-        @Override
-        public void updateEventNoFlush(Object event) {
+    @Override
+    public List<String> getModuleEventList(String moduleName) {
+        return Collections.emptyList();
+    }
 
-        }
+    @Override
+    public void setAck(int eventId, long eventInstanceId, boolean ack) {
 
-        @Override
-        public void updateEventWithFlush(Object event) {
+    }
 
-        }
+    @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 List<String> getModuleList() {
-        return Collections.emptyList();
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleDependencies() {
+        return null;
     }
 
     @Override
-    public List<String> getModuleEventList(String moduleName) {
-        return Collections.emptyList();
+    public
+            void
+            init(FloodlightModuleContext context)
+                                                 throws FloodlightModuleException {
+
     }
 
+    @Override
+    public
+            void
+            startUp(FloodlightModuleContext context)
+                                                    throws FloodlightModuleException {
+
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResource.java b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResource.java
deleted file mode 100644
index a3f06ceaf3f7ab615ae062d9e4d35d02117eb4e9..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResource.java
+++ /dev/null
@@ -1,322 +0,0 @@
-package net.floodlightcontroller.debugevent.web;
-
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import net.floodlightcontroller.debugevent.IDebugEventService.DebugEventInfo;
-import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
-
-import org.restlet.resource.Get;
-import org.restlet.resource.Post;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Web interface for Debug Events
- *
- * @author Saurav
- */
-public class DebugEventResource extends DebugEventResourceBase {
-    protected static Logger logger =
-            LoggerFactory.getLogger(DebugEventResource.class);
-
-    /**
-     * The output JSON model that contains the counter information
-     */
-    public static class DebugEventInfoOutput {
-        protected class DEInfo {
-            private final boolean enabled;
-            private final int bufferCapacity;
-            private final EventType eventType;
-            private final String eventDesc;
-            private final String eventName;
-            private final String moduleName;
-            private final String[] metaData;
-            private final List<Map<String,String>> eventHistory;
-
-            DEInfo(DebugEventInfo dei) {
-                this.moduleName = dei.getEventInfo().getModuleName();
-                this.eventName = dei.getEventInfo().getEventName();
-                this.eventDesc = dei.getEventInfo().getEventDesc();
-                this.metaData = dei.getEventInfo().getMetaData();
-                this.enabled = dei.getEventInfo().isEnabled();
-                this.eventType = dei.getEventInfo().getEtype();
-                this.bufferCapacity = dei.getEventInfo().getBufferCapacity();
-                this.eventHistory = dei.getEvents();
-            }
-            public boolean isEnabled() {
-                return enabled;
-            }
-            public int getBufferCapacity() {
-                return bufferCapacity;
-            }
-            public String getEventDesc() {
-                return eventDesc;
-            }
-            public String getEventName() {
-                return eventName;
-            }
-            public String getModuleName() {
-                return moduleName;
-            }
-            public String[] getMetaData() {
-                return metaData;
-            }
-            public EventType getEventType() {
-                return eventType;
-            }
-            public List<Map<String,String>> getEventHistory() {
-                return eventHistory;
-            }
-
-        }
-
-        public Map<String, DEInfo> eventMap = null;
-        public List<String> names = null;
-        public String error = null;
-
-        DebugEventInfoOutput(boolean getList) {
-            if (!getList) {
-                eventMap = new HashMap<String, DEInfo>();
-            }
-        }
-        public Map<String, DEInfo> getEventMap() {
-            return eventMap;
-        }
-        public List<String> getNames() {
-            return names;
-        }
-        public String getError() {
-            return error;
-        }
-
-    }
-
-    public enum Option {
-        ALL, ONE_MODULE, ONE_MODULE_EVENT, ERROR_BAD_MODULE_NAME, ERROR_BAD_PARAM,
-        ERROR_BAD_MODULE_EVENT_NAME
-    }
-
-    public static class DebugEventPost {
-        public Boolean reset;
-
-        public Boolean getReset() {
-            return reset;
-        }
-        public void setReset(Boolean reset) {
-            this.reset = reset;
-        }
-    }
-
-    public static class ResetOutput {
-        String error = null;
-
-        public String getError() {
-            return error;
-        }
-        public void setError(String error) {
-            this.error = error;
-        }
-    }
-
-    /**
-     * Reset events
-     *
-     * If using curl:
-     * curl -X POST -d {\"reset\":true} -H "Content-Type: application/json" URL
-     * where URL must be in one of the following forms for resetting registered events:
-     * "http://{controller-hostname}:8080/wm/debugevent/
-     * "http://{controller-hostname}:8080/wm/debugevent/{param1}
-     * "http://{controller-hostname}:8080/wm/debugevent/{param1}/{param2}
-     *
-     * Not giving {param1} will reset all events
-     * {param1} can be 'all' or the name of a module. The former case will reset
-     * all events, while the latter will reset all events for the moduleName (if
-     * param2 is null).{param2} must be an eventName for the given moduleName to
-     * reset a specific event.
-     */
-    @Post
-    public ResetOutput postHandler(DebugEventPost postData) {
-        ResetOutput output = new ResetOutput();
-        String param1 = (String)getRequestAttributes().get("param1");
-        String param2 = (String)getRequestAttributes().get("param2");
-
-        if (postData.getReset() != null && postData.getReset()) {
-            Option choice = Option.ERROR_BAD_PARAM;
-
-            if (param1 == null) {
-                param1 = "all";
-                choice = Option.ALL;
-            } else if (param1.equals("all")) {
-                choice = Option.ALL;
-            } else if (param2 == null) {
-                boolean isRegistered = debugEvent.containsModuleName(param1);
-                if (isRegistered) {
-                    choice = Option.ONE_MODULE;
-                } else {
-                    choice = Option.ERROR_BAD_MODULE_NAME;
-                }
-            } else {
-                // differentiate between disabled and non-existing events
-                boolean isRegistered = debugEvent.containsModuleEventName(param1, param2);
-                if (isRegistered) {
-                    choice = Option.ONE_MODULE_EVENT;
-                } else {
-                    choice = Option.ERROR_BAD_MODULE_EVENT_NAME;
-                }
-            }
-
-            switch (choice) {
-                case ALL:
-                    debugEvent.resetAllEvents();
-                    break;
-                case ONE_MODULE:
-                    debugEvent.resetAllModuleEvents(param1);
-                    break;
-                case ONE_MODULE_EVENT:
-                    debugEvent.resetSingleEvent(param1, param2);
-                    break;
-                case ERROR_BAD_MODULE_NAME:
-                    output.error = "Module name has no corresponding registered events";
-                    break;
-                case ERROR_BAD_MODULE_EVENT_NAME:
-                    output.error = "Event not registered";
-                    break;
-                case ERROR_BAD_PARAM:
-                    output.error = "Bad param";
-            }
-        }
-
-        return output;
-
-    }
-
-    /**
-     * Return the debug event data for the get rest-api call
-     *
-     * URL must be in one of the following forms for retrieving a list
-     * moduleNames    "http://{controller-hostname}:8080/wm/debugevent/
-     * counterNames   "http://{controller-hostname}:8080/wm/debugevent/{moduleName}
-     *
-     * URL must be in one of the following forms for retrieving event data:
-     * "http://{controller-hostname}:8080/wm/debugevent/{param1}
-     * "http://{controller-hostname}:8080/wm/debugevent/{param1}/{param2}
-     *
-     *  where {param1} must be one of (no quotes):
-     *       null                   if nothing is given then by default the list
-     *                              of all moduleNames is returned for which
-     *                              events have been registered
-     *       "all"                  can return value/info on all active events
-     *                              but is currently disallowed
-     *       "{moduleName}"         returns value/info on events for the specified module
-     *                              depending on the value of param2
-     *  and   {param2} must be one of (no quotes):
-     *       null                   returns all eventNames registered for the
-     *                              given moduleName (in param1)
-     *       "{eventName}"          returns value/info for specific event if it is active.
-     *
-     */
-    @Get("json")
-    public DebugEventInfoOutput handleEventInfoQuery() {
-        Option choice = Option.ERROR_BAD_PARAM;
-        DebugEventInfoOutput output;
-        String laststr = getQueryValue("last");
-        int last = Integer.MAX_VALUE;
-        try {
-            if (laststr != null)
-                last = Integer.valueOf(laststr);
-            if (last < 1) last = Integer.MAX_VALUE;
-        } catch (NumberFormatException e) {
-            output = new DebugEventInfoOutput(false);
-            output.error = "Expected an integer requesting last X events;" +
-                           " received " + laststr;
-            return output;
-        }
-        String param1 = (String)getRequestAttributes().get("param1");
-        String param2 = (String)getRequestAttributes().get("param2");
-
-        if (param1 == null) {
-            output = new DebugEventInfoOutput(true);
-            return listEvents(output);
-        } else if (param1.equals("all")) {
-            output = new DebugEventInfoOutput(false);
-            //populateEvents(debugEvent.getAllEventHistory(), output);
-            output.error = "Cannot retrieve all events - please select a specific event";
-            return output;
-        }
-
-        if (param2 == null) {
-            output = new DebugEventInfoOutput(true);
-            boolean isRegistered = debugEvent.containsModuleName(param1);
-            if (isRegistered) {
-                return listEvents(param1, output);
-            } else {
-                choice = Option.ERROR_BAD_MODULE_NAME;
-            }
-        } else if (param2.equals("all")) {
-            output = new DebugEventInfoOutput(false);
-            //choice = Option.ONE_MODULE;
-            output.error = "Cannot retrieve all events - please select a specific event";
-            return output;
-        } else {
-            // differentiate between disabled and non-existing events
-            boolean isRegistered = debugEvent.containsModuleEventName(param1, param2);
-            if (isRegistered) {
-                choice = Option.ONE_MODULE_EVENT;
-            } else {
-                choice = Option.ERROR_BAD_MODULE_EVENT_NAME;
-            }
-        }
-
-        output = new DebugEventInfoOutput(false);
-        switch (choice) {
-            case ONE_MODULE:
-                populateEvents(debugEvent.getModuleEventHistory(param1), output);
-                break;
-            case ONE_MODULE_EVENT:
-                populateSingleEvent(debugEvent.getSingleEventHistory(param1, param2, last),
-                                    output);
-                break;
-            case ERROR_BAD_MODULE_NAME:
-                output.error = "Module name has no corresponding registered events";
-                break;
-            case ERROR_BAD_MODULE_EVENT_NAME:
-                output.error = "Event not registered";
-                break;
-            case ERROR_BAD_PARAM:
-            default:
-                output.error = "Bad param";
-        }
-
-        return output;
-    }
-
-    private DebugEventInfoOutput listEvents(DebugEventInfoOutput output) {
-        output.names = debugEvent.getModuleList();
-        return output;
-    }
-
-    private DebugEventInfoOutput listEvents(String moduleName,
-                                            DebugEventInfoOutput output) {
-        output.names = debugEvent.getModuleEventList(moduleName);
-        return output;
-    }
-
-    private void populateSingleEvent(DebugEventInfo singleEventHistory,
-                                     DebugEventInfoOutput output) {
-        if (singleEventHistory != null) {
-            output.eventMap.put(singleEventHistory.getEventInfo().getModuleEventName(),
-                                output.new DEInfo(singleEventHistory));
-        }
-    }
-
-    private void populateEvents(List<DebugEventInfo> eventHistory,
-                                DebugEventInfoOutput output) {
-        if (eventHistory != null) {
-            for (DebugEventInfo de : eventHistory)
-                populateSingleEvent(de, output);
-        }
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResourceBase.java b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResourceBase.java
deleted file mode 100644
index 964deeb7467bf70d1b8e6e3578743ded26415558..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventResourceBase.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.floodlightcontroller.debugevent.web;
-
-
-import net.floodlightcontroller.debugevent.IDebugEventService;
-
-import org.restlet.resource.ResourceException;
-import org.restlet.resource.ServerResource;
-
-public class DebugEventResourceBase extends ServerResource{
-    protected IDebugEventService debugEvent;
-
-    @Override
-    protected void doInit() throws ResourceException {
-        super.doInit();
-        debugEvent = (IDebugEventService)getContext().getAttributes().
-                get(IDebugEventService.class.getCanonicalName());
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventRoutable.java b/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventRoutable.java
deleted file mode 100644
index d4ee7c6fd1b21ccaf63ad588c16993fcb91f6ed0..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/debugevent/web/DebugEventRoutable.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.floodlightcontroller.debugevent.web;
-
-import org.restlet.Context;
-import org.restlet.Restlet;
-import org.restlet.routing.Router;
-
-import net.floodlightcontroller.restserver.RestletRoutable;
-
-public class DebugEventRoutable implements RestletRoutable {
-
-    @Override
-    public Restlet getRestlet(Context context) {
-        Router router = new Router(context);
-        router.attach("/{param1}/{param2}/", DebugEventResource.class);
-        router.attach("/{param1}/{param2}", DebugEventResource.class);
-        router.attach("/{param1}/", DebugEventResource.class);
-        router.attach("/{param1}", DebugEventResource.class);
-        router.attach("/", DebugEventResource.class);
-        return router;
-    }
-
-    @Override
-    public String basePath() {
-        return "/wm/debugevent";
-    }
-
-}
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java b/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java
index 4593b7bac9d8f4b25f9a3c1e5c4693bfd1a0fca0..4d5ba9be6d5d5ef7f31a4316cb92d2303a62502f 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java
@@ -19,6 +19,10 @@ 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 
@@ -37,7 +41,7 @@ public interface IDevice {
      * Get the MAC address of the device as a Long value.
      * @return the MAC address for the device
      */
-    public long getMACAddress();
+    public MacAddress getMACAddress();
 
     /**
      * Get the MAC address of the device as a String value.
@@ -50,13 +54,13 @@ public interface IDevice {
      * entities, then the value -1 will be returned.
      * @return an array containing all unique VLAN IDs for the device.
      */
-    public Short[] getVlanId();
+    public VlanVid[] getVlanId();
     
     /**
      * Get all unique IPv4 addresses associated with the device.
      * @return an array containing the unique IPv4 addresses for the device.
      */
-    public Integer[] getIPv4Addresses();
+    public IPv4Address[] getIPv4Addresses();
     
     /**
      * Get all unique attachment points associated with the device.  This will
@@ -85,7 +89,7 @@ public interface IDevice {
      * @param swp the switch port to query
      * @return an array containing the unique VLAN IDs
      */
-    public Short[] getSwitchPortVlanIds(SwitchPort swp);
+    public VlanVid[] 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 eb3801344f73d68ab0c35e6db556c09edfa1ba68..40d729f6894149d9a1e3142c618bc606c0753a4b 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java
@@ -22,6 +22,12 @@ 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;
 
@@ -95,9 +101,9 @@ public interface IDeviceService extends IFloodlightService {
      * @throws IllegalArgumentException if not all key fields of the
      * current {@link IEntityClassifierService} are specified.
      */
-    public IDevice findDevice(long macAddress, Short vlan,
-                              Integer ipv4Address, Long switchDPID,
-                              Integer switchPort)
+    public IDevice findDevice(MacAddress macAddress, VlanVid vlan,
+                              IPv4Address ipv4Address, DatapathId switchDPID,
+                              OFPort switchPort)
                               throws IllegalArgumentException;
     
     /**
@@ -122,8 +128,8 @@ public interface IDeviceService extends IFloodlightService {
      * source's {@link IEntityClass} are specified.
      */
     public IDevice findClassDevice(IEntityClass entityClass,
-                                   long macAddress, Short vlan,
-                                   Integer ipv4Address)
+                                   MacAddress macAddress, VlanVid vlan,
+                                   IPv4Address ipv4Address)
                                    throws IllegalArgumentException;
 
     /**
@@ -162,11 +168,11 @@ public interface IDeviceService extends IFloodlightService {
      * @see IDeviceService#queryClassDevices(IEntityClass, Long, 
      * Short, Integer, Long, Integer)
      */
-    public Iterator<? extends IDevice> queryDevices(Long macAddress,
-                                                    Short vlan,
-                                                    Integer ipv4Address, 
-                                                    Long switchDPID,
-                                                    Integer switchPort);
+    public Iterator<? extends IDevice> queryDevices(MacAddress macAddress,
+                                                    VlanVid vlan,
+                                                    IPv4Address ipv4Address, 
+                                                    DatapathId switchDPID,
+                                                    OFPort switchPort);
 
     /**
      * Find devices that match the provided query.  Only the index for
@@ -187,11 +193,11 @@ public interface IDeviceService extends IFloodlightService {
      * Short, Integer, Long, Integer)
      */
     public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass,
-                                                         Long macAddress,
-                                                         Short vlan,
-                                                         Integer ipv4Address, 
-                                                         Long switchDPID,
-                                                         Integer switchPort);
+                                                         MacAddress macAddress,
+                                                         VlanVid vlan,
+                                                         IPv4Address ipv4Address, 
+                                                         DatapathId switchDPID,
+                                                         OFPort switchPort);
     
     /**
      * Adds a listener to listen for IDeviceManagerServices notifications
@@ -207,9 +213,9 @@ public interface IDeviceService extends IFloodlightService {
      * @param sw
      * @param port
      */
-    public void addSuppressAPs(long swId, short port);
+    public void addSuppressAPs(DatapathId swId, OFPort port);
 
-    public void removeSuppressAPs(long swId, short port);
+    public void removeSuppressAPs(DatapathId swId, OFPort port);
 
     public Set<SwitchPort> getSuppressAPs();
 
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassifierService.java b/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassifierService.java
index 2569a7df54ed892464810ca415b12a52d1ea76a7..f3e17ccfea12f90ff7136f79eb78a19d4bc94d1a 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassifierService.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/IEntityClassifierService.java
@@ -80,8 +80,7 @@ public interface IEntityClassifierService extends IFloodlightService {
     * @param entity the entity to reclassify
     * @return the IEntityClass resulting from the classification
     */
-   IEntityClass reclassifyEntity(IDevice curDevice,
-                                             Entity entity);
+   IEntityClass reclassifyEntity(IDevice curDevice, Entity entity);
 
    /**
     * Once reclassification is complete for a device, this method will be
@@ -95,8 +94,7 @@ public interface IEntityClassifierService extends IFloodlightService {
     * @param newDevices all the new devices derived from the entities of the
     * old device.  If null, the old device was unchanged.
     */
-   void deviceUpdate(IDevice oldDevice, 
-                     Collection<? extends IDevice> newDevices);
+   void deviceUpdate(IDevice oldDevice, Collection<? extends IDevice> newDevices);
 
    /**
     * Adds a listener to listen for IEntityClassifierServices notifications
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java b/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java
index 9fe62d9507c0d2e575bebaa8bdcc86b8c15676a4..d057f9c4a353f0501631f6cf7725fd00d4be5b4e 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/SwitchPort.java
@@ -17,7 +17,8 @@
 
 package net.floodlightcontroller.devicemanager;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
 
 import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
 
@@ -55,8 +56,8 @@ public class SwitchPort {
         }
     }
 
-    private final long switchDPID;
-    private final int port;
+    private final DatapathId switchDPID;
+    private final OFPort port;
     private final ErrorStatus errorStatus;
 
     /**
@@ -65,7 +66,7 @@ public class SwitchPort {
      * @param port the port
      * @param errorStatus any error status for the switch port
      */
-    public SwitchPort(long switchDPID, int port, ErrorStatus errorStatus) {
+    public SwitchPort(DatapathId switchDPID, OFPort port, ErrorStatus errorStatus) {
         super();
         this.switchDPID = switchDPID;
         this.port = port;
@@ -77,7 +78,7 @@ public class SwitchPort {
      * @param switchDPID the dpid
      * @param port the port
      */
-    public SwitchPort(long switchDPID, int port) {
+    public SwitchPort(DatapathId switchDPID, OFPort port) {
         super();
         this.switchDPID = switchDPID;
         this.port = port;
@@ -89,11 +90,11 @@ public class SwitchPort {
     // ***************
 
     @JsonSerialize(using=DPIDSerializer.class)
-    public long getSwitchDPID() {
+    public DatapathId getSwitchDPID() {
         return switchDPID;
     }
 
-    public int getPort() {
+    public OFPort getPort() {
         return port;
     }
 
@@ -113,8 +114,8 @@ public class SwitchPort {
                         + ((errorStatus == null)
                                 ? 0
                                 : errorStatus.hashCode());
-        result = prime * result + port;
-        result = prime * result + (int) (switchDPID ^ (switchDPID >>> 32));
+        result = prime * result + port.getPortNumber();
+        result = prime * result + (int) (switchDPID.getLong() ^ (switchDPID.getLong() >>> 32));
         return result;
     }
 
@@ -132,7 +133,7 @@ public class SwitchPort {
 
     @Override
     public String toString() {
-        return "SwitchPort [switchDPID=" + HexString.toHexString(switchDPID) +
+        return "SwitchPort [switchDPID=" + switchDPID.toString() +
                ", 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 a08a3a5d2cb723582cf422b5ca988a22ac61e3f2..da7490f1ef9a9e80983aa48fad27f39242580779 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java
@@ -21,11 +21,16 @@
 
 package net.floodlightcontroller.devicemanager.internal;
 
+import java.util.Date;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+
 public class AttachmentPoint {
-    long  sw;
-    short port;
-    long  activeSince;
-    long  lastSeen;
+    DatapathId  sw;
+    OFPort port;
+    Date  activeSince;
+    Date  lastSeen;
 
     // Timeout for moving attachment points from OF/broadcast
     // domain to another.
@@ -34,15 +39,14 @@ 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(long sw, short port, long activeSince,
-                           long lastSeen) {
+    public AttachmentPoint(DatapathId sw, OFPort port, Date activeSince, Date lastSeen) {
         this.sw = sw;
         this.port = port;
         this.activeSince = activeSince;
         this.lastSeen = lastSeen;
     }
 
-    public AttachmentPoint(long sw, short port, long lastSeen) {
+    public AttachmentPoint(DatapathId sw, OFPort port, Date lastSeen) {
         this.sw = sw;
         this.port = port;
         this.lastSeen = lastSeen;
@@ -50,37 +54,37 @@ public class AttachmentPoint {
     }
 
     public AttachmentPoint(AttachmentPoint ap) {
-        this.sw = ap.sw;
+        this.sw = ap.getSw();
         this.port = ap.port;
         this.activeSince = ap.activeSince;
         this.lastSeen = ap.lastSeen;
     }
 
-    public long getSw() {
+    public DatapathId getSw() {
         return sw;
     }
-    public void setSw(long sw) {
+    public void setSw(DatapathId sw) {
         this.sw = sw;
     }
-    public short getPort() {
+    public OFPort getPort() {
         return port;
     }
-    public void setPort(short port) {
+    public void setPort(OFPort port) {
         this.port = port;
     }
-    public long getActiveSince() {
+    public Date getActiveSince() {
         return activeSince;
     }
-    public void setActiveSince(long activeSince) {
+    public void setActiveSince(Date activeSince) {
         this.activeSince = activeSince;
     }
-    public long getLastSeen() {
+    public Date getLastSeen() {
         return lastSeen;
     }
-    public void setLastSeen(long lastSeen) {
-        if (this.lastSeen + INACTIVITY_INTERVAL < lastSeen)
+    public void setLastSeen(Date lastSeen) {
+        if (this.lastSeen.getTime() + INACTIVITY_INTERVAL < lastSeen.getTime())
             this.activeSince = lastSeen;
-        if (this.lastSeen < lastSeen)
+        if (this.lastSeen.before(lastSeen))
             this.lastSeen = lastSeen;
     }
 
@@ -91,8 +95,8 @@ public class AttachmentPoint {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + port;
-        result = prime * result + (int) (sw ^ (sw >>> 32));
+        result = prime * result + port.getPortNumber();
+        result = prime * result + (int) (sw.getLong() ^ (sw.getLong() >>> 32));
         return result;
     }
 
@@ -108,9 +112,9 @@ public class AttachmentPoint {
         if (getClass() != obj.getClass())
             return false;
         AttachmentPoint other = (AttachmentPoint) obj;
-        if (port != other.port)
+        if (port.getPortNumber() != other.port.getPortNumber())
             return false;
-        if (sw != other.sw)
+        if (sw.getLong() != other.sw.getLong())
             return false;
         return true;
     }
@@ -118,7 +122,7 @@ public class AttachmentPoint {
     @Override
     public String toString() {
         return "AttachmentPoint [sw=" + sw + ", port=" + port
-               + ", activeSince=" + activeSince + ", lastSeen=" + lastSeen
+               + ", activeSince=" + activeSince + ", lastSeen=" + lastSeen.toString()
                + "]";
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java
index faed0d4016147080ce254122b02fa6b8f5c4975f..ea55f8cac2bba0f33746375ff96b40a8ad6825f4 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DefaultEntityClassifier.java
@@ -68,8 +68,7 @@ public class DefaultEntityClassifier implements
     static {
         keyFields = EnumSet.of(DeviceField.MAC, DeviceField.VLAN);
     }
-    protected static DefaultEntityClass entityClass =
-        new DefaultEntityClass("DefaultEntityClass");
+    protected static DefaultEntityClass entityClass = new DefaultEntityClass("DefaultEntityClass");
 
     @Override
     public IEntityClass classifyEntity(Entity entity) {
@@ -77,14 +76,12 @@ public class DefaultEntityClassifier implements
     }
 
     @Override
-    public IEntityClass reclassifyEntity(IDevice curDevice,
-                                                     Entity entity) {
+    public IEntityClass reclassifyEntity(IDevice curDevice, Entity entity) {
         return entityClass;
     }
 
     @Override
-    public void deviceUpdate(IDevice oldDevice, 
-                             Collection<? extends IDevice> newDevices) {
+    public void deviceUpdate(IDevice oldDevice, Collection<? extends IDevice> newDevices) {
         // no-op
     }
 
@@ -95,8 +92,7 @@ public class DefaultEntityClassifier implements
 
     @Override
     public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l = 
-                new ArrayList<Class<? extends IFloodlightService>>();
+        Collection<Class<? extends IFloodlightService>> l =  new ArrayList<Class<? extends IFloodlightService>>();
         l.add(IEntityClassifierService.class);
         return l;
     }
@@ -104,24 +100,20 @@ public class DefaultEntityClassifier implements
     @Override
     public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
         Map<Class<? extends IFloodlightService>,
-        IFloodlightService> m = 
-        new HashMap<Class<? extends IFloodlightService>,
-                    IFloodlightService>();
+        IFloodlightService> m = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
         // We are the class that implements the service
         m.put(IEntityClassifierService.class, this);
         return m;
     }
 
     @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleDependencies() {
+    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
         // No dependencies
         return null;
     }
 
     @Override
-    public void init(FloodlightModuleContext context)
-                                                 throws FloodlightModuleException {
+    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
         // no-op
     }
 
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
index ef0ba346809496090c83e273be35c5576699369c..5b663e3246df6b42c74cb5fe80f6525486716969 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
@@ -30,7 +30,12 @@ import java.util.Map;
 import java.util.TreeSet;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import org.openflow.util.HexString;
+
+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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,8 +45,6 @@ import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.IEntityClass;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus;
-import net.floodlightcontroller.packet.Ethernet;
-import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.topology.ITopologyService;
 
 /**
@@ -50,8 +53,7 @@ import net.floodlightcontroller.topology.ITopologyService;
  */
 @JsonSerialize(using=DeviceSerializer.class)
 public class Device implements IDevice {
-    protected static Logger log =
-            LoggerFactory.getLogger(Device.class);
+    protected static Logger log = LoggerFactory.getLogger(Device.class);
 
     private final Long deviceKey;
     protected final DeviceManagerImpl deviceManager;
@@ -61,7 +63,7 @@ public class Device implements IDevice {
 
     protected final String macAddressString;
     // the vlan Ids from the entities of this device
-    protected final Short[] vlanIds;
+    protected final VlanVid[] vlanIds;
     protected volatile String dhcpClientName;
 
     /**
@@ -85,15 +87,12 @@ public class Device implements IDevice {
      * @param entity the initial entity for the device
      * @param entityClass the entity classes associated with the entity
      */
-    public Device(DeviceManagerImpl deviceManager,
-                  Long deviceKey,
-                  Entity entity,
-                  IEntityClass entityClass) {
+    public Device(DeviceManagerImpl deviceManager, Long deviceKey,
+                  Entity entity, IEntityClass entityClass) {
         this.deviceManager = deviceManager;
         this.deviceKey = deviceKey;
         this.entities = new Entity[] {entity};
-        this.macAddressString =
-                HexString.toHexString(entity.getMacAddress(), 6);
+        this.macAddressString = entity.getMacAddress().toString();
         this.entityClass = entityClass;
         Arrays.sort(this.entities);
 
@@ -101,16 +100,13 @@ public class Device implements IDevice {
         this.oldAPs = null;
         this.attachmentPoints = null;
 
-        if (entity.getSwitchDPID() != null &&
-                entity.getSwitchPort() != null){
-            long sw = entity.getSwitchDPID();
-            short port = entity.getSwitchPort().shortValue();
+        if (entity.getSwitchDPID() != null && entity.getSwitchPort() != null) {
+            DatapathId sw = entity.getSwitchDPID();
+            OFPort port = entity.getSwitchPort();
 
             if (deviceManager.isValidAttachmentPoint(sw, port)) {
                 AttachmentPoint ap;
-                ap = new AttachmentPoint(sw, port,
-                                         entity.getLastSeenTimestamp().getTime());
-
+                ap = new AttachmentPoint(sw, port, entity.getLastSeenTimestamp());
                 this.attachmentPoints = new ArrayList<AttachmentPoint>();
                 this.attachmentPoints.add(ap);
             }
@@ -139,15 +135,12 @@ public class Device implements IDevice {
         this.oldAPs = null;
         this.attachmentPoints = null;
         if (oldAPs != null) {
-            this.oldAPs =
-                    new ArrayList<AttachmentPoint>(oldAPs);
+            this.oldAPs = new ArrayList<AttachmentPoint>(oldAPs);
         }
         if (attachmentPoints != null) {
-            this.attachmentPoints =
-                    new ArrayList<AttachmentPoint>(attachmentPoints);
+            this.attachmentPoints = new ArrayList<AttachmentPoint>(attachmentPoints);
         }
-        this.macAddressString =
-                HexString.toHexString(this.entities[0].getMacAddress(), 6);
+        this.macAddressString = this.entities[0].getMacAddress().toString();
         this.entityClass = entityClass;
         Arrays.sort(this.entities);
         vlanIds = computeVlandIds();
@@ -165,31 +158,26 @@ public class Device implements IDevice {
      *        new entity should be inserted. If negative we will compute the
      *        correct insertion point
      */
-    public Device(Device device,
-                  Entity newEntity,
-                  int insertionpoint) {
+    public Device(Device device, Entity newEntity, int insertionpoint) {
         this.deviceManager = device.deviceManager;
         this.deviceKey = device.deviceKey;
         this.dhcpClientName = device.dhcpClientName;
 
         this.entities = new Entity[device.entities.length + 1];
         if (insertionpoint < 0) {
-            insertionpoint = -(Arrays.binarySearch(device.entities,
-                                                   newEntity)+1);
+            insertionpoint = -(Arrays.binarySearch(device.entities, newEntity) + 1);
         }
         if (insertionpoint > 0) {
             // insertion point is not the beginning:
             // copy up to insertion point
-            System.arraycopy(device.entities, 0,
-                             this.entities, 0,
-                             insertionpoint);
+            System.arraycopy(device.entities, 0, this.entities, 0, insertionpoint);
         }
         if (insertionpoint < device.entities.length) {
             // insertion point is not the end
             // copy from insertion point
             System.arraycopy(device.entities, insertionpoint,
-                             this.entities, insertionpoint+1,
-                             device.entities.length-insertionpoint);
+                             this.entities, insertionpoint + 1,
+                             device.entities.length - insertionpoint);
         }
         this.entities[insertionpoint] = newEntity;
         /*
@@ -200,39 +188,36 @@ public class Device implements IDevice {
         */
         this.oldAPs = null;
         if (device.oldAPs != null) {
-            this.oldAPs =
-                    new ArrayList<AttachmentPoint>(device.oldAPs);
+            this.oldAPs = new ArrayList<AttachmentPoint>(device.oldAPs);
         }
         this.attachmentPoints = null;
         if (device.attachmentPoints != null) {
-            this.attachmentPoints =
-                    new ArrayList<AttachmentPoint>(device.attachmentPoints);
+            this.attachmentPoints = new ArrayList<AttachmentPoint>(device.attachmentPoints);
         }
 
-        this.macAddressString =
-                HexString.toHexString(this.entities[0].getMacAddress(), 6);
+        this.macAddressString = this.entities[0].getMacAddress().toString();
 
         this.entityClass = device.entityClass;
         vlanIds = computeVlandIds();
     }
 
-    private Short[]  computeVlandIds() {
+    private VlanVid[] computeVlandIds() {
         if (entities.length == 1) {
             if (entities[0].getVlan() != null) {
-                return new Short[]{ entities[0].getVlan() };
+                return new VlanVid[]{ entities[0].getVlan() };
             } else {
-                return new Short[] { Short.valueOf((short)-1) };
+                return new VlanVid[] { VlanVid.ofVlan(-1) };
             }
         }
 
-        TreeSet<Short> vals = new TreeSet<Short>();
+        TreeSet<VlanVid> vals = new TreeSet<VlanVid>();
         for (Entity e : entities) {
             if (e.getVlan() == null)
-                vals.add((short)-1);
+                vals.add(VlanVid.ofVlan(-1));
             else
                 vals.add(e.getVlan());
         }
-        return vals.toArray(new Short[vals.size()]);
+        return vals.toArray(new VlanVid[vals.size()]);
     }
 
     /**
@@ -241,7 +226,7 @@ public class Device implements IDevice {
      * @param apList
      * @return
      */
-    private Map<Long, AttachmentPoint> getAPMap(List<AttachmentPoint> apList) {
+    private Map<DatapathId, AttachmentPoint> getAPMap(List<AttachmentPoint> apList) {
 
         if (apList == null) return null;
         ITopologyService topology = deviceManager.topology;
@@ -254,7 +239,7 @@ public class Device implements IDevice {
         List<AttachmentPoint>tempAP =
                 new ArrayList<AttachmentPoint>();
         for(AttachmentPoint ap: oldAP) {
-            if (deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort())){
+            if (deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort())) {
                 tempAP.add(ap);
             }
         }
@@ -263,16 +248,15 @@ public class Device implements IDevice {
         Collections.sort(oldAP, deviceManager.apComparator);
 
         // Map of attachment point by L2 domain Id.
-        Map<Long, AttachmentPoint> apMap = new HashMap<Long, AttachmentPoint>();
+        Map<DatapathId, AttachmentPoint> apMap = new HashMap<DatapathId, AttachmentPoint>();
 
         for(int i=0; i<oldAP.size(); ++i) {
             AttachmentPoint ap = oldAP.get(i);
             // if this is not a valid attachment point, continue
-            if (!deviceManager.isValidAttachmentPoint(ap.getSw(),
-                                                      ap.getPort()))
+            if (!deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort()))
                 continue;
 
-            long id = topology.getL2DomainId(ap.getSw());
+            DatapathId id = topology.getL2DomainId(ap.getSw());
             apMap.put(id, ap);
         }
 
@@ -293,9 +277,9 @@ public class Device implements IDevice {
         if (apList == null) return false;
 
         for(AttachmentPoint ap: apList) {
-            if (ap.getLastSeen() + AttachmentPoint.INACTIVITY_INTERVAL <
-                    System.currentTimeMillis())
+            if (ap.getLastSeen().getTime() + AttachmentPoint.INACTIVITY_INTERVAL < System.currentTimeMillis()) {
                 expiredAPs.add(ap);
+            }
         }
         if (expiredAPs.size() > 0) {
             apList.removeAll(expiredAPs);
@@ -315,25 +299,23 @@ public class Device implements IDevice {
      * @param apMap
      * @return
      */
-    List<AttachmentPoint> getDuplicateAttachmentPoints(List<AttachmentPoint>oldAPList,
-                                                       Map<Long, AttachmentPoint>apMap) {
+    List<AttachmentPoint> getDuplicateAttachmentPoints(List<AttachmentPoint>oldAPList, Map<DatapathId, AttachmentPoint>apMap) {
         ITopologyService topology = deviceManager.topology;
         List<AttachmentPoint> dupAPs = new ArrayList<AttachmentPoint>();
-        long timeThreshold = System.currentTimeMillis() -
-                AttachmentPoint.INACTIVITY_INTERVAL;
+        long timeThreshold = System.currentTimeMillis() - AttachmentPoint.INACTIVITY_INTERVAL;
 
         if (oldAPList == null || apMap == null)
             return dupAPs;
 
-        for(AttachmentPoint ap: oldAPList) {
-            long id = topology.getL2DomainId(ap.getSw());
+        for(AttachmentPoint ap : oldAPList) {
+            DatapathId id = topology.getL2DomainId(ap.getSw());
             AttachmentPoint trueAP = apMap.get(id);
 
             if (trueAP == null) continue;
             boolean c = (topology.isConsistent(trueAP.getSw(), trueAP.getPort(),
                                               ap.getSw(), ap.getPort()));
-            boolean active = (ap.getActiveSince() > trueAP.getActiveSince());
-            boolean last = ap.getLastSeen() > timeThreshold;
+            boolean active = (ap.getActiveSince().after(trueAP.getActiveSince()));
+            boolean last = ap.getLastSeen().getTime() > timeThreshold;
             if (!c && active && last) {
                 dupAPs.add(ap);
             }
@@ -357,7 +339,7 @@ public class Device implements IDevice {
 
         List<AttachmentPoint> apList = new ArrayList<AttachmentPoint>();
         if (attachmentPoints != null) apList.addAll(attachmentPoints);
-        Map<Long, AttachmentPoint> newMap = getAPMap(apList);
+        Map<DatapathId, AttachmentPoint> newMap = getAPMap(apList);
         if (newMap == null || newMap.size() != apList.size()) {
             moved = true;
         }
@@ -365,8 +347,7 @@ public class Device implements IDevice {
         // Prepare the new attachment point list.
         if (moved) {
             log.info("updateAttachmentPoint: ap {}  newmap {} ", attachmentPoints, newMap);
-            List<AttachmentPoint> newAPList =
-                    new ArrayList<AttachmentPoint>();
+            List<AttachmentPoint> newAPList = new ArrayList<AttachmentPoint>();
             if (newMap != null) newAPList.addAll(newMap.values());
             this.attachmentPoints = newAPList;
         }
@@ -385,7 +366,7 @@ public class Device implements IDevice {
      * @param lastSeen
      * @return
      */
-    protected boolean updateAttachmentPoint(long sw, short port, long lastSeen){
+    protected boolean updateAttachmentPoint(DatapathId sw, OFPort port, Date lastSeen){
         ITopologyService topology = deviceManager.topology;
         List<AttachmentPoint> oldAPList;
         List<AttachmentPoint> apList;
@@ -412,7 +393,7 @@ public class Device implements IDevice {
         // newAP now contains the new attachment point.
 
         // Get the APMap is null or empty.
-        Map<Long, AttachmentPoint> apMap = getAPMap(apList);
+        Map<DatapathId, AttachmentPoint> apMap = getAPMap(apList);
         if (apMap == null || apMap.isEmpty()) {
             apList.add(newAP);
             attachmentPoints = apList;
@@ -423,11 +404,10 @@ public class Device implements IDevice {
             return true;
         }
 
-        long id = topology.getL2DomainId(sw);
+        DatapathId id = topology.getL2DomainId(sw);
         AttachmentPoint oldAP = apMap.get(id);
 
-        if (oldAP == null) // No attachment on this L2 domain.
-        {
+        if (oldAP == null) { // No attachment on this L2 domain.
             apList = new ArrayList<AttachmentPoint>();
             apList.addAll(apMap.values());
             apList.add(newAP);
@@ -439,7 +419,7 @@ public class Device implements IDevice {
         // we need to compare oldAP and newAP.
         if (oldAP.equals(newAP)) {
             // nothing to do here. just the last seen has to be changed.
-            if (newAP.lastSeen > oldAP.lastSeen) {
+            if (newAP.lastSeen.after(oldAP.lastSeen)) {
                 oldAP.setLastSeen(newAP.lastSeen);
             }
             this.attachmentPoints =
@@ -480,9 +460,9 @@ public class Device implements IDevice {
      * @param port
      * @return
      */
-    public boolean deleteAttachmentPoint(long sw, short port) {
-        AttachmentPoint ap = new AttachmentPoint(sw, port, 0);
-
+    public boolean deleteAttachmentPoint(DatapathId sw, OFPort port) {
+        AttachmentPoint ap = new AttachmentPoint(sw, port, new Date(0));
+        
         if (this.oldAPs != null) {
             ArrayList<AttachmentPoint> apList = new ArrayList<AttachmentPoint>();
             apList.addAll(this.oldAPs);
@@ -506,7 +486,7 @@ public class Device implements IDevice {
         return false;
     }
 
-    public boolean deleteAttachmentPoint(long sw) {
+    public boolean deleteAttachmentPoint(DatapathId sw) {
         boolean deletedFlag;
         ArrayList<AttachmentPoint> apList;
         ArrayList<AttachmentPoint> modifiedList;
@@ -519,7 +499,7 @@ public class Device implements IDevice {
         modifiedList = new ArrayList<AttachmentPoint>();
 
         for(AttachmentPoint ap: apList) {
-            if (ap.getSw() == sw) {
+            if (ap.getSw().equals(sw)) {
                 deletedFlag = true;
             } else {
                 modifiedList.add(ap);
@@ -538,7 +518,7 @@ public class Device implements IDevice {
         modifiedList = new ArrayList<AttachmentPoint>();
 
         for(AttachmentPoint ap: apList) {
-            if (ap.getSw() == sw) {
+            if (ap.getSw().equals(sw)) {
                 deletedFlag = true;
             } else {
                 modifiedList.add(ap);
@@ -617,7 +597,7 @@ public class Device implements IDevice {
 
         List<AttachmentPoint> dupList;
         // get AP map.
-        Map<Long, AttachmentPoint> apMap = getAPMap(apList);
+        Map<DatapathId, AttachmentPoint> apMap = getAPMap(apList);
         dupList = this.getDuplicateAttachmentPoints(oldAPList, apMap);
         if (dupList != null) {
             for(AttachmentPoint ap: dupList) {
@@ -636,7 +616,7 @@ public class Device implements IDevice {
     }
 
     @Override
-    public long getMACAddress() {
+    public MacAddress getMACAddress() {
         // we assume only one MAC per device for now.
         return entities[0].getMacAddress();
     }
@@ -647,18 +627,18 @@ public class Device implements IDevice {
     }
 
     @Override
-    public Short[] getVlanId() {
+    public VlanVid[] getVlanId() {
         return Arrays.copyOf(vlanIds, vlanIds.length);
     }
 
     static final EnumSet<DeviceField> ipv4Fields = EnumSet.of(DeviceField.IPV4);
 
     @Override
-    public Integer[] getIPv4Addresses() {
+    public IPv4Address[] getIPv4Addresses() {
         // XXX - TODO we can cache this result.  Let's find out if this
         // is really a performance bottleneck first though.
 
-        TreeSet<Integer> vals = new TreeSet<Integer>();
+        TreeSet<IPv4Address> vals = new TreeSet<IPv4Address>();
         for (Entity e : entities) {
             if (e.getIpv4Address() == null) continue;
 
@@ -689,22 +669,22 @@ public class Device implements IDevice {
                 vals.add(e.getIpv4Address());
         }
 
-        return vals.toArray(new Integer[vals.size()]);
+        return vals.toArray(new IPv4Address[vals.size()]);
     }
 
     @Override
-    public Short[] getSwitchPortVlanIds(SwitchPort swp) {
-        TreeSet<Short> vals = new TreeSet<Short>();
+    public VlanVid[] getSwitchPortVlanIds(SwitchPort swp) {
+        TreeSet<VlanVid> vals = new TreeSet<VlanVid>();
         for (Entity e : entities) {
             if (e.switchDPID == swp.getSwitchDPID()
                     && e.switchPort == swp.getPort()) {
                 if (e.getVlan() == null)
-                    vals.add(Ethernet.VLAN_UNTAGGED);
+                    vals.add(VlanVid.ofVlan(-1)); //TODO @Ryan is this the correct way to represent an untagged vlan?
                 else
                     vals.add(e.getVlan());
             }
         }
-        return vals.toArray(new Short[vals.size()]);
+        return vals.toArray(new VlanVid[vals.size()]);
     }
 
     @Override
@@ -782,11 +762,11 @@ public class Device implements IDevice {
         builder.append(macAddressString);
         builder.append(", IPs=[");
         boolean isFirst = true;
-        for (Integer ip: getIPv4Addresses()) {
+        for (IPv4Address ip: getIPv4Addresses()) {
             if (!isFirst)
                 builder.append(", ");
             isFirst = false;
-            builder.append(IPv4.fromIPv4Address(ip));
+            builder.append(ip.toString());
         }
         builder.append("], APs=");
         builder.append(Arrays.toString(getAttachmentPoints(true)));
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java
index 0d8ea75dd42466600e9abf24637903750479985c..0c5100498a87c1c94736a90e793d1968c282283e 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIndex.java
@@ -71,8 +71,9 @@ public abstract class DeviceIndex {
      * update will not fail because of a concurrent update 
      * @param device the device to update
      * @param deviceKey the device key for the device
+     * @return 
      */
-    public abstract void updateIndex(Entity entity, Long deviceKey);
+    public abstract boolean updateIndex(Entity entity, Long deviceKey);
 
     /**
      * Remove the entry for the given entity
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java
index 2cbea66e5577495461171661f479c4f26335f11f..7d4d0c35a9c141eb08a82ea52e7283993bdbafaa 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceIterator.java
@@ -19,6 +19,13 @@ package net.floodlightcontroller.devicemanager.internal;
 
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
+
+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;
@@ -30,11 +37,11 @@ import net.floodlightcontroller.util.FilterIterator;
 public class DeviceIterator extends FilterIterator<Device> {
     private IEntityClass[] entityClasses;
     
-    private Long macAddress;
-    private Short vlan;
-    private Integer ipv4Address; 
-    private Long switchDPID;
-    private Integer switchPort;
+    private MacAddress macAddress;
+    private VlanVid vlan;
+    private IPv4Address ipv4Address; 
+    private DatapathId switchDPID;
+    private OFPort switchPort;
     
     /**
      * Construct a new device iterator over the key fields
@@ -48,11 +55,11 @@ public class DeviceIterator extends FilterIterator<Device> {
      */
     public DeviceIterator(Iterator<Device> subIterator, 
                           IEntityClass[] entityClasses,
-                          Long macAddress,
-                          Short vlan, 
-                          Integer ipv4Address, 
-                          Long switchDPID,
-                          Integer switchPort) {
+                          MacAddress macAddress,
+                          VlanVid vlan, 
+                          IPv4Address ipv4Address, 
+                          DatapathId switchDPID,
+                          OFPort switchPort) {
         super(subIterator);
         this.entityClasses = entityClasses;
         this.subIterator = subIterator;
@@ -80,18 +87,31 @@ public class DeviceIterator extends FilterIterator<Device> {
             if (!match) return false;                
         }
         if (macAddress != null) {
-            if (macAddress.longValue() != value.getMACAddress())
+            if (!macAddress.equals(value.getMACAddress()))
                 return false;
         }
         if (vlan != null) {
-            Short[] vlans = value.getVlanId();
-            if (Arrays.binarySearch(vlans, vlan) < 0) 
+            VlanVid[] vlans = value.getVlanId();
+            List<VlanVid> searchableVlanList = Arrays.asList(vlans);
+            if (!searchableVlanList.contains(vlan)) {
+            	return false;
+            }
+            /*TODO @Ryan Does the above replace the below?
+             * Maybe should change the return of Device to be List/ArrayList instead
+            if (Arrays.binarySearch(vlans.vlans, vlan) < 0) 
                 return false;
+            */
         }
         if (ipv4Address != null) {
-            Integer[] ipv4Addresses = value.getIPv4Addresses();
-            if (Arrays.binarySearch(ipv4Addresses, ipv4Address) < 0) 
+            IPv4Address[] ipv4Addresses = value.getIPv4Addresses();
+            /*TODO @Ryan same here...
+               if (Arrays.binarySearch(ipv4Addresses, ipv4Address) < 0) 
                 return false;
+             */
+            List<IPv4Address> searchableIPv4AddrList = Arrays.asList(ipv4Addresses);
+            if (!searchableIPv4AddrList.contains(ipv4Address)) {
+            	return false;
+            }
         }
         if (switchDPID != null || switchPort != null) {
             SwitchPort[] sps = value.getAttachmentPoints();
@@ -100,11 +120,11 @@ public class DeviceIterator extends FilterIterator<Device> {
             match = false;
             for (SwitchPort sp : sps) {
                 if (switchDPID != null) {
-                    if (switchDPID.longValue() != sp.getSwitchDPID())
+                    if (switchDPID.getLong() != sp.getSwitchDPID().getLong())
                         return false;
                 }
                 if (switchPort != null) {
-                    if (switchPort.intValue() != sp.getPort())
+                    if (switchPort.getPortNumber() != sp.getPort().getPortNumber())
                         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 e4f67420bed7489558a389dd6714c14b57451766..63aad5e3ebfafda042543217f1370f1aad69867e 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.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.HARole;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -56,16 +56,12 @@ import net.floodlightcontroller.core.util.ListenerDispatcher;
 import net.floodlightcontroller.core.util.SingletonTask;
 import net.floodlightcontroller.debugcounter.IDebugCounter;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
-import net.floodlightcontroller.debugcounter.NullDebugCounter;
-import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
+import net.floodlightcontroller.debugevent.DebugEventService.EventCategoryBuilder;
 import net.floodlightcontroller.debugevent.IDebugEventService;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
-import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
-import net.floodlightcontroller.debugevent.IEventUpdater;
-import net.floodlightcontroller.debugevent.NullDebugEvent;
+import net.floodlightcontroller.debugevent.IEventCategory;
 import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.devicemanager.IEntityClass;
@@ -93,14 +89,21 @@ import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.topology.ITopologyListener;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.util.MultiIterator;
+import net.floodlightcontroller.util.OFMatchWithSwDpid;
 import static net.floodlightcontroller.devicemanager.internal.
 DeviceManagerImpl.DeviceUpdate.Change.*;
 
-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.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+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.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
 import org.sdnplatform.sync.IClosableIterator;
 import org.sdnplatform.sync.IStoreClient;
 import org.sdnplatform.sync.ISyncService;
@@ -117,1329 +120,1281 @@ import org.slf4j.LoggerFactory;
  * within the network.
  * @author readams
  */
-public class DeviceManagerImpl implements
-IDeviceService, IOFMessageListener, ITopologyListener,
-IFloodlightModule, IEntityClassListener,
-IFlowReconcileListener, IInfoProvider {
-    protected static Logger logger =
-            LoggerFactory.getLogger(DeviceManagerImpl.class);
-
-
-    protected IFloodlightProviderService floodlightProvider;
-    protected ITopologyService topology;
-    protected IStorageSourceService storageSource;
-    protected IRestApiService restApi;
-    protected IThreadPoolService threadPool;
-    protected IFlowReconcileService flowReconcileMgr;
-    protected IFlowReconcileEngineService flowReconcileEngine;
-    protected IDebugCounterService debugCounters;
-    private ISyncService syncService;
-    private IStoreClient<String,DeviceSyncRepresentation> storeClient;
-    private DeviceSyncManager deviceSyncManager;
-
-    /**
-     * Debug Counters
-     */
-    public static final String MODULE_NAME = "devicemanager";
-    public static final String PACKAGE = DeviceManagerImpl.class.getPackage().getName();
-    public IDebugCounter cntIncoming;
-    public IDebugCounter cntReconcileRequest;
-    public IDebugCounter cntReconcileNoSource;
-    public IDebugCounter cntReconcileNoDest;
-    public IDebugCounter cntInvalidSource;
-    public IDebugCounter cntInvalidDest;
-    public IDebugCounter cntNoSource;
-    public IDebugCounter cntNoDest;
-    public IDebugCounter cntDhcpClientNameSnooped;
-    public IDebugCounter cntDeviceOnInternalPortNotLearned;
-    public IDebugCounter cntPacketNotAllowed;
-    public IDebugCounter cntNewDevice;
-    public IDebugCounter cntPacketOnInternalPortForKnownDevice;
-    public IDebugCounter cntNewEntity;
-    public IDebugCounter cntDeviceChanged;
-    public IDebugCounter cntDeviceMoved;
-    public IDebugCounter cntCleanupEntitiesRuns;
-    public IDebugCounter cntEntityRemovedTimeout;
-    public IDebugCounter cntDeviceDeleted;
-    public IDebugCounter cntDeviceReclassifyDelete;
-    public IDebugCounter cntDeviceStrored;
-    public IDebugCounter cntDeviceStoreThrottled;
-    public IDebugCounter cntDeviceRemovedFromStore;
-    public IDebugCounter cntSyncException;
-    public IDebugCounter cntDevicesFromStore;
-    public IDebugCounter cntConsolidateStoreRuns;
-    public IDebugCounter cntConsolidateStoreDevicesRemoved;
-    public IDebugCounter cntTransitionToMaster;
-
-    /**
-     * Debug Events
-     */
-    private IDebugEventService debugEvents;
-    private IEventUpdater<DeviceEvent> evDevice;
-
-    private boolean isMaster = false;
-
-    static final String DEVICE_SYNC_STORE_NAME =
-            DeviceManagerImpl.class.getCanonicalName() + ".stateStore";
-
-    /**
-     * Time interval between writes of entries for the same device to
-     * the sync store.
-     */
-    static final int DEFAULT_SYNC_STORE_WRITE_INTERVAL_MS =
-            5*60*1000; // 5 min
-    private int syncStoreWriteIntervalMs = DEFAULT_SYNC_STORE_WRITE_INTERVAL_MS;
-
-    /**
-     * Time after SLAVE->MASTER until we run the consolidate store
-     * code.
-     */
-    static final int DEFAULT_INITIAL_SYNC_STORE_CONSOLIDATE_MS =
-            15*1000; // 15 sec
-    private int initialSyncStoreConsolidateMs =
-            DEFAULT_INITIAL_SYNC_STORE_CONSOLIDATE_MS;
-
-    /**
-     * Time interval between consolidate store runs.
-     */
-    static final int DEFAULT_SYNC_STORE_CONSOLIDATE_INTERVAL_MS =
-            75*60*1000; // 75 min
-    private final int syncStoreConsolidateIntervalMs =
-            DEFAULT_SYNC_STORE_CONSOLIDATE_INTERVAL_MS;
-
-    /**
-     * Time in milliseconds before entities will expire
-     */
-    protected static final int ENTITY_TIMEOUT = 60*60*1000;
-
-    /**
-     * Time in seconds between cleaning up old entities/devices
-     */
-    protected static final int ENTITY_CLEANUP_INTERVAL = 60*60;
-
-    /**
-     * This is the master device map that maps device IDs to {@link Device}
-     * objects.
-     */
-    protected ConcurrentHashMap<Long, Device> deviceMap;
-
-    /**
-     * Counter used to generate device keys
-     */
-    protected AtomicLong deviceKeyCounter = new AtomicLong(0);
-
-    /**
-     * This is the primary entity index that contains all entities
-     */
-    protected DeviceUniqueIndex primaryIndex;
-
-    /**
-     * This stores secondary indices over the fields in the devices
-     */
-    protected Map<EnumSet<DeviceField>, DeviceIndex> secondaryIndexMap;
-
-    /**
-     * This map contains state for each of the {@ref IEntityClass}
-     * that exist
-     */
-    protected ConcurrentHashMap<String, ClassState> classStateMap;
-
-    /**
-     * This is the list of indices we want on a per-class basis
-     */
-    protected Set<EnumSet<DeviceField>> perClassIndices;
-
-    /**
-     * The entity classifier currently in use
-     */
-    protected IEntityClassifierService entityClassifier;
-
-    /**
-     * Used to cache state about specific entity classes
-     */
-    protected class ClassState {
-
-        /**
-         * The class index
-         */
-        protected DeviceUniqueIndex classIndex;
-
-        /**
-         * This stores secondary indices over the fields in the device for the
-         * class
-         */
-        protected Map<EnumSet<DeviceField>, DeviceIndex> secondaryIndexMap;
-
-        /**
-         * Allocate a new {@link ClassState} object for the class
-         * @param clazz the class to use for the state
-         */
-        public ClassState(IEntityClass clazz) {
-            EnumSet<DeviceField> keyFields = clazz.getKeyFields();
-            EnumSet<DeviceField> primaryKeyFields =
-                    entityClassifier.getKeyFields();
-            boolean keyFieldsMatchPrimary =
-                    primaryKeyFields.equals(keyFields);
-
-            if (!keyFieldsMatchPrimary)
-                classIndex = new DeviceUniqueIndex(keyFields);
-
-            secondaryIndexMap =
-                    new HashMap<EnumSet<DeviceField>, DeviceIndex>();
-            for (EnumSet<DeviceField> fields : perClassIndices) {
-                secondaryIndexMap.put(fields,
-                                      new DeviceMultiIndex(fields));
-            }
-        }
-    }
-
-    /**
-     * Device manager event listeners
-     * reclassifyDeviceListeners are notified first before reconcileDeviceListeners.
-     * This is to make sure devices are correctly reclassified before reconciliation.
-     */
-    protected ListenerDispatcher<String,IDeviceListener> deviceListeners;
-
-    /**
-     * A device update event to be dispatched
-     */
-    protected static class DeviceUpdate {
-        public enum Change {
-            ADD, DELETE, CHANGE;
-        }
-
-        /**
-         * The affected device
-         */
-        protected Device device;
-
-        /**
-         * The change that was made
-         */
-        protected Change change;
-
-        /**
-         * If not added, then this is the list of fields changed
-         */
-        protected EnumSet<DeviceField> fieldsChanged;
-
-        public DeviceUpdate(Device device, Change change,
-                            EnumSet<DeviceField> fieldsChanged) {
-            super();
-            this.device = device;
-            this.change = change;
-            this.fieldsChanged = fieldsChanged;
-        }
-
-        @Override
-        public String toString() {
-            String devIdStr = device.getEntityClass().getName() + "::" +
-                    device.getMACAddressString();
-            return "DeviceUpdate [device=" + devIdStr + ", change=" + change
-                   + ", fieldsChanged=" + fieldsChanged + "]";
-        }
-
-    }
-
-    /**
-     * AttachmentPointComparator
-     *
-     * Compares two attachment points and returns the latest one.
-     * It is assumed that the two attachment points are in the same
-     * L2 domain.
-     *
-     * @author srini
-     */
-    protected class AttachmentPointComparator
-    implements Comparator<AttachmentPoint> {
-        public AttachmentPointComparator() {
-            super();
-        }
-
-        @Override
-        public int compare(AttachmentPoint oldAP, AttachmentPoint newAP) {
-            //First compare based on L2 domain ID;
-
-            long oldSw = oldAP.getSw();
-            short oldPort = oldAP.getPort();
-            long oldDomain = topology.getL2DomainId(oldSw);
-            boolean oldBD = topology.isBroadcastDomainPort(oldSw, oldPort);
-
-            long newSw = newAP.getSw();
-            short newPort = newAP.getPort();
-            long newDomain = topology.getL2DomainId(newSw);
-            boolean newBD = topology.isBroadcastDomainPort(newSw, newPort);
-
-            if (oldDomain < newDomain) return -1;
-            else if (oldDomain > newDomain) return 1;
-
-
-            // Give preference to OFPP_LOCAL always
-            if (oldPort != OFPort.OFPP_LOCAL.getValue() &&
-                    newPort == OFPort.OFPP_LOCAL.getValue()) {
-                return -1;
-            } 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() > newAP.getActiveSince())
-                return -compare(newAP, oldAP);
-
-            long activeOffset = 0;
-            if (!topology.isConsistent(oldSw, oldPort, newSw, newPort)) {
-                if (!newBD && oldBD) {
-                    return -1;
-                }
-                if (newBD && oldBD) {
-                    activeOffset = AttachmentPoint.EXTERNAL_TO_EXTERNAL_TIMEOUT;
-                }
-                else if (newBD && !oldBD){
-                    activeOffset = AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT;
-                }
-
-            } else {
-                // The attachment point is consistent.
-                activeOffset = AttachmentPoint.CONSISTENT_TIMEOUT;
-            }
-
-
-            if ((newAP.getActiveSince() > oldAP.getLastSeen() + activeOffset) ||
-                    (newAP.getLastSeen() > oldAP.getLastSeen() +
-                            AttachmentPoint.INACTIVITY_INTERVAL)) {
-                return -1;
-            }
-            return 1;
-        }
-    }
-    /**
-     * Comparator for sorting by cluster ID
-     */
-    public AttachmentPointComparator apComparator;
-
-    /**
-     * Switch ports where attachment points shouldn't be learned
-     */
-    private Set<SwitchPort> suppressAPs;
-
-    /**
-     * Periodic task to clean up expired entities
-     */
-    public SingletonTask entityCleanupTask;
-
-
-    /**
-     * Periodic task to consolidate entries in the store. I.e., delete
-     * entries in the store that are not known to DeviceManager
-     */
-    private SingletonTask storeConsolidateTask;
-
-    /**
-     * Listens for HA notifications
-     */
-    protected HAListenerDelegate haListenerDelegate;
-
-
-    // *********************
-    // IDeviceManagerService
-    // *********************
-
-    @Override
-    public IDevice getDevice(Long deviceKey) {
-        return deviceMap.get(deviceKey);
-    }
-
-    @Override
-    public IDevice findDevice(long macAddress, Short vlan,
-                              Integer ipv4Address, Long switchDPID,
-                              Integer switchPort)
-                              throws IllegalArgumentException {
-        if (vlan != null && vlan.shortValue() <= 0)
-            vlan = null;
-        if (ipv4Address != null && ipv4Address == 0)
-            ipv4Address = null;
-        Entity e = new Entity(macAddress, vlan, ipv4Address, switchDPID,
-                              switchPort, null);
-        if (!allKeyFieldsPresent(e, entityClassifier.getKeyFields())) {
-            throw new IllegalArgumentException("Not all key fields specified."
-                      + " Required fields: " + entityClassifier.getKeyFields());
-        }
-        return findDeviceByEntity(e);
-    }
-
-    @Override
-    public IDevice findClassDevice(IEntityClass entityClass, long macAddress,
-                                  Short vlan, Integer ipv4Address)
-                                  throws IllegalArgumentException {
-        if (vlan != null && vlan.shortValue() <= 0)
-            vlan = null;
-        if (ipv4Address != null && ipv4Address == 0)
-            ipv4Address = null;
-        Entity e = new Entity(macAddress, vlan, ipv4Address,
-                              null, null, null);
-        if (entityClass == null ||
-                !allKeyFieldsPresent(e, entityClass.getKeyFields())) {
-            throw new IllegalArgumentException("Not all key fields and/or "
-                    + " no source device specified. Required fields: " +
-                    entityClassifier.getKeyFields());
-        }
-        return findDestByEntity(entityClass, e);
-    }
-
-    @Override
-    public Collection<? extends IDevice> getAllDevices() {
-        return Collections.unmodifiableCollection(deviceMap.values());
-    }
-
-    @Override
-    public void addIndex(boolean perClass,
-                         EnumSet<DeviceField> keyFields) {
-        if (perClass) {
-            perClassIndices.add(keyFields);
-        } else {
-            secondaryIndexMap.put(keyFields,
-                                  new DeviceMultiIndex(keyFields));
-        }
-    }
-
-    @Override
-    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 =
-                    getEntityKeys(macAddress, vlan, ipv4Address,
-                                  switchDPID, switchPort);
-            index = secondaryIndexMap.get(keys);
-        }
-
-        Iterator<Device> deviceIterator = null;
-        if (index == null) {
-            // Do a full table scan
-            deviceIterator = deviceMap.values().iterator();
-        } else {
-            // index lookup
-            Entity entity = new Entity((macAddress == null ? 0 : macAddress),
-                                       vlan,
-                                       ipv4Address,
-                                       switchDPID,
-                                       switchPort,
-                                       null);
-            deviceIterator =
-                    new DeviceIndexInterator(this, index.queryByEntity(entity));
-        }
-
-        DeviceIterator di =
-                new DeviceIterator(deviceIterator,
-                                   null,
-                                   macAddress,
-                                   vlan,
-                                   ipv4Address,
-                                   switchDPID,
-                                   switchPort);
-        return di;
-    }
-
-    @Override
-    public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass,
-                                                         Long macAddress,
-                                                         Short vlan,
-                                                         Integer ipv4Address,
-                                                         Long switchDPID,
-                                                         Integer switchPort) {
-        ArrayList<Iterator<Device>> iterators =
-                new ArrayList<Iterator<Device>>();
-        ClassState classState = getClassState(entityClass);
-
-        DeviceIndex index = null;
-        if (classState.secondaryIndexMap.size() > 0) {
-            EnumSet<DeviceField> keys =
-                    getEntityKeys(macAddress, vlan, ipv4Address,
-                                  switchDPID, switchPort);
-            index = classState.secondaryIndexMap.get(keys);
-        }
-
-        Iterator<Device> iter;
-        if (index == null) {
-            index = classState.classIndex;
-            if (index == null) {
-                // scan all devices
-                return new DeviceIterator(deviceMap.values().iterator(),
-                                          new IEntityClass[] { entityClass },
-                                          macAddress, vlan, ipv4Address,
-                                          switchDPID, switchPort);
-            } else {
-                // scan the entire class
-                iter = new DeviceIndexInterator(this, index.getAll());
-            }
-        } else {
-            // index lookup
-            Entity entity =
-                    new Entity((macAddress == null ? 0 : macAddress),
-                               vlan,
-                               ipv4Address,
-                               switchDPID,
-                               switchPort,
-                               null);
-            iter = new DeviceIndexInterator(this,
-                                            index.queryByEntity(entity));
-        }
-        iterators.add(iter);
-
-        return new MultiIterator<Device>(iterators.iterator());
-    }
-
-    protected Iterator<Device> getDeviceIteratorForQuery(Long macAddress,
-                                                        Short vlan,
-                                                        Integer ipv4Address,
-                                                        Long switchDPID,
-                                                        Integer switchPort) {
-        DeviceIndex index = null;
-        if (secondaryIndexMap.size() > 0) {
-            EnumSet<DeviceField> keys =
-                getEntityKeys(macAddress, vlan, ipv4Address,
-                            switchDPID, switchPort);
-            index = secondaryIndexMap.get(keys);
-        }
-
-        Iterator<Device> deviceIterator = null;
-        if (index == null) {
-            // Do a full table scan
-            deviceIterator = deviceMap.values().iterator();
-        } else {
-            // index lookup
-            Entity entity = new Entity((macAddress == null ? 0 : macAddress),
-                                vlan,
-                                ipv4Address,
-                                switchDPID,
-                                switchPort,
-                                null);
-            deviceIterator =
-                new DeviceIndexInterator(this, index.queryByEntity(entity));
-        }
-
-        DeviceIterator di =
-            new DeviceIterator(deviceIterator,
-                                null,
-                                macAddress,
-                                vlan,
-                                ipv4Address,
-                                switchDPID,
-                                switchPort);
-        return di;
-    }
-
-    @Override
-    public void addListener(IDeviceListener listener) {
-         deviceListeners.addListener("device", listener);
-         logListeners();
-    }
-
-    @Override
-    public void addSuppressAPs(long swId, short port) {
-        suppressAPs.add(new SwitchPort(swId, port));
-    }
-
-    @Override
-    public void removeSuppressAPs(long swId, short port) {
-        suppressAPs.remove(new SwitchPort(swId, port));
-    }
-
-    @Override
-    public Set<SwitchPort> getSuppressAPs() {
-        return Collections.unmodifiableSet(suppressAPs);
-    }
-
-    private void logListeners() {
-        List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
-        if (listeners != null) {
-            StringBuffer sb = new StringBuffer();
-            sb.append("DeviceListeners: ");
-            for (IDeviceListener l : listeners) {
-                sb.append(l.getName());
-                sb.append(",");
-            }
-            logger.debug(sb.toString());
-        }
-    }
-
-    // ***************
-    // IDeviceListener
-    // ***************
-    private class DeviceDebugEventLogger implements IDeviceListener {
-        @Override
-        public String getName() {
-            return "deviceDebugEventLogger";
-        }
-
-        @Override
-        public boolean isCallbackOrderingPrereq(String type, String name) {
-            return false;
-        }
-
-        @Override
-        public boolean isCallbackOrderingPostreq(String type, String name) {
-            return false;
-        }
-
-        @Override
-        public void deviceAdded(IDevice device) {
-            generateDeviceEvent(device, "host-added");
-        }
-
-        @Override
-        public void deviceRemoved(IDevice device) {
-            generateDeviceEvent(device, "host-removed");
-        }
-
-        @Override
-        public void deviceMoved(IDevice device) {
-            generateDeviceEvent(device, "host-moved");
-        }
-
-        @Override
-        public void deviceIPV4AddrChanged(IDevice device) {
-            generateDeviceEvent(device, "host-ipv4-addr-changed");
-        }
-
-        @Override
-        public void deviceVlanChanged(IDevice device) {
-            generateDeviceEvent(device, "host-vlan-changed");
-        }
-
-        private void generateDeviceEvent(IDevice device, String reason) {
-            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<Short> vlanIds =
-                    new ArrayList<Short>(Arrays.asList(device.getVlanId()));
-
-            evDevice.updateEventNoFlush(
-                    new DeviceEvent(device.getMACAddress(),
-                                    ipv4Addresses,
-                                    oldAps,
-                                    currentAps,
-                                    vlanIds, reason));
-        }
-    }
-
-    // *************
-    // IInfoProvider
-    // *************
-
-    @Override
-    public Map<String, Object> getInfo(String type) {
-        if (!"summary".equals(type))
-            return null;
-
-        Map<String, Object> info = new HashMap<String, Object>();
-        info.put("# hosts", deviceMap.size());
-        return info;
-    }
-
-    // ******************
-    // IOFMessageListener
-    // ******************
-
-    @Override
-    public String getName() {
-        return MODULE_NAME;
-    }
-
-    @Override
-    public boolean isCallbackOrderingPrereq(OFType type, String name) {
-        return ((type == OFType.PACKET_IN || type == OFType.FLOW_MOD)
-                && name.equals("topology"));
-    }
-
-    @Override
-    public boolean isCallbackOrderingPostreq(OFType type, String name) {
-        return false;
-    }
-
-    @Override
-    public Command receive(IOFSwitch sw, OFMessage msg,
-                           FloodlightContext cntx) {
-        switch (msg.getType()) {
-            case PACKET_IN:
-                cntIncoming.updateCounterNoFlush();
-                return this.processPacketInMessage(sw,
-                                                   (OFPacketIn) msg, cntx);
-            default:
-                break;
-        }
-        return Command.CONTINUE;
-    }
-
-    // ***************
-    // IFlowReconcileListener
-    // ***************
-    @Override
-    public Command reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList) {
-        ListIterator<OFMatchReconcile> iter = ofmRcList.listIterator();
-        while (iter.hasNext()) {
-            OFMatchReconcile ofm = iter.next();
-
-            // Remove the STOPPed flow.
-            if (Command.STOP == reconcileFlow(ofm)) {
-                iter.remove();
-            }
-        }
-
-        if (ofmRcList.size() > 0) {
-            return Command.CONTINUE;
-        } else {
-            return Command.STOP;
-        }
-    }
-
-    protected Command reconcileFlow(OFMatchReconcile ofm) {
-        cntReconcileRequest.updateCounterNoFlush();
-        // Extract source entity information
-        Entity srcEntity =
-                getEntityFromFlowMod(ofm.ofmWithSwDpid, true);
-        if (srcEntity == null) {
-            cntReconcileNoSource.updateCounterNoFlush();
-            return Command.STOP;
-       }
-
-        // Find the device by source entity
-        Device srcDevice = findDeviceByEntity(srcEntity);
-        if (srcDevice == null)  {
-            cntReconcileNoSource.updateCounterNoFlush();
-            return Command.STOP;
-        }
-        // Store the source device in the context
-        fcStore.put(ofm.cntx, CONTEXT_SRC_DEVICE, srcDevice);
-
-        // Find the device matching the destination from the entity
-        // classes of the source.
-        Entity dstEntity = getEntityFromFlowMod(ofm.ofmWithSwDpid, false);
-        Device dstDevice = null;
-        if (dstEntity != null) {
-            dstDevice = findDestByEntity(srcDevice.getEntityClass(), dstEntity);
-            if (dstDevice != null)
-                fcStore.put(ofm.cntx, CONTEXT_DST_DEVICE, dstDevice);
-            else
-                cntReconcileNoDest.updateCounterNoFlush();
-        } else {
-            cntReconcileNoDest.updateCounterNoFlush();
-        }
-        if (logger.isTraceEnabled()) {
-            logger.trace("Reconciling flow: match={}, srcEntity={}, srcDev={}, "
-                         + "dstEntity={}, dstDev={}",
-                         new Object[] {ofm.ofmWithSwDpid.getOfMatch(),
-                                       srcEntity, srcDevice,
-                                       dstEntity, dstDevice } );
-        }
-        return Command.CONTINUE;
-    }
-
-    // *****************
-    // IFloodlightModule
-    // *****************
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l =
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IDeviceService.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(IDeviceService.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(IStorageSourceService.class);
-        l.add(ITopologyService.class);
-        l.add(IRestApiService.class);
-        l.add(IThreadPoolService.class);
-        l.add(IFlowReconcileService.class);
-        l.add(IEntityClassifierService.class);
-        l.add(ISyncService.class);
-        return l;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext fmc) throws FloodlightModuleException {
-        this.perClassIndices =
-                new HashSet<EnumSet<DeviceField>>();
-        addIndex(true, EnumSet.of(DeviceField.IPV4));
-
-        this.deviceListeners = new ListenerDispatcher<String, IDeviceListener>();
-        this.suppressAPs = Collections.newSetFromMap(
-                               new ConcurrentHashMap<SwitchPort, Boolean>());
-
-        this.floodlightProvider =
-                fmc.getServiceImpl(IFloodlightProviderService.class);
-        this.storageSource =
-                fmc.getServiceImpl(IStorageSourceService.class);
-        this.topology =
-                fmc.getServiceImpl(ITopologyService.class);
-        this.restApi = fmc.getServiceImpl(IRestApiService.class);
-        this.threadPool = fmc.getServiceImpl(IThreadPoolService.class);
-        this.flowReconcileMgr = fmc.getServiceImpl(IFlowReconcileService.class);
-        this.flowReconcileEngine = fmc.getServiceImpl(IFlowReconcileEngineService.class);
-        this.entityClassifier = fmc.getServiceImpl(IEntityClassifierService.class);
-        this.debugCounters = fmc.getServiceImpl(IDebugCounterService.class);
-        this.debugEvents = fmc.getServiceImpl(IDebugEventService.class);
-        this.syncService = fmc.getServiceImpl(ISyncService.class);
-        this.deviceSyncManager = new DeviceSyncManager();
-        this.haListenerDelegate = new HAListenerDelegate();
-        registerDeviceManagerDebugCounters();
-        registerDeviceManagerDebugEvents();
-        this.addListener(new DeviceDebugEventLogger());
-    }
-
-    private void registerDeviceManagerDebugEvents() throws FloodlightModuleException {
-        if (debugEvents == null) {
-            debugEvents = new NullDebugEvent();
-        }
-        try {
-            evDevice =
-                debugEvents.registerEvent(PACKAGE, "hostevent",
-                                          "Host added, removed, updated, or moved",
-                                          EventType.ALWAYS_LOG, DeviceEvent.class, 500);
-        } catch (MaxEventsRegistered e) {
-            throw new FloodlightModuleException("Max events registered", e);
-        }
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext fmc)
-            throws FloodlightModuleException {
-        isMaster = (floodlightProvider.getRole() == Role.MASTER);
-        primaryIndex = new DeviceUniqueIndex(entityClassifier.getKeyFields());
-        secondaryIndexMap = new HashMap<EnumSet<DeviceField>, DeviceIndex>();
-
-        deviceMap = new ConcurrentHashMap<Long, Device>();
-        classStateMap =
-                new ConcurrentHashMap<String, ClassState>();
-        apComparator = new AttachmentPointComparator();
-
-        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-        floodlightProvider.addHAListener(this.haListenerDelegate);
-        if (topology != null)
-            topology.addListener(this);
-        flowReconcileMgr.addFlowReconcileListener(this);
-        entityClassifier.addListener(this);
-
-        ScheduledExecutorService ses = threadPool.getScheduledExecutor();
-        Runnable ecr = new Runnable() {
-            @Override
-            public void run() {
-                cleanupEntities();
-                entityCleanupTask.reschedule(ENTITY_CLEANUP_INTERVAL,
-                                             TimeUnit.SECONDS);
-            }
-        };
-        entityCleanupTask = new SingletonTask(ses, ecr);
-        entityCleanupTask.reschedule(ENTITY_CLEANUP_INTERVAL,
-                                     TimeUnit.SECONDS);
-
-        Runnable consolidateStoreRunner = new Runnable() {
-            @Override
-            public void run() {
-                deviceSyncManager.consolidateStore();
-                storeConsolidateTask.reschedule(syncStoreConsolidateIntervalMs,
-                                                TimeUnit.MILLISECONDS);
-            }
-        };
-        storeConsolidateTask = new SingletonTask(ses, consolidateStoreRunner);
-        if (isMaster)
-            storeConsolidateTask.reschedule(syncStoreConsolidateIntervalMs,
-                                            TimeUnit.MILLISECONDS);
-
-
-        if (restApi != null) {
-            restApi.addRestletRoutable(new DeviceRoutable());
-        } else {
-            logger.debug("Could not instantiate REST API");
-        }
-
-        try {
-            this.syncService.registerStore(DEVICE_SYNC_STORE_NAME, Scope.LOCAL);
-            this.storeClient = this.syncService
-                    .getStoreClient(DEVICE_SYNC_STORE_NAME,
-                                    String.class,
-                                    DeviceSyncRepresentation.class);
-        } catch (SyncException e) {
-            throw new FloodlightModuleException("Error while setting up sync service", e);
-        }
-        floodlightProvider.addInfoProvider("summary", this);
-    }
-
-    private void registerDeviceManagerDebugCounters() throws FloodlightModuleException {
-        if (debugCounters == null) {
-            logger.error("Debug Counter Service not found.");
-            debugCounters = new NullDebugCounter();
-        }
-        try {
-            cntIncoming = debugCounters.registerCounter(PACKAGE, "incoming",
-                "All incoming packets seen by this module", CounterType.ALWAYS_COUNT);
-            cntReconcileRequest = debugCounters.registerCounter(PACKAGE,
-                "reconcile-request",
-                "Number of flows that have been received for reconciliation by " +
-                "this module",
-                CounterType.ALWAYS_COUNT);
-            cntReconcileNoSource = debugCounters.registerCounter(PACKAGE,
-                "reconcile-no-source-device",
-                "Number of flow reconcile events that failed because no source " +
-                "device could be identified",
-                CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); // is this really a IDebugCounterService.CTR_MDATA_WARNing
-            cntReconcileNoDest = debugCounters.registerCounter(PACKAGE,
-                "reconcile-no-dest-device",
-                "Number of flow reconcile events that failed because no " +
-                "destination device could be identified",
-                CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); // is this really a IDebugCounterService.CTR_MDATA_WARNing
-            cntInvalidSource = debugCounters.registerCounter(PACKAGE,
-                "invalid-source",
-                "Number of packetIns that were discarded because the source " +
-                "MAC was invalid (broadcast, multicast, or zero)",
-                CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN);
-            cntNoSource = debugCounters.registerCounter(PACKAGE, "no-source-device",
-                 "Number of packetIns that were discarded because the " +
-                 "could not identify a source device. This can happen if a " +
-                 "packet is not allowed, appears on an illegal port, does not " +
-                 "have a valid address space, etc.",
-                 CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN);
-            cntInvalidDest = debugCounters.registerCounter(PACKAGE,
-                "invalid-dest",
-                "Number of packetIns that were discarded because the dest " +
-                "MAC was invalid (zero)",
-                 CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN);
-            cntNoDest = debugCounters.registerCounter(PACKAGE, "no-dest-device",
-                 "Number of packetIns that did not have an associated " +
-                 "destination device. E.g., because the destination MAC is " +
-                 "broadcast/multicast or is not yet known to the controller.",
-                 CounterType.ALWAYS_COUNT);
-            cntDhcpClientNameSnooped = debugCounters.registerCounter(PACKAGE,
-                 "dhcp-client-name-snooped",
-                 "Number of times a DHCP client name was snooped from a " +
-                 "packetIn.",
-                 CounterType.ALWAYS_COUNT);
-            cntDeviceOnInternalPortNotLearned = debugCounters.registerCounter(
-                 PACKAGE,
-                 "device-on-internal-port-not-learned",
-                 "Number of times packetIn was received on an internal port and" +
-                 "no source device is known for the source MAC. The packetIn is " +
-                 "discarded.",
-                 CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN);
-            cntPacketNotAllowed = debugCounters.registerCounter(PACKAGE,
-                 "packet-not-allowed",
-                 "Number of times a packetIn was not allowed due to spoofing " +
-                 "protection configuration.",
-                 CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); // is this really a IDebugCounterService.CTR_MDATA_WARNing?
-            cntNewDevice = debugCounters.registerCounter(PACKAGE, "new-device",
-                 "Number of times a new device was learned",
-                 CounterType.ALWAYS_COUNT);
-            cntPacketOnInternalPortForKnownDevice = debugCounters.registerCounter(
-                 PACKAGE,
-                 "packet-on-internal-port-for-known-device",
-                 "Number of times a packetIn was received on an internal port " +
-                 "for a known device.",
-                 CounterType.ALWAYS_COUNT);
-            cntNewEntity = debugCounters.registerCounter(PACKAGE, "new-entity",
-                 "Number of times a new entity was learned for an existing device",
-                 CounterType.ALWAYS_COUNT);
-            cntDeviceChanged = debugCounters.registerCounter(PACKAGE, "device-changed",
-                 "Number of times device properties have changed",
-                 CounterType.ALWAYS_COUNT);
-            cntDeviceMoved = debugCounters.registerCounter(PACKAGE, "device-moved",
-                 "Number of times devices have moved",
-                 CounterType.ALWAYS_COUNT);
-            cntCleanupEntitiesRuns = debugCounters.registerCounter(PACKAGE,
-                 "cleanup-entities-runs",
-                 "Number of times the entity cleanup task has been run",
-                 CounterType.ALWAYS_COUNT);
-            cntEntityRemovedTimeout = debugCounters.registerCounter(PACKAGE,
-                 "entity-removed-timeout",
-                 "Number of times entities have been removed due to timeout " +
-                 "(entity has been inactive for " + ENTITY_TIMEOUT/1000 + "s)",
-                 CounterType.ALWAYS_COUNT);
-            cntDeviceDeleted = debugCounters.registerCounter(PACKAGE, "device-deleted",
-                 "Number of devices that have been removed due to inactivity",
-                 CounterType.ALWAYS_COUNT);
-            cntDeviceReclassifyDelete = debugCounters.registerCounter(PACKAGE,
-                 "device-reclassify-delete",
-                 "Number of devices that required reclassification and have been " +
-                 "temporarily delete for reclassification",
-                 CounterType.ALWAYS_COUNT);
-            cntDeviceStrored = debugCounters.registerCounter(PACKAGE, "device-stored",
-                 "Number of device entries written or updated to the sync store",
-                 CounterType.ALWAYS_COUNT);
-            cntDeviceStoreThrottled = debugCounters.registerCounter(PACKAGE,
-                 "device-store-throttled",
-                 "Number of times a device update to the sync store was " +
-                 "requested but not performed because the same device entities " +
-                 "have recently been updated already",
-                 CounterType.ALWAYS_COUNT);
-            cntDeviceRemovedFromStore = debugCounters.registerCounter(PACKAGE,
-                 "device-removed-from-store",
-                 "Number of devices that were removed from the sync store " +
-                 "because the local controller removed the device due to " +
-                 "inactivity",
-                 CounterType.ALWAYS_COUNT);
-            cntSyncException = debugCounters.registerCounter(PACKAGE, "sync-exception",
-                 "Number of times an operation on the sync store resulted in " +
-                 "sync exception",
-                 CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN); // it this an error?
-            cntDevicesFromStore = debugCounters.registerCounter(PACKAGE,
-                 "devices-from-store",
-                 "Number of devices that were read from the sync store after " +
-                 "the local controller transitioned from SLAVE to MASTER",
-                 CounterType.ALWAYS_COUNT);
-            cntConsolidateStoreRuns = debugCounters.registerCounter(PACKAGE,
-                 "consolidate-store-runs",
-                 "Number of times the task to consolidate entries in the " +
-                 "store witch live known devices has been run",
-                 CounterType.ALWAYS_COUNT);
-            cntConsolidateStoreDevicesRemoved = debugCounters.registerCounter(PACKAGE,
-                 "consolidate-store-devices-removed",
-                 "Number of times a device has been removed from the sync " +
-                 "store because no corresponding live device is known. " +
-                 "This indicates a remote controller still writing device " +
-                 "entries despite the local controller being MASTER or an " +
-                 "incosistent store update from the local controller.",
-                 CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN);
-            cntTransitionToMaster = debugCounters.registerCounter(PACKAGE,
-                 "transition-to-master",
-                 "Number of times this controller has transitioned from SLAVE " +
-                 "to MASTER role. Will be 0 or 1.",
-                 CounterType.ALWAYS_COUNT);
-        } catch (CounterException e) {
-            throw new FloodlightModuleException(e.getMessage());
-        }
-    }
-
-    // ***************
-    // IHAListener
-    // ***************
-
-    protected class HAListenerDelegate implements IHAListener {
-        @Override
-        public void transitionToMaster() {
-            DeviceManagerImpl.this.isMaster = true;
-            DeviceManagerImpl.this.deviceSyncManager.goToMaster();
-        }
-
-        @Override
-        public void controllerNodeIPsChanged(
-                Map<String, String> curControllerNodeIPs,
-                Map<String, String> addedControllerNodeIPs,
-                Map<String, String> removedControllerNodeIPs) {
-            // no-op
-        }
-
-        @Override
-        public String getName() {
-            return DeviceManagerImpl.this.getName();
-        }
-
-        @Override
-        public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
-                                                String name) {
-            return ("topology".equals(name) ||
-                    "bvsmanager".equals(name));
-        }
-
-        @Override
-        public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
-                                                 String name) {
-            // TODO Auto-generated method stub
-            return false;
-        }
-    }
-
-
-    // ****************
-    // Internal methods
-    // ****************
-
-    protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi,
-                                             FloodlightContext cntx) {
-        Ethernet eth =
-                IFloodlightProviderService.bcStore.
-                get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-
-        // Extract source entity information
-        Entity srcEntity =
-                getSourceEntityFromPacket(eth, sw.getId(), pi.getInPort());
-        if (srcEntity == null) {
-            cntInvalidSource.updateCounterNoFlush();
-            return Command.STOP;
-        }
-
-        // Learn from ARP packet for special VRRP settings.
-        // In VRRP settings, the source MAC address and sender MAC
-        // addresses can be different.  In such cases, we need to learn
-        // the IP to MAC mapping of the VRRP IP address.  The source
-        // entity will not have that information.  Hence, a separate call
-        // to learn devices in such cases.
-        learnDeviceFromArpResponseData(eth, sw.getId(), pi.getInPort());
-
-        // Learn/lookup device information
-        Device srcDevice = learnDeviceByEntity(srcEntity);
-        if (srcDevice == null) {
-            cntNoSource.updateCounterNoFlush();
-            return Command.STOP;
-        }
-
-        // Store the source device in the context
-        fcStore.put(cntx, CONTEXT_SRC_DEVICE, srcDevice);
-
-        // Find the device matching the destination from the entity
-        // classes of the source.
-        if (eth.getDestinationMAC().toLong() == 0) {
-            cntInvalidDest.updateCounterNoFlush();
-            return Command.STOP;
-        }
-        Entity dstEntity = getDestEntityFromPacket(eth);
-        Device dstDevice = null;
-        if (dstEntity != null) {
-            dstDevice =
-                    findDestByEntity(srcDevice.getEntityClass(), dstEntity);
-            if (dstDevice != null)
-                fcStore.put(cntx, CONTEXT_DST_DEVICE, dstDevice);
-            else
-                cntNoDest.updateCounterNoFlush();
-        } else {
-            cntNoDest.updateCounterNoFlush();
-        }
-
-       if (logger.isTraceEnabled()) {
-           logger.trace("Received PI: {} on switch {}, port {} *** eth={}" +
-                        " *** srcDev={} *** dstDev={} *** ",
-                        new Object[] { pi, sw.getStringId(), pi.getInPort(), eth,
-                        srcDevice, dstDevice });
-       }
-
-        snoopDHCPClientName(eth, srcDevice);
-
-        return Command.CONTINUE;
-    }
-
-    /**
-     * Snoop and record client-provided host name from DHCP requests
-     * @param eth
-     * @param srcDevice
-     */
-    private void snoopDHCPClientName(Ethernet eth, Device srcDevice) {
-        if (! (eth.getPayload() instanceof IPv4) )
-            return;
-        IPv4 ipv4 = (IPv4) eth.getPayload();
-        if (! (ipv4.getPayload() instanceof UDP) )
-            return;
-        UDP udp = (UDP) ipv4.getPayload();
-        if (!(udp.getPayload() instanceof DHCP))
-            return;
-        DHCP dhcp = (DHCP) udp.getPayload();
-        byte opcode = dhcp.getOpCode();
-        if (opcode == DHCP.OPCODE_REQUEST) {
-            DHCPOption dhcpOption = dhcp.getOption(
-                    DHCPOptionCode.OptionCode_Hostname);
-            if (dhcpOption != null) {
-                cntDhcpClientNameSnooped.updateCounterNoFlush();
-                srcDevice.dhcpClientName = new String(dhcpOption.getData());
-            }
-        }
-    }
-
-    /**
-     * Check whether the given attachment point is valid given the current
-     * topology
-     * @param switchDPID the DPID
-     * @param switchPort the port
-     * @return true if it's a valid attachment point
-     */
-    public boolean isValidAttachmentPoint(long switchDPID,
-                                             int switchPort) {
-        if (topology.isAttachmentPointPort(switchDPID,
-                                           (short)switchPort) == false)
-            return false;
-
-        if (suppressAPs.contains(new SwitchPort(switchDPID, switchPort)))
-            return false;
-
-        return true;
-    }
-
-    /**
-     * Get sender IP address from packet if the packet is an ARP
-     * packet and if the source MAC address matches the ARP packets
-     * sender MAC address.
-     * @param eth
-     * @param dlAddr
-     * @return
-     */
-    private int getSrcNwAddr(Ethernet eth, long dlAddr) {
-        if (eth.getPayload() instanceof ARP) {
-            ARP arp = (ARP) eth.getPayload();
-            if ((arp.getProtocolType() == ARP.PROTO_TYPE_IP) &&
-                    (Ethernet.toLong(arp.getSenderHardwareAddress()) == dlAddr)) {
-                return IPv4.toIPv4Address(arp.getSenderProtocolAddress());
-            }
-        }
-        return 0;
-    }
-
-    /**
-     * Parse an entity from an {@link Ethernet} packet.
-     * @param eth the packet to parse
-     * @param sw the switch on which the packet arrived
-     * @param pi the original packetin
-     * @return the entity from the packet
-     */
-    protected Entity getSourceEntityFromPacket(Ethernet eth,
-                                             long swdpid,
-                                             int port) {
-        byte[] dlAddrArr = eth.getSourceMACAddress();
-        long dlAddr = Ethernet.toLong(dlAddrArr);
-
-        // Ignore broadcast/multicast source
-        if ((dlAddrArr[0] & 0x1) != 0)
-            return null;
-        // Ignore 0 source mac
-        if (dlAddr == 0)
-            return null;
-
-        short vlan = eth.getVlanID();
-        int nwSrc = getSrcNwAddr(eth, dlAddr);
-        return new Entity(dlAddr,
-                          ((vlan >= 0) ? vlan : null),
-                          ((nwSrc != 0) ? nwSrc : null),
-                          swdpid,
-                          port,
-                          new Date());
-    }
-
-    /**
-     * Learn device from ARP data in scenarios where the
-     * Ethernet source MAC is different from the sender hardware
-     * address in ARP data.
-     */
-    protected void learnDeviceFromArpResponseData(Ethernet eth,
-                                            long swdpid,
-                                            int port) {
-
-        if (!(eth.getPayload() instanceof ARP)) return;
-        ARP arp = (ARP) eth.getPayload();
-
-        byte[] dlAddrArr = eth.getSourceMACAddress();
-        long dlAddr = Ethernet.toLong(dlAddrArr);
-
-        byte[] senderHardwareAddr = arp.getSenderHardwareAddress();
-        long senderAddr = Ethernet.toLong(senderHardwareAddr);
-
-        if (dlAddr == senderAddr) return;
-
-        // Ignore broadcast/multicast source
-        if ((senderHardwareAddr[0] & 0x1) != 0)
-            return;
-        // Ignore zero sender mac
-        if (senderAddr == 0)
-            return;
-
-        short vlan = eth.getVlanID();
-        int nwSrc = IPv4.toIPv4Address(arp.getSenderProtocolAddress());
-
-        Entity e =  new Entity(senderAddr,
-                ((vlan >= 0) ? vlan : null),
-                ((nwSrc != 0) ? nwSrc : null),
-                swdpid,
-                port,
-                new Date());
-
-        learnDeviceByEntity(e);
-    }
-
-    /**
-     * Get a (partial) entity for the destination from the packet.
-     * @param eth
-     * @return
-     */
-    protected Entity getDestEntityFromPacket(Ethernet eth) {
-        byte[] dlAddrArr = eth.getDestinationMACAddress();
-        long dlAddr = Ethernet.toLong(dlAddrArr);
-        short vlan = eth.getVlanID();
-        int nwDst = 0;
-
-        // Ignore broadcast/multicast destination
-        if ((dlAddrArr[0] & 0x1) != 0)
-            return null;
-        // Ignore zero dest mac
-        if (dlAddr == 0)
-            return null;
-
-        if (eth.getPayload() instanceof IPv4) {
-            IPv4 ipv4 = (IPv4) eth.getPayload();
-            nwDst = ipv4.getDestinationAddress();
-        }
-
-        return new Entity(dlAddr,
-                          ((vlan >= 0) ? vlan : null),
-                          ((nwDst != 0) ? nwDst : null),
-                          null,
-                          null,
-                          null);
-    }
-
-    /**
-     * Parse an entity from an OFMatchWithSwDpid.
-     * @param ofmWithSwDpid
-     * @return the entity from the packet
-     */
-    private Entity getEntityFromFlowMod(OFMatchWithSwDpid ofmWithSwDpid,
-                boolean isSource) {
-        byte[] dlAddrArr = ofmWithSwDpid.getOfMatch().getDataLayerSource();
-        int nwSrc = ofmWithSwDpid.getOfMatch().getNetworkSource();
-        if (!isSource) {
-            dlAddrArr = ofmWithSwDpid.getOfMatch().getDataLayerDestination();
-            nwSrc = ofmWithSwDpid.getOfMatch().getNetworkDestination();
-        }
-
-        long dlAddr = Ethernet.toLong(dlAddrArr);
-
-        // Ignore broadcast/multicast source
-        if ((dlAddrArr[0] & 0x1) != 0)
-            return null;
-
-        Long swDpid = null;
-        Short inPort = null;
-
-        if (isSource) {
-            swDpid = ofmWithSwDpid.getSwitchDataPathId();
-            inPort = ofmWithSwDpid.getOfMatch().getInputPort();
-        }
-
-        /**for the new flow cache design, the flow mods retrived are not always
-         * from the source, learn AP should be disabled --meiyang*/
-        boolean learnap = false;
-        /**
-         * if (swDpid == null ||
+public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, ITopologyListener, IFloodlightModule, IEntityClassListener, IFlowReconcileListener, IInfoProvider {
+	protected static Logger logger = LoggerFactory.getLogger(DeviceManagerImpl.class);
+	protected IFloodlightProviderService floodlightProvider;
+	protected ITopologyService topology;
+	protected IStorageSourceService storageSource;
+	protected IRestApiService restApi;
+	protected IThreadPoolService threadPool;
+	protected IFlowReconcileService flowReconcileMgr;
+	protected IFlowReconcileEngineService flowReconcileEngine;
+	protected IDebugCounterService debugCounters;
+	private ISyncService syncService;
+	private IStoreClient<String, DeviceSyncRepresentation> storeClient;
+	private DeviceSyncManager deviceSyncManager;
+
+	/**
+	 * Debug Counters
+	 */
+	public static final String MODULE_NAME = "devicemanager";
+	public static final String PACKAGE = DeviceManagerImpl.class.getPackage().getName();
+	public IDebugCounter cntIncoming;
+	public IDebugCounter cntReconcileRequest;
+	public IDebugCounter cntReconcileNoSource;
+	public IDebugCounter cntReconcileNoDest;
+	public IDebugCounter cntInvalidSource;
+	public IDebugCounter cntInvalidDest;
+	public IDebugCounter cntNoSource;
+	public IDebugCounter cntNoDest;
+	public IDebugCounter cntDhcpClientNameSnooped;
+	public IDebugCounter cntDeviceOnInternalPortNotLearned;
+	public IDebugCounter cntPacketNotAllowed;
+	public IDebugCounter cntNewDevice;
+	public IDebugCounter cntPacketOnInternalPortForKnownDevice;
+	public IDebugCounter cntNewEntity;
+	public IDebugCounter cntDeviceChanged;
+	public IDebugCounter cntDeviceMoved;
+	public IDebugCounter cntCleanupEntitiesRuns;
+	public IDebugCounter cntEntityRemovedTimeout;
+	public IDebugCounter cntDeviceDeleted;
+	public IDebugCounter cntDeviceReclassifyDelete;
+	public IDebugCounter cntDeviceStrored;
+	public IDebugCounter cntDeviceStoreThrottled;
+	public IDebugCounter cntDeviceRemovedFromStore;
+	public IDebugCounter cntSyncException;
+	public IDebugCounter cntDevicesFromStore;
+	public IDebugCounter cntConsolidateStoreRuns;
+	public IDebugCounter cntConsolidateStoreDevicesRemoved;
+	public IDebugCounter cntTransitionToMaster;
+
+	/**
+	 * Debug Events
+	 */
+	private IDebugEventService debugEventService;
+	private IEventCategory<DeviceEvent> debugEventCategory;
+
+	private boolean isMaster = false;
+
+	static final String DEVICE_SYNC_STORE_NAME =
+			DeviceManagerImpl.class.getCanonicalName() + ".stateStore";
+
+	/**
+	 * Time interval between writes of entries for the same device to
+	 * the sync store.
+	 */
+	static final int DEFAULT_SYNC_STORE_WRITE_INTERVAL_MS = 5*60*1000; // 5 min
+	private int syncStoreWriteIntervalMs = DEFAULT_SYNC_STORE_WRITE_INTERVAL_MS;
+
+	/**
+	 * Time after SLAVE->MASTER until we run the consolidate store
+	 * code.
+	 */
+	static final int DEFAULT_INITIAL_SYNC_STORE_CONSOLIDATE_MS =
+			15*1000; // 15 sec
+	private int initialSyncStoreConsolidateMs =
+			DEFAULT_INITIAL_SYNC_STORE_CONSOLIDATE_MS;
+
+	/**
+	 * Time interval between consolidate store runs.
+	 */
+	static final int DEFAULT_SYNC_STORE_CONSOLIDATE_INTERVAL_MS =
+			75*60*1000; // 75 min
+	private final int syncStoreConsolidateIntervalMs =
+			DEFAULT_SYNC_STORE_CONSOLIDATE_INTERVAL_MS;
+
+	/**
+	 * Time in milliseconds before entities will expire
+	 */
+	protected static final int ENTITY_TIMEOUT = 60*60*1000;
+
+	/**
+	 * Time in seconds between cleaning up old entities/devices
+	 */
+	protected static final int ENTITY_CLEANUP_INTERVAL = 60*60;
+
+	/**
+	 * This is the master device map that maps device IDs to {@link Device}
+	 * objects.
+	 */
+	protected ConcurrentHashMap<Long, Device> deviceMap;
+
+	/**
+	 * Counter used to generate device keys
+	 */
+	protected AtomicLong deviceKeyCounter = new AtomicLong(0);
+
+	/**
+	 * This is the primary entity index that contains all entities
+	 */
+	protected DeviceUniqueIndex primaryIndex;
+
+	/**
+	 * This stores secondary indices over the fields in the devices
+	 */
+	protected Map<EnumSet<DeviceField>, DeviceIndex> secondaryIndexMap;
+
+	/**
+	 * This map contains state for each of the {@ref IEntityClass}
+	 * that exist
+	 */
+	protected ConcurrentHashMap<String, ClassState> classStateMap;
+
+	/**
+	 * This is the list of indices we want on a per-class basis
+	 */
+	protected Set<EnumSet<DeviceField>> perClassIndices;
+
+	/**
+	 * The entity classifier currently in use
+	 */
+	protected IEntityClassifierService entityClassifier;
+
+	/**
+	 * Used to cache state about specific entity classes
+	 */
+	protected class ClassState {
+
+		/**
+		 * The class index
+		 */
+		protected DeviceUniqueIndex classIndex;
+
+		/**
+		 * This stores secondary indices over the fields in the device for the
+		 * class
+		 */
+		protected Map<EnumSet<DeviceField>, DeviceIndex> secondaryIndexMap;
+
+		/**
+		 * Allocate a new {@link ClassState} object for the class
+		 * @param clazz the class to use for the state
+		 */
+		public ClassState(IEntityClass clazz) {
+			EnumSet<DeviceField> keyFields = clazz.getKeyFields();
+			EnumSet<DeviceField> primaryKeyFields =
+					entityClassifier.getKeyFields();
+			boolean keyFieldsMatchPrimary =
+					primaryKeyFields.equals(keyFields);
+
+			if (!keyFieldsMatchPrimary)
+				classIndex = new DeviceUniqueIndex(keyFields);
+
+			secondaryIndexMap =
+					new HashMap<EnumSet<DeviceField>, DeviceIndex>();
+			for (EnumSet<DeviceField> fields : perClassIndices) {
+				secondaryIndexMap.put(fields,
+						new DeviceMultiIndex(fields));
+			}
+		}
+	}
+
+	/**
+	 * Device manager event listeners
+	 * reclassifyDeviceListeners are notified first before reconcileDeviceListeners.
+	 * This is to make sure devices are correctly reclassified before reconciliation.
+	 */
+	protected ListenerDispatcher<String,IDeviceListener> deviceListeners;
+
+	/**
+	 * A device update event to be dispatched
+	 */
+	protected static class DeviceUpdate {
+		public enum Change {
+			ADD, DELETE, CHANGE;
+		}
+
+		/**
+		 * The affected device
+		 */
+		protected Device device;
+
+		/**
+		 * The change that was made
+		 */
+		protected Change change;
+
+		/**
+		 * If not added, then this is the list of fields changed
+		 */
+		protected EnumSet<DeviceField> fieldsChanged;
+
+		public DeviceUpdate(Device device, Change change,
+				EnumSet<DeviceField> fieldsChanged) {
+			super();
+			this.device = device;
+			this.change = change;
+			this.fieldsChanged = fieldsChanged;
+		}
+
+		@Override
+		public String toString() {
+			String devIdStr = device.getEntityClass().getName() + "::" +
+					device.getMACAddressString();
+			return "DeviceUpdate [device=" + devIdStr + ", change=" + change
+					+ ", fieldsChanged=" + fieldsChanged + "]";
+		}
+
+	}
+
+	/**
+	 * AttachmentPointComparator
+	 *
+	 * Compares two attachment points and returns the latest one.
+	 * It is assumed that the two attachment points are in the same
+	 * L2 domain.
+	 *
+	 * @author srini
+	 */
+	protected class AttachmentPointComparator
+	implements Comparator<AttachmentPoint> {
+		public AttachmentPointComparator() {
+			super();
+		}
+
+		@Override
+		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);
+			boolean oldBD = topology.isBroadcastDomainPort(oldSw, oldPort);
+
+			DatapathId newSw = newAP.getSw();
+			OFPort newPort = newAP.getPort();
+			DatapathId 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;
+
+
+			// Give preference to LOCAL always
+			if (oldPort != OFPort.LOCAL &&
+					newPort == OFPort.LOCAL) {
+				return -1;
+			} else if (oldPort == OFPort.LOCAL &&
+					newPort != OFPort.LOCAL) {
+				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()))
+				return -compare(newAP, oldAP);
+
+			long activeOffset = 0;
+			if (!topology.isConsistent(oldSw, oldPort, newSw, newPort)) {
+				if (!newBD && oldBD) {
+					return -1;
+				}
+				if (newBD && oldBD) {
+					activeOffset = AttachmentPoint.EXTERNAL_TO_EXTERNAL_TIMEOUT;
+				}
+				else if (newBD && !oldBD){
+					activeOffset = AttachmentPoint.OPENFLOW_TO_EXTERNAL_TIMEOUT;
+				}
+
+			} else {
+				// The attachment point is consistent.
+				activeOffset = AttachmentPoint.CONSISTENT_TIMEOUT;
+			}
+
+
+			if ((newAP.getActiveSince().getTime() > oldAP.getLastSeen().getTime() + activeOffset) ||
+					(newAP.getLastSeen().getTime() > oldAP.getLastSeen().getTime() +
+							AttachmentPoint.INACTIVITY_INTERVAL)) {
+				return -1;
+			}
+			return 1;
+		}
+	}
+	/**
+	 * Comparator for sorting by cluster ID
+	 */
+	public AttachmentPointComparator apComparator;
+
+	/**
+	 * Switch ports where attachment points shouldn't be learned
+	 */
+	private Set<SwitchPort> suppressAPs;
+
+	/**
+	 * Periodic task to clean up expired entities
+	 */
+	public SingletonTask entityCleanupTask;
+
+
+	/**
+	 * Periodic task to consolidate entries in the store. I.e., delete
+	 * entries in the store that are not known to DeviceManager
+	 */
+	private SingletonTask storeConsolidateTask;
+
+	/**
+	 * Listens for HA notifications
+	 */
+	protected HAListenerDelegate haListenerDelegate;
+
+
+	// *********************
+	// IDeviceManagerService
+	// *********************
+
+	@Override
+	public IDevice getDevice(Long deviceKey) {
+		return deviceMap.get(deviceKey);
+	}
+
+	@Override
+	public IDevice findDevice(MacAddress macAddress, VlanVid vlan,
+			IPv4Address ipv4Address, DatapathId switchDPID,
+			OFPort switchPort)
+					throws IllegalArgumentException {
+		if (vlan != null && vlan.getVlan() <= 0)
+			vlan = null;
+		if (ipv4Address != null && ipv4Address.getInt() == 0)
+			ipv4Address = null;
+		Entity e = new Entity(macAddress, vlan, ipv4Address, switchDPID,
+				switchPort, null);
+		if (!allKeyFieldsPresent(e, entityClassifier.getKeyFields())) {
+			throw new IllegalArgumentException("Not all key fields specified."
+					+ " Required fields: " + entityClassifier.getKeyFields());
+		}
+		return findDeviceByEntity(e);
+	}
+
+	@Override
+	public IDevice findClassDevice(IEntityClass entityClass, MacAddress macAddress,
+			VlanVid vlan, IPv4Address ipv4Address)
+					throws IllegalArgumentException {
+		if (vlan != null && vlan.getVlan() <= 0)
+			vlan = null;
+		if (ipv4Address != null && ipv4Address.getInt() == 0)
+			ipv4Address = null;
+		Entity e = new Entity(macAddress, vlan, ipv4Address,
+				null, null, null);
+		if (entityClass == null ||
+				!allKeyFieldsPresent(e, entityClass.getKeyFields())) {
+			throw new IllegalArgumentException("Not all key fields and/or "
+					+ " no source device specified. Required fields: " +
+					entityClassifier.getKeyFields());
+		}
+		return findDestByEntity(entityClass, e);
+	}
+
+	@Override
+	public Collection<? extends IDevice> getAllDevices() {
+		return Collections.unmodifiableCollection(deviceMap.values());
+	}
+
+	@Override
+	public void addIndex(boolean perClass,
+			EnumSet<DeviceField> keyFields) {
+		if (perClass) {
+			perClassIndices.add(keyFields);
+		} else {
+			secondaryIndexMap.put(keyFields,
+					new DeviceMultiIndex(keyFields));
+		}
+	}
+
+	@Override
+	public Iterator<? extends IDevice> queryDevices(MacAddress macAddress,
+			VlanVid vlan,
+			IPv4Address ipv4Address,
+			DatapathId switchDPID,
+			OFPort switchPort) {
+		DeviceIndex index = null;
+		if (secondaryIndexMap.size() > 0) {
+			EnumSet<DeviceField> keys =
+					getEntityKeys(macAddress, vlan, ipv4Address,
+							switchDPID, switchPort);
+			index = secondaryIndexMap.get(keys);
+		}
+
+		Iterator<Device> deviceIterator = null;
+		if (index == null) {
+			// Do a full table scan
+			deviceIterator = deviceMap.values().iterator();
+		} else {
+			// index lookup
+			Entity entity = new Entity(macAddress,
+					vlan,
+					ipv4Address,
+					switchDPID,
+					switchPort,
+					null);
+			deviceIterator =
+					new DeviceIndexInterator(this, index.queryByEntity(entity));
+		}
+
+		DeviceIterator di =
+				new DeviceIterator(deviceIterator,
+						null,
+						macAddress,
+						vlan,
+						ipv4Address,
+						switchDPID,
+						switchPort);
+		return di;
+	}
+
+	@Override
+	public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass,
+			MacAddress macAddress,
+			VlanVid vlan,
+			IPv4Address ipv4Address,
+			DatapathId switchDPID,
+			OFPort switchPort) {
+		ArrayList<Iterator<Device>> iterators =
+				new ArrayList<Iterator<Device>>();
+		ClassState classState = getClassState(entityClass);
+
+		DeviceIndex index = null;
+		if (classState.secondaryIndexMap.size() > 0) {
+			EnumSet<DeviceField> keys =
+					getEntityKeys(macAddress, vlan, ipv4Address,
+							switchDPID, switchPort);
+			index = classState.secondaryIndexMap.get(keys);
+		}
+
+		Iterator<Device> iter;
+		if (index == null) {
+			index = classState.classIndex;
+			if (index == null) {
+				// scan all devices
+				return new DeviceIterator(deviceMap.values().iterator(),
+						new IEntityClass[] { entityClass },
+						macAddress, vlan, ipv4Address,
+						switchDPID, switchPort);
+			} else {
+				// scan the entire class
+				iter = new DeviceIndexInterator(this, index.getAll());
+			}
+		} else {
+			// index lookup
+			Entity entity =
+					new Entity(macAddress,
+							vlan,
+							ipv4Address,
+							switchDPID,
+							switchPort,
+							null);
+			iter = new DeviceIndexInterator(this,
+					index.queryByEntity(entity));
+		}
+		iterators.add(iter);
+
+		return new MultiIterator<Device>(iterators.iterator());
+	}
+
+	protected Iterator<Device> getDeviceIteratorForQuery(MacAddress macAddress,
+			VlanVid vlan,
+			IPv4Address ipv4Address,
+			DatapathId switchDPID,
+			OFPort switchPort) {
+		DeviceIndex index = null;
+		if (secondaryIndexMap.size() > 0) {
+			EnumSet<DeviceField> keys =
+					getEntityKeys(macAddress, vlan, ipv4Address,
+							switchDPID, switchPort);
+			index = secondaryIndexMap.get(keys);
+		}
+
+		Iterator<Device> deviceIterator = null;
+		if (index == null) {
+			// Do a full table scan
+			deviceIterator = deviceMap.values().iterator();
+		} else {
+			// index lookup
+			Entity entity = new Entity(macAddress,
+					vlan,
+					ipv4Address,
+					switchDPID,
+					switchPort,
+					null);
+			deviceIterator =
+					new DeviceIndexInterator(this, index.queryByEntity(entity));
+		}
+
+		DeviceIterator di =
+				new DeviceIterator(deviceIterator,
+						null,
+						macAddress,
+						vlan,
+						ipv4Address,
+						switchDPID,
+						switchPort);
+		return di;
+	}
+
+	@Override
+	public void addListener(IDeviceListener listener) {
+		deviceListeners.addListener("device", listener);
+		logListeners();
+	}
+
+	@Override
+	public void addSuppressAPs(DatapathId swId, OFPort port) {
+		suppressAPs.add(new SwitchPort(swId, port));
+	}
+
+	@Override
+	public void removeSuppressAPs(DatapathId swId, OFPort port) {
+		suppressAPs.remove(new SwitchPort(swId, port));
+	}
+
+	@Override
+	public Set<SwitchPort> getSuppressAPs() {
+		return Collections.unmodifiableSet(suppressAPs);
+	}
+
+	private void logListeners() {
+		List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
+		if (listeners != null) {
+			StringBuffer sb = new StringBuffer();
+			sb.append("DeviceListeners: ");
+			for (IDeviceListener l : listeners) {
+				sb.append(l.getName());
+				sb.append(",");
+			}
+			logger.debug(sb.toString());
+		}
+	}
+
+	// ***************
+	// IDeviceListener
+	// ***************
+	private class DeviceDebugEventLogger implements IDeviceListener {
+		@Override
+		public String getName() {
+			return "deviceDebugEventLogger";
+		}
+
+		@Override
+		public boolean isCallbackOrderingPrereq(String type, String name) {
+			return false;
+		}
+
+		@Override
+		public boolean isCallbackOrderingPostreq(String type, String name) {
+			return false;
+		}
+
+		@Override
+		public void deviceAdded(IDevice device) {
+			generateDeviceEvent(device, "host-added");
+		}
+
+		@Override
+		public void deviceRemoved(IDevice device) {
+			generateDeviceEvent(device, "host-removed");
+		}
+
+		@Override
+		public void deviceMoved(IDevice device) {
+			generateDeviceEvent(device, "host-moved");
+		}
+
+		@Override
+		public void deviceIPV4AddrChanged(IDevice device) {
+			generateDeviceEvent(device, "host-ipv4-addr-changed");
+		}
+
+		@Override
+		public void deviceVlanChanged(IDevice device) {
+			generateDeviceEvent(device, "host-vlan-changed");
+		}
+
+		private void generateDeviceEvent(IDevice device, String reason) {
+			List<IPv4Address> ipv4Addresses =
+					new ArrayList<IPv4Address>(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()));
+
+			debugEventCategory.newEventNoFlush(new DeviceEvent(device.getMACAddress(),
+					ipv4Addresses,
+					oldAps,
+					currentAps,
+					vlanIds, reason));
+		}
+	}
+
+	// *************
+	// IInfoProvider
+	// *************
+
+	@Override
+	public Map<String, Object> getInfo(String type) {
+		if (!"summary".equals(type))
+			return null;
+
+		Map<String, Object> info = new HashMap<String, Object>();
+		info.put("# hosts", deviceMap.size());
+		return info;
+	}
+
+	// ******************
+	// IOFMessageListener
+	// ******************
+
+	@Override
+	public String getName() {
+		return MODULE_NAME;
+	}
+
+	@Override
+	public boolean isCallbackOrderingPrereq(OFType type, String name) {
+		return ((type == OFType.PACKET_IN || type == OFType.FLOW_MOD)
+				&& name.equals("topology"));
+	}
+
+	@Override
+	public boolean isCallbackOrderingPostreq(OFType type, String name) {
+		return false;
+	}
+
+	@Override
+	public Command receive(IOFSwitch sw, OFMessage msg,
+			FloodlightContext cntx) {
+		switch (msg.getType()) {
+		case PACKET_IN:
+			cntIncoming.increment();
+			return this.processPacketInMessage(sw, (OFPacketIn) msg, cntx);
+		default:
+			break;
+		}
+		return Command.CONTINUE;
+	}
+
+	// ***************
+	// IFlowReconcileListener
+	// ***************
+	@Override
+	public Command reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList) {
+		ListIterator<OFMatchReconcile> iter = ofmRcList.listIterator();
+		while (iter.hasNext()) {
+			OFMatchReconcile ofm = iter.next();
+
+			// Remove the STOPPed flow.
+			if (Command.STOP == reconcileFlow(ofm)) {
+				iter.remove();
+			}
+		}
+
+		if (ofmRcList.size() > 0) {
+			return Command.CONTINUE;
+		} else {
+			return Command.STOP;
+		}
+	}
+
+	protected Command reconcileFlow(OFMatchReconcile ofm) {
+		cntReconcileRequest.increment();
+		// Extract source entity information
+		Entity srcEntity =
+				getEntityFromFlowMod(ofm.ofmWithSwDpid, true);
+		if (srcEntity == null) {
+			cntReconcileNoSource.increment();
+			return Command.STOP;
+		}
+
+		// Find the device by source entity
+		Device srcDevice = findDeviceByEntity(srcEntity);
+		if (srcDevice == null)  {
+			cntReconcileNoSource.increment();
+			return Command.STOP;
+		}
+		// Store the source device in the context
+		fcStore.put(ofm.cntx, CONTEXT_SRC_DEVICE, srcDevice);
+
+		// Find the device matching the destination from the entity
+		// classes of the source.
+		Entity dstEntity = getEntityFromFlowMod(ofm.ofmWithSwDpid, false);
+		Device dstDevice = null;
+		if (dstEntity != null) {
+			dstDevice = findDestByEntity(srcDevice.getEntityClass(), dstEntity);
+			if (dstDevice != null)
+				fcStore.put(ofm.cntx, CONTEXT_DST_DEVICE, dstDevice);
+			else
+				cntReconcileNoDest.increment();
+		} else {
+			cntReconcileNoDest.increment();
+		}
+		if (logger.isTraceEnabled()) {
+			logger.trace("Reconciling flow: match={}, srcEntity={}, srcDev={}, "
+					+ "dstEntity={}, dstDev={}",
+					new Object[] {ofm.ofmWithSwDpid.getMatch(),
+							srcEntity, srcDevice,
+							dstEntity, dstDevice } );
+		}
+		return Command.CONTINUE;
+	}
+
+	// *****************
+	// IFloodlightModule
+	// *****************
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		Collection<Class<? extends IFloodlightService>> l =
+				new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(IDeviceService.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(IDeviceService.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(IStorageSourceService.class);
+		l.add(ITopologyService.class);
+		l.add(IRestApiService.class);
+		l.add(IThreadPoolService.class);
+		l.add(IFlowReconcileService.class);
+		l.add(IEntityClassifierService.class);
+		l.add(ISyncService.class);
+		return l;
+	}
+
+	@Override
+	public void init(FloodlightModuleContext fmc) throws FloodlightModuleException {
+		this.perClassIndices =
+				new HashSet<EnumSet<DeviceField>>();
+		addIndex(true, EnumSet.of(DeviceField.IPV4));
+
+		this.deviceListeners = new ListenerDispatcher<String, IDeviceListener>();
+		this.suppressAPs = Collections.newSetFromMap(
+				new ConcurrentHashMap<SwitchPort, Boolean>());
+
+		this.floodlightProvider =
+				fmc.getServiceImpl(IFloodlightProviderService.class);
+		this.storageSource =
+				fmc.getServiceImpl(IStorageSourceService.class);
+		this.topology =
+				fmc.getServiceImpl(ITopologyService.class);
+		this.restApi = fmc.getServiceImpl(IRestApiService.class);
+		this.threadPool = fmc.getServiceImpl(IThreadPoolService.class);
+		this.flowReconcileMgr = fmc.getServiceImpl(IFlowReconcileService.class);
+		this.flowReconcileEngine = fmc.getServiceImpl(IFlowReconcileEngineService.class);
+		this.entityClassifier = fmc.getServiceImpl(IEntityClassifierService.class);
+		this.debugCounters = fmc.getServiceImpl(IDebugCounterService.class);
+		this.debugEventService = fmc.getServiceImpl(IDebugEventService.class);
+		this.syncService = fmc.getServiceImpl(ISyncService.class);
+		this.deviceSyncManager = new DeviceSyncManager();
+		this.haListenerDelegate = new HAListenerDelegate();
+		registerDeviceManagerDebugCounters();
+		registerDeviceManagerDebugEvents();
+		this.addListener(new DeviceDebugEventLogger());
+	}
+
+	private void registerDeviceManagerDebugEvents() throws FloodlightModuleException {
+		if (debugEventService == null) {
+			logger.error("debugEventService should not be null");
+		}
+		EventCategoryBuilder<DeviceEvent> ecb = debugEventService.buildEvent(DeviceEvent.class);
+		debugEventCategory = ecb.setModuleName(PACKAGE)
+				.setEventName("hostevent")
+				.setEventDescription("Host added, removed, updated, or moved")
+				.setEventType(EventType.ALWAYS_LOG)
+				.setBufferCapacity(500)
+				.setAckable(false)
+				.register();
+	}
+
+	@Override
+	public void startUp(FloodlightModuleContext fmc)
+			throws FloodlightModuleException {
+		isMaster = (floodlightProvider.getRole() == HARole.ACTIVE);
+		primaryIndex = new DeviceUniqueIndex(entityClassifier.getKeyFields());
+		secondaryIndexMap = new HashMap<EnumSet<DeviceField>, DeviceIndex>();
+
+		deviceMap = new ConcurrentHashMap<Long, Device>();
+		classStateMap =
+				new ConcurrentHashMap<String, ClassState>();
+		apComparator = new AttachmentPointComparator();
+
+		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
+		floodlightProvider.addHAListener(this.haListenerDelegate);
+		if (topology != null)
+			topology.addListener(this);
+		flowReconcileMgr.addFlowReconcileListener(this);
+		entityClassifier.addListener(this);
+
+		ScheduledExecutorService ses = threadPool.getScheduledExecutor();
+		Runnable ecr = new Runnable() {
+			@Override
+			public void run() {
+				cleanupEntities();
+				entityCleanupTask.reschedule(ENTITY_CLEANUP_INTERVAL,
+						TimeUnit.SECONDS);
+			}
+		};
+		entityCleanupTask = new SingletonTask(ses, ecr);
+		entityCleanupTask.reschedule(ENTITY_CLEANUP_INTERVAL,
+				TimeUnit.SECONDS);
+
+		Runnable consolidateStoreRunner = new Runnable() {
+			@Override
+			public void run() {
+				deviceSyncManager.consolidateStore();
+				storeConsolidateTask.reschedule(syncStoreConsolidateIntervalMs,
+						TimeUnit.MILLISECONDS);
+			}
+		};
+		storeConsolidateTask = new SingletonTask(ses, consolidateStoreRunner);
+		if (isMaster)
+			storeConsolidateTask.reschedule(syncStoreConsolidateIntervalMs,
+					TimeUnit.MILLISECONDS);
+
+
+		if (restApi != null) {
+			restApi.addRestletRoutable(new DeviceRoutable());
+		} else {
+			logger.debug("Could not instantiate REST API");
+		}
+
+		try {
+			this.syncService.registerStore(DEVICE_SYNC_STORE_NAME, Scope.LOCAL);
+			this.storeClient = this.syncService
+					.getStoreClient(DEVICE_SYNC_STORE_NAME,
+							String.class,
+							DeviceSyncRepresentation.class);
+		} catch (SyncException e) {
+			throw new FloodlightModuleException("Error while setting up sync service", e);
+		}
+		floodlightProvider.addInfoProvider("summary", this);
+	}
+
+	private void registerDeviceManagerDebugCounters() throws FloodlightModuleException {
+		if (debugCounters == null) {
+			logger.error("Debug Counter Service not found.");
+		}
+		debugCounters.registerModule(PACKAGE);
+		cntIncoming = debugCounters.registerCounter(PACKAGE, "incoming",
+				"All incoming packets seen by this module");
+		cntReconcileRequest = debugCounters.registerCounter(PACKAGE,
+				"reconcile-request",
+				"Number of flows that have been received for reconciliation by " +
+				"this module");
+		cntReconcileNoSource = debugCounters.registerCounter(PACKAGE,
+				"reconcile-no-source-device",
+				"Number of flow reconcile events that failed because no source " +
+						"device could be identified", IDebugCounterService.MetaData.WARN); // is this really a IDebugCounterService.CTR_MDATA_WARNing
+		cntReconcileNoDest = debugCounters.registerCounter(PACKAGE,
+				"reconcile-no-dest-device",
+				"Number of flow reconcile events that failed because no " +
+						"destination device could be identified", IDebugCounterService.MetaData.WARN); // is this really a IDebugCounterService.CTR_MDATA_WARNing
+		cntInvalidSource = debugCounters.registerCounter(PACKAGE,
+				"invalid-source",
+				"Number of packetIns that were discarded because the source " +
+						"MAC was invalid (broadcast, multicast, or zero)", IDebugCounterService.MetaData.WARN);
+		cntNoSource = debugCounters.registerCounter(PACKAGE, "no-source-device",
+				"Number of packetIns that were discarded because the " +
+						"could not identify a source device. This can happen if a " +
+						"packet is not allowed, appears on an illegal port, does not " +
+						"have a valid address space, etc.", IDebugCounterService.MetaData.WARN);
+		cntInvalidDest = debugCounters.registerCounter(PACKAGE,
+				"invalid-dest",
+				"Number of packetIns that were discarded because the dest " +
+						"MAC was invalid (zero)", IDebugCounterService.MetaData.WARN);
+		cntNoDest = debugCounters.registerCounter(PACKAGE, "no-dest-device",
+				"Number of packetIns that did not have an associated " +
+						"destination device. E.g., because the destination MAC is " +
+				"broadcast/multicast or is not yet known to the controller.");
+		cntDhcpClientNameSnooped = debugCounters.registerCounter(PACKAGE,
+				"dhcp-client-name-snooped",
+				"Number of times a DHCP client name was snooped from a " +
+				"packetIn.");
+		cntDeviceOnInternalPortNotLearned = debugCounters.registerCounter(
+				PACKAGE,
+				"device-on-internal-port-not-learned",
+				"Number of times packetIn was received on an internal port and" +
+						"no source device is known for the source MAC. The packetIn is " +
+						"discarded.", IDebugCounterService.MetaData.WARN);
+		cntPacketNotAllowed = debugCounters.registerCounter(PACKAGE,
+				"packet-not-allowed",
+				"Number of times a packetIn was not allowed due to spoofing " +
+						"protection configuration.", IDebugCounterService.MetaData.WARN); // is this really a IDebugCounterService.CTR_MDATA_WARNing?
+		cntNewDevice = debugCounters.registerCounter(PACKAGE, "new-device",
+				"Number of times a new device was learned");
+		cntPacketOnInternalPortForKnownDevice = debugCounters.registerCounter(
+				PACKAGE,
+				"packet-on-internal-port-for-known-device",
+				"Number of times a packetIn was received on an internal port " +
+				"for a known device.");
+		cntNewEntity = debugCounters.registerCounter(PACKAGE, "new-entity",
+				"Number of times a new entity was learned for an existing device");
+		cntDeviceChanged = debugCounters.registerCounter(PACKAGE, "device-changed",
+				"Number of times device properties have changed");
+		cntDeviceMoved = debugCounters.registerCounter(PACKAGE, "device-moved",
+				"Number of times devices have moved");
+		cntCleanupEntitiesRuns = debugCounters.registerCounter(PACKAGE,
+				"cleanup-entities-runs",
+				"Number of times the entity cleanup task has been run");
+		cntEntityRemovedTimeout = debugCounters.registerCounter(PACKAGE,
+				"entity-removed-timeout",
+				"Number of times entities have been removed due to timeout " +
+						"(entity has been inactive for " + ENTITY_TIMEOUT/1000 + "s)");
+		cntDeviceDeleted = debugCounters.registerCounter(PACKAGE, "device-deleted",
+				"Number of devices that have been removed due to inactivity");
+		cntDeviceReclassifyDelete = debugCounters.registerCounter(PACKAGE,
+				"device-reclassify-delete",
+				"Number of devices that required reclassification and have been " +
+				"temporarily delete for reclassification");
+		cntDeviceStrored = debugCounters.registerCounter(PACKAGE, "device-stored",
+				"Number of device entries written or updated to the sync store");
+		cntDeviceStoreThrottled = debugCounters.registerCounter(PACKAGE,
+				"device-store-throttled",
+				"Number of times a device update to the sync store was " +
+						"requested but not performed because the same device entities " +
+				"have recently been updated already");
+		cntDeviceRemovedFromStore = debugCounters.registerCounter(PACKAGE,
+				"device-removed-from-store",
+				"Number of devices that were removed from the sync store " +
+						"because the local controller removed the device due to " +
+				"inactivity");
+		cntSyncException = debugCounters.registerCounter(PACKAGE, "sync-exception",
+				"Number of times an operation on the sync store resulted in " +
+						"sync exception", IDebugCounterService.MetaData.WARN); // it this an error?
+		cntDevicesFromStore = debugCounters.registerCounter(PACKAGE,
+				"devices-from-store",
+				"Number of devices that were read from the sync store after " +
+				"the local controller transitioned from SLAVE to MASTER");
+		cntConsolidateStoreRuns = debugCounters.registerCounter(PACKAGE,
+				"consolidate-store-runs",
+				"Number of times the task to consolidate entries in the " +
+				"store witch live known devices has been run");
+		cntConsolidateStoreDevicesRemoved = debugCounters.registerCounter(PACKAGE,
+				"consolidate-store-devices-removed",
+				"Number of times a device has been removed from the sync " +
+						"store because no corresponding live device is known. " +
+						"This indicates a remote controller still writing device " +
+						"entries despite the local controller being MASTER or an " +
+						"incosistent store update from the local controller.", IDebugCounterService.MetaData.WARN);
+		cntTransitionToMaster = debugCounters.registerCounter(PACKAGE,
+				"transition-to-master",
+				"Number of times this controller has transitioned from SLAVE " +
+				"to MASTER role. Will be 0 or 1.");
+	}
+
+	// ***************
+	// IHAListener
+	// ***************
+
+	protected class HAListenerDelegate implements IHAListener {
+		@Override
+		public void transitionToActive() {
+			DeviceManagerImpl.this.isMaster = true;
+			DeviceManagerImpl.this.deviceSyncManager.goToMaster();
+		}
+
+		@Override
+		public void controllerNodeIPsChanged(
+				Map<String, String> curControllerNodeIPs,
+				Map<String, String> addedControllerNodeIPs,
+				Map<String, String> removedControllerNodeIPs) {
+			// no-op
+		}
+
+		@Override
+		public String getName() {
+			return DeviceManagerImpl.this.getName();
+		}
+
+		@Override
+		public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
+				String name) {
+			return ("topology".equals(name) ||
+					"bvsmanager".equals(name));
+		}
+
+		@Override
+		public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
+				String name) {
+			// TODO Auto-generated method stub
+			return false;
+		}
+
+		@Override
+		public void transitionToStandby() {
+			DeviceManagerImpl.this.isMaster = false;
+			//TODO @Ryan is there a goToStandby()?
+			//DeviceManagerImpl.this.deviceSyncManager.goToSlave();
+		}
+	}
+
+
+	// ****************
+	// Internal methods
+	// ****************
+
+	protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
+		Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+
+		// Extract source entity information
+		Entity srcEntity = getSourceEntityFromPacket(eth, sw.getId(), (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+		if (srcEntity == null) {
+			cntInvalidSource.increment();
+			return Command.STOP;
+		}
+
+		// Learn from ARP packet for special VRRP settings.
+		// In VRRP settings, the source MAC address and sender MAC
+		// addresses can be different.  In such cases, we need to learn
+		// the IP to MAC mapping of the VRRP IP address.  The source
+		// entity will not have that information.  Hence, a separate call
+		// to learn devices in such cases.
+		learnDeviceFromArpResponseData(eth, sw.getId(), (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+
+		// Learn/lookup device information
+		Device srcDevice = learnDeviceByEntity(srcEntity);
+		if (srcDevice == null) {
+			cntNoSource.increment();
+			return Command.STOP;
+		}
+
+		// Store the source device in the context
+		fcStore.put(cntx, CONTEXT_SRC_DEVICE, srcDevice);
+
+		// Find the device matching the destination from the entity
+		// classes of the source.
+		if (eth.getDestinationMACAddress().getLong() == 0) {
+			cntInvalidDest.increment();
+			return Command.STOP;
+		}
+		Entity dstEntity = getDestEntityFromPacket(eth);
+		Device dstDevice = null;
+		if (dstEntity != null) {
+			dstDevice = findDestByEntity(srcDevice.getEntityClass(), dstEntity);
+			if (dstDevice != null)
+				fcStore.put(cntx, CONTEXT_DST_DEVICE, dstDevice);
+			else
+				cntNoDest.increment();
+		} else {
+			cntNoDest.increment();
+		}
+
+		if (logger.isTraceEnabled()) {
+			logger.trace("Received PI: {} on switch {}, port {} *** eth={}" +
+					" *** srcDev={} *** dstDev={} *** ",
+					new Object[] { pi, sw.getId().toString(), (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)), eth,
+					srcDevice, dstDevice });
+		}
+
+		snoopDHCPClientName(eth, srcDevice);
+
+		return Command.CONTINUE;
+	}
+
+	/**
+	 * Snoop and record client-provided host name from DHCP requests
+	 * @param eth
+	 * @param srcDevice
+	 */
+	private void snoopDHCPClientName(Ethernet eth, Device srcDevice) {
+		if (! (eth.getPayload() instanceof IPv4) )
+			return;
+		IPv4 ipv4 = (IPv4) eth.getPayload();
+		if (! (ipv4.getPayload() instanceof UDP) )
+			return;
+		UDP udp = (UDP) ipv4.getPayload();
+		if (!(udp.getPayload() instanceof DHCP))
+			return;
+		DHCP dhcp = (DHCP) udp.getPayload();
+		byte opcode = dhcp.getOpCode();
+		if (opcode == DHCP.OPCODE_REQUEST) {
+			DHCPOption dhcpOption = dhcp.getOption(
+					DHCPOptionCode.OptionCode_Hostname);
+			if (dhcpOption != null) {
+				cntDhcpClientNameSnooped.increment();
+				srcDevice.dhcpClientName = new String(dhcpOption.getData());
+			}
+		}
+	}
+
+	/**
+	 * Check whether the given attachment point is valid given the current
+	 * topology
+	 * @param switchDPID the DPID
+	 * @param switchPort the port
+	 * @return true if it's a valid attachment point
+	 */
+	public boolean isValidAttachmentPoint(DatapathId switchDPID,
+			OFPort switchPort) {
+		if (topology.isAttachmentPointPort(switchDPID, switchPort) == false)
+			return false;
+
+		if (suppressAPs.contains(new SwitchPort(switchDPID, switchPort)))
+			return false;
+
+		return true;
+	}
+
+	/**
+	 * Get sender IP address from packet if the packet is an ARP
+	 * packet and if the source MAC address matches the ARP packets
+	 * sender MAC address.
+	 * @param eth
+	 * @param dlAddr
+	 * @return
+	 */
+	private IPv4Address getSrcNwAddr(Ethernet eth, MacAddress dlAddr) {
+		if (eth.getPayload() instanceof ARP) {
+			ARP arp = (ARP) eth.getPayload();
+			if ((arp.getProtocolType() == ARP.PROTO_TYPE_IP) && (MacAddress.of(arp.getSenderHardwareAddress()).equals(dlAddr))) {
+				return IPv4Address.of(arp.getSenderProtocolAddress());
+			}
+		}
+		return IPv4Address.NONE;
+	}
+
+	/**
+	 * Parse an entity from an {@link Ethernet} packet.
+	 * @param eth the packet to parse
+	 * @param sw the switch on which the packet arrived
+	 * @param pi the original packetin
+	 * @return the entity from the packet
+	 */
+	protected Entity getSourceEntityFromPacket(Ethernet eth, DatapathId swdpid, OFPort port) {
+		MacAddress dlAddr = eth.getSourceMACAddress();
+
+		// Ignore broadcast/multicast source
+		if (dlAddr.isBroadcast() || dlAddr.isMulticast())
+			return null;
+		// Ignore 0 source mac
+		if (dlAddr.getLong() == 0)
+			return null;
+
+		VlanVid vlan = VlanVid.ofVlan(eth.getVlanID());
+		IPv4Address nwSrc = getSrcNwAddr(eth, dlAddr);
+		return new Entity(dlAddr,
+				vlan,
+				nwSrc,
+				swdpid,
+				port,
+				new Date());
+	}
+
+	/**
+	 * Learn device from ARP data in scenarios where the
+	 * Ethernet source MAC is different from the sender hardware
+	 * address in ARP data.
+	 */
+	protected void learnDeviceFromArpResponseData(Ethernet eth,
+			DatapathId swdpid,
+			OFPort port) {
+
+		if (!(eth.getPayload() instanceof ARP)) return;
+		ARP arp = (ARP) eth.getPayload();
+
+		MacAddress dlAddr = eth.getSourceMACAddress();
+
+		MacAddress senderAddr = MacAddress.of(arp.getSenderHardwareAddress());
+
+		if (dlAddr.equals(senderAddr)) return; // arp request
+
+		// Ignore broadcast/multicast source
+		if (senderAddr.isBroadcast() || senderAddr.isMulticast())
+			return;
+		// Ignore zero sender mac
+		if (senderAddr.getLong() == 0)
+			return;
+
+		VlanVid vlan = VlanVid.ofVlan(eth.getVlanID());
+		IPv4Address nwSrc = IPv4Address.of(arp.getSenderProtocolAddress());
+
+		Entity e =  new Entity(senderAddr,
+				((vlan.getVlan() >= 0) ? vlan : null),
+				((nwSrc.getInt() != 0) ? nwSrc : null),
+				swdpid,
+				port,
+				new Date());
+
+		learnDeviceByEntity(e);
+	}
+
+	/**
+	 * Get a (partial) entity for the destination from the packet.
+	 * @param eth
+	 * @return
+	 */
+	protected Entity getDestEntityFromPacket(Ethernet eth) {
+		MacAddress dlAddr = eth.getDestinationMACAddress();
+		VlanVid vlan = VlanVid.ofVlan(eth.getVlanID());
+		IPv4Address nwDst = IPv4Address.NONE;
+
+		// Ignore broadcast/multicast destination
+		if (dlAddr.isBroadcast() || dlAddr.isMulticast())
+			return null;
+		// Ignore zero dest mac
+		if (dlAddr.getLong() == 0)
+			return null;
+
+		if (eth.getPayload() instanceof IPv4) {
+			IPv4 ipv4 = (IPv4) eth.getPayload();
+			nwDst = ipv4.getDestinationAddress();
+		}
+		
+		return new Entity(dlAddr,
+				vlan,
+				nwDst,
+				null,
+				null,
+				null);
+	}
+
+	/**
+	 * Parse an entity from an OFMatchWithSwDpid.
+	 * @param ofmWithSwDpid
+	 * @return the entity from the packet
+	 */
+	private Entity getEntityFromFlowMod(OFMatchWithSwDpid ofmWithSwDpid,
+			boolean isSource) {
+		MacAddress dlAddr = ofmWithSwDpid.getMatch().get(MatchField.ETH_SRC);
+		IPv4Address nwSrc = ofmWithSwDpid.getMatch().get(MatchField.IPV4_SRC);
+		if (!isSource) {
+			dlAddr = ofmWithSwDpid.getMatch().get(MatchField.ETH_DST);
+			nwSrc = ofmWithSwDpid.getMatch().get(MatchField.IPV4_DST);
+		}
+
+		// Ignore broadcast/multicast source
+		if (dlAddr.isBroadcast() || dlAddr.isMulticast())
+			return null;
+
+		DatapathId swDpid = DatapathId.NONE;
+		OFPort inPort = OFPort.ZERO;
+
+		if (isSource) {
+			swDpid = ofmWithSwDpid.getDpid();
+			inPort = ofmWithSwDpid.getMatch().get(MatchField.IN_PORT);
+		}
+
+		/**for the new flow cache design, the flow mods retrived are not always
+		 * from the source, learn AP should be disabled --meiyang*/
+		boolean learnap = false;
+		/**
+		 * if (swDpid == null ||
             inPort == null ||
             !isValidAttachmentPoint(swDpid, inPort)) {
             // If this is an internal port or we otherwise don't want
@@ -1450,1177 +1405,1164 @@ IFlowReconcileListener, IInfoProvider {
             // as a key field.
             learnap = false;
         }
-        */
-
-        short vlan = ofmWithSwDpid.getOfMatch().getDataLayerVirtualLan();
-        return new Entity(dlAddr,
-                          ((vlan >= 0) ? vlan : null),
-                          ((nwSrc != 0) ? nwSrc : null),
-                          (learnap ? swDpid : null),
-                          (learnap ? (int)inPort : null),
-                          new Date());
-    }
-
-    /**
-     * Look up a {@link Device} based on the provided {@link Entity}. We first
-     * check the primary index. If we do not find an entry there we classify
-     * the device into its IEntityClass and query the classIndex.
-     * This implies that all key field of the current IEntityClassifier must
-     * be present in the entity for the lookup to succeed!
-     * @param entity the entity to search for
-     * @return The {@link Device} object if found
-     */
-    protected Device findDeviceByEntity(Entity entity) {
-        // Look up the fully-qualified entity to see if it already
-        // exists in the primary entity index.
-        Long deviceKey = primaryIndex.findByEntity(entity);
-        IEntityClass entityClass = null;
-
-        if (deviceKey == null) {
-            // If the entity does not exist in the primary entity index,
-            // use the entity classifier for find the classes for the
-            // entity. Look up the entity in the returned class'
-            // class entity index.
-            entityClass = entityClassifier.classifyEntity(entity);
-            if (entityClass == null) {
-                return null;
-            }
-            ClassState classState = getClassState(entityClass);
-
-            if (classState.classIndex != null) {
-                deviceKey =
-                        classState.classIndex.findByEntity(entity);
-            }
-        }
-        if (deviceKey == null) return null;
-        return deviceMap.get(deviceKey);
-    }
-
-    /**
-     * Get a destination device using entity fields that corresponds with
-     * the given source device.  The source device is important since
-     * there could be ambiguity in the destination device without the
-     * attachment point information.
-     * @param reference  the source device's entity class.
-     *                   The returned destination will be
-     *                   in the same entity class as the source.
-     * @param dstEntity  the entity to look up
-     * @return an {@link Device} or null if no device is found.
-     */
-    protected Device findDestByEntity(IEntityClass reference,
-                                      Entity dstEntity) {
-
-        // Look  up the fully-qualified entity to see if it
-        // exists in the primary entity index
-        Long deviceKey = primaryIndex.findByEntity(dstEntity);
-
-        if (deviceKey == null) {
-            // This could happen because:
-            // 1) no destination known, or a broadcast destination
-            // 2) if we have attachment point key fields since
-            // attachment point information isn't available for
-            // destination devices.
-            // For the second case, we'll need to match up the
-            // destination device with the class of the source
-            // device.
-            ClassState classState = getClassState(reference);
-            if (classState.classIndex == null) {
-                return null;
-            }
-            deviceKey = classState.classIndex.findByEntity(dstEntity);
-        }
-        if (deviceKey == null) return null;
-        return deviceMap.get(deviceKey);
-    }
-
-    /**
-     * Look up a {@link Device} within a particular entity class based on
-     * the provided {@link Entity}.
-     * @param clazz the entity class to search for the entity
-     * @param entity the entity to search for
-     * @return The {@link Device} object if found
+		 */
+
+		OFVlanVidMatch vlan = ofmWithSwDpid.getMatch().get(MatchField.VLAN_VID);
+		return new Entity(dlAddr,
+				((vlan.getVlan() >= 0) ? vlan.getVlanVid() : null),
+				((nwSrc.getInt() != 0) ? nwSrc : null),
+				(learnap ? swDpid : null),
+				(learnap ? inPort : null),
+				new Date());
+	}
+
+	/**
+	 * Look up a {@link Device} based on the provided {@link Entity}. We first
+	 * check the primary index. If we do not find an entry there we classify
+	 * the device into its IEntityClass and query the classIndex.
+	 * This implies that all key field of the current IEntityClassifier must
+	 * be present in the entity for the lookup to succeed!
+	 * @param entity the entity to search for
+	 * @return The {@link Device} object if found
+	 */
+	protected Device findDeviceByEntity(Entity entity) {
+		// Look up the fully-qualified entity to see if it already
+		// exists in the primary entity index.
+		Long deviceKey = primaryIndex.findByEntity(entity);
+		IEntityClass entityClass = null;
+
+		if (deviceKey == null) {
+			// If the entity does not exist in the primary entity index,
+			// use the entity classifier for find the classes for the
+			// entity. Look up the entity in the returned class'
+			// class entity index.
+			entityClass = entityClassifier.classifyEntity(entity);
+			if (entityClass == null) {
+				return null;
+			}
+			ClassState classState = getClassState(entityClass);
+
+			if (classState.classIndex != null) {
+				deviceKey = classState.classIndex.findByEntity(entity);
+			}
+		}
+		if (deviceKey == null) return null;
+		return deviceMap.get(deviceKey);
+	}
+
+	/**
+	 * Get a destination device using entity fields that corresponds with
+	 * the given source device.  The source device is important since
+	 * there could be ambiguity in the destination device without the
+	 * attachment point information.
+	 * @param reference  the source device's entity class.
+	 *                   The returned destination will be
+	 *                   in the same entity class as the source.
+	 * @param dstEntity  the entity to look up
+	 * @return an {@link Device} or null if no device is found.
+	 */
+	protected Device findDestByEntity(IEntityClass reference,
+			Entity dstEntity) {
+
+		// Look  up the fully-qualified entity to see if it
+		// exists in the primary entity index
+		Long deviceKey = primaryIndex.findByEntity(dstEntity);
+
+		if (deviceKey == null) {
+			// This could happen because:
+			// 1) no destination known, or a broadcast destination
+			// 2) if we have attachment point key fields since
+			// attachment point information isn't available for
+			// destination devices.
+			// For the second case, we'll need to match up the
+			// destination device with the class of the source
+			// device.
+			ClassState classState = getClassState(reference);
+			if (classState.classIndex == null) {
+				return null;
+			}
+			deviceKey = classState.classIndex.findByEntity(dstEntity);
+		}
+		if (deviceKey == null) return null;
+		return deviceMap.get(deviceKey);
+	}
+
+	/**
+	 * Look up a {@link Device} within a particular entity class based on
+	 * the provided {@link Entity}.
+	 * @param clazz the entity class to search for the entity
+	 * @param entity the entity to search for
+	 * @return The {@link Device} object if found
     private Device findDeviceInClassByEntity(IEntityClass clazz,
                                                Entity entity) {
         // XXX - TODO
         throw new UnsupportedOperationException();
     }
-     */
-
-    /**
-     * Look up a {@link Device} based on the provided {@link Entity}.  Also
-     * learns based on the new entity, and will update existing devices as
-     * required.
-     *
-     * @param entity the {@link Entity}
-     * @return The {@link Device} object if found
-     */
-    protected Device learnDeviceByEntity(Entity entity) {
-        ArrayList<Long> deleteQueue = null;
-        LinkedList<DeviceUpdate> deviceUpdates = null;
-        Device device = null;
-
-        // we may need to restart the learning process if we detect
-        // concurrent modification.  Note that we ensure that at least
-        // one thread should always succeed so we don't get into infinite
-        // starvation loops
-        while (true) {
-            deviceUpdates = null;
-
-            // Look up the fully-qualified entity to see if it already
-            // exists in the primary entity index.
-            Long deviceKey = primaryIndex.findByEntity(entity);
-            IEntityClass entityClass = null;
-
-            if (deviceKey == null) {
-                // If the entity does not exist in the primary entity index,
-                // use the entity classifier for find the classes for the
-                // entity. Look up the entity in the returned class'
-                // class entity index.
-                entityClass = entityClassifier.classifyEntity(entity);
-                if (entityClass == null) {
-                    // could not classify entity. No device
-                    device = null;
-                    break;
-                }
-                ClassState classState = getClassState(entityClass);
-
-                if (classState.classIndex != null) {
-                    deviceKey =
-                            classState.classIndex.findByEntity(entity);
-                }
-            }
-            if (deviceKey != null) {
-                // If the primary or secondary index contains the entity
-                // use resulting device key to look up the device in the
-                // device map, and use the referenced Device below.
-                device = deviceMap.get(deviceKey);
-                if (device == null) {
-                    // This can happen due to concurrent modification
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("No device for deviceKey {} while "
-                                     + "while processing entity {}",
-                                     deviceKey, entity);
-                    }
-                    // if so, then try again till we don't even get the device key
-                    // and so we recreate the device
-                    continue;
-                }
-            } else {
-                // If the secondary index does not contain the entity,
-                // create a new Device object containing the entity, and
-                // generate a new device ID if the the entity is on an
-                // attachment point port. Otherwise ignore.
-                if (entity.hasSwitchPort() &&
-                        !topology.isAttachmentPointPort(entity.getSwitchDPID(),
-                                                 entity.getSwitchPort().shortValue())) {
-                    cntDeviceOnInternalPortNotLearned.updateCounterNoFlush();
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("Not learning new device on internal"
-                                     + " link: {}", entity);
-                    }
-                    device = null;
-                    break;
-                }
-                // Before we create the new device also check if
-                // the entity is allowed (e.g., for spoofing protection)
-                if (!isEntityAllowed(entity, entityClass)) {
-                    cntPacketNotAllowed.updateCounterNoFlush();
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("PacketIn is not allowed {} {}",
-                                    entityClass.getName(), entity);
-                    }
-                    device = null;
-                    break;
-                }
-                deviceKey = deviceKeyCounter.getAndIncrement();
-                device = allocateDevice(deviceKey, entity, entityClass);
-
-
-                // Add the new device to the primary map with a simple put
-                deviceMap.put(deviceKey, device);
-
-                // update indices
-                if (!updateIndices(device, deviceKey)) {
-                    if (deleteQueue == null)
-                        deleteQueue = new ArrayList<Long>();
-                    deleteQueue.add(deviceKey);
-                    continue;
-                }
-
-                updateSecondaryIndices(entity, entityClass, deviceKey);
-
-                // 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.updateCounterNoFlush();
-                if (logger.isDebugEnabled()) {
-                    logger.debug("New device created: {} deviceKey={}, entity={}",
-                                 new Object[]{device, deviceKey, entity});
-                }
-                // generate new device update
-                deviceUpdates =
-                        updateUpdates(deviceUpdates,
-                                      new DeviceUpdate(device, ADD, null));
-
-                break;
-            }
-            // if it gets here, we have a pre-existing Device for this Entity
-            if (!isEntityAllowed(entity, device.getEntityClass())) {
-                cntPacketNotAllowed.updateCounterNoFlush();
-                if (logger.isDebugEnabled()) {
-                    logger.info("PacketIn is not allowed {} {}",
-                                device.getEntityClass().getName(), entity);
-                }
-                return null;
-            }
-            // If this is not an attachment point port we don't learn the new entity
-            // and don't update indexes. But we do allow the device to continue up
-            // the chain.
-            if (entity.hasSwitchPort() &&
-                    !topology.isAttachmentPointPort(entity.getSwitchDPID(),
-                                                 entity.getSwitchPort().shortValue())) {
-                cntPacketOnInternalPortForKnownDevice.updateCounterNoFlush();
-                break;
-            }
-            int entityindex = -1;
-            if ((entityindex = device.entityIndex(entity)) >= 0) {
-                // Entity already exists
-                // update timestamp on the found entity
-                Date lastSeen = entity.getLastSeenTimestamp();
-                if (lastSeen == null) {
-                    lastSeen = new Date();
-                    entity.setLastSeenTimestamp(lastSeen);
-                }
-                device.entities[entityindex].setLastSeenTimestamp(lastSeen);
-                // we break the loop after checking for changes to the AP
-            } else {
-                // New entity for this device
-                // compute the insertion point for the entity.
-                // see Arrays.binarySearch()
-                entityindex = -(entityindex + 1);
-                Device newDevice = allocateDevice(device, entity, entityindex);
-
-                // generate updates
-                EnumSet<DeviceField> changedFields =
-                        findChangedFields(device, entity);
-
-                // update the device map with a replace call
-                boolean res = deviceMap.replace(deviceKey, device, newDevice);
-                // If replace returns false, restart the process from the
-                // beginning (this implies another thread concurrently
-                // modified this Device).
-                if (!res)
-                    continue;
-
-                device = newDevice;
-                // update indices
-                if (!updateIndices(device, deviceKey)) {
-                    continue;
-                }
-                updateSecondaryIndices(entity,
-                                       device.getEntityClass(),
-                                       deviceKey);
-
-                // We need to count here after all the possible "continue"
-                // statements in this branch
-                cntNewEntity.updateCounterNoFlush();
-                if (changedFields.size() > 0) {
-                    cntDeviceChanged.updateCounterNoFlush();
-                    deviceUpdates =
-                    updateUpdates(deviceUpdates,
-                                  new DeviceUpdate(newDevice, CHANGE,
-                                                   changedFields));
-                }
-                // we break the loop after checking for changed AP
-            }
-            // Update attachment point (will only be hit if the device
-            // already existed and no concurrent modification)
-            if (entity.hasSwitchPort()) {
-                boolean moved =
-                        device.updateAttachmentPoint(entity.getSwitchDPID(),
-                                entity.getSwitchPort().shortValue(),
-                                entity.getLastSeenTimestamp().getTime());
-                // TODO: use update mechanism instead of sending the
-                // notification directly
-                if (moved) {
-                    // we count device moved events in sendDeviceMovedNotification()
-                    sendDeviceMovedNotification(device);
-                    if (logger.isTraceEnabled()) {
-                        logger.trace("Device moved: attachment points {}," +
-                                "entities {}", device.attachmentPoints,
-                                device.entities);
-                    }
-                } else {
-                    if (logger.isTraceEnabled()) {
-                        logger.trace("Device attachment point updated: " +
-                                     "attachment points {}," +
-                                     "entities {}", device.attachmentPoints,
-                                     device.entities);
-                    }
-                }
-            }
-            break;
-        }
-
-        if (deleteQueue != null) {
-            for (Long l : deleteQueue) {
-                Device dev = deviceMap.get(l);
-                this.deleteDevice(dev);
-            }
-        }
-
-        processUpdates(deviceUpdates);
-        deviceSyncManager.storeDeviceThrottled(device);
-
-        return device;
-    }
-
-    protected boolean isEntityAllowed(Entity entity, IEntityClass entityClass) {
-        return true;
-    }
-
-
-
-
-
-    protected EnumSet<DeviceField> findChangedFields(Device device,
-                                                     Entity newEntity) {
-        EnumSet<DeviceField> changedFields =
-                EnumSet.of(DeviceField.IPV4,
-                           DeviceField.VLAN,
-                           DeviceField.SWITCH);
-
-        if (newEntity.getIpv4Address() == null)
-            changedFields.remove(DeviceField.IPV4);
-        if (newEntity.getVlan() == null)
-            changedFields.remove(DeviceField.VLAN);
-        if (newEntity.getSwitchDPID() == null ||
-                newEntity.getSwitchPort() == null)
-            changedFields.remove(DeviceField.SWITCH);
-
-        if (changedFields.size() == 0) return changedFields;
-
-        for (Entity entity : device.getEntities()) {
-            if (newEntity.getIpv4Address() == null ||
-                    (entity.getIpv4Address() != null &&
-                    entity.getIpv4Address().equals(newEntity.getIpv4Address())))
-                changedFields.remove(DeviceField.IPV4);
-            if (newEntity.getVlan() == null ||
-                    (entity.getVlan() != null &&
-                    entity.getVlan().equals(newEntity.getVlan())))
-                changedFields.remove(DeviceField.VLAN);
-            if (newEntity.getSwitchDPID() == null ||
-                    newEntity.getSwitchPort() == null ||
-                    (entity.getSwitchDPID() != null &&
-                    entity.getSwitchPort() != null &&
-                    entity.getSwitchDPID().equals(newEntity.getSwitchDPID()) &&
-                    entity.getSwitchPort().equals(newEntity.getSwitchPort())))
-                changedFields.remove(DeviceField.SWITCH);
-        }
-
-        return changedFields;
-    }
-
-    /**
-     * Send update notifications to listeners
-     * @param updates the updates to process.
-     */
-    protected void processUpdates(Queue<DeviceUpdate> updates) {
-        if (updates == null) return;
-        DeviceUpdate update = null;
-        while (null != (update = updates.poll())) {
-            if (logger.isTraceEnabled()) {
-                logger.trace("Dispatching device update: {}", update);
-            }
-            if (update.change == DeviceUpdate.Change.DELETE)
-                deviceSyncManager.removeDevice(update.device);
-            else
-                deviceSyncManager.storeDevice(update.device);
-            List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
-            notifyListeners(listeners, update);
-        }
-    }
-
-    protected void notifyListeners(List<IDeviceListener> listeners, DeviceUpdate update) {
-        if (listeners == null) {
-            return;
-        }
-        for (IDeviceListener listener : listeners) {
-            switch (update.change) {
-                case ADD:
-                    listener.deviceAdded(update.device);
-                    break;
-                case DELETE:
-                    listener.deviceRemoved(update.device);
-                    break;
-                case CHANGE:
-                    for (DeviceField field : update.fieldsChanged) {
-                        switch (field) {
-                            case IPV4:
-                                listener.deviceIPV4AddrChanged(update.device);
-                                break;
-                            case SWITCH:
-                            case PORT:
-                                //listener.deviceMoved(update.device);
-                                break;
-                            case VLAN:
-                                listener.deviceVlanChanged(update.device);
-                                break;
-                            default:
-                                logger.debug("Unknown device field changed {}",
-                                            update.fieldsChanged.toString());
-                                break;
-                        }
-                    }
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Check if the entity e has all the keyFields set. Returns false if not
-     * @param e entity to check
-     * @param keyFields the key fields to check e against
-     * @return
-     */
-    protected boolean allKeyFieldsPresent(Entity e, EnumSet<DeviceField> keyFields) {
-        for (DeviceField f : keyFields) {
-            switch (f) {
-                case MAC:
-                    // MAC address is always present
-                    break;
-                case IPV4:
-                    if (e.ipv4Address == null) return false;
-                    break;
-                case SWITCH:
-                    if (e.switchDPID == null) return false;
-                    break;
-                case PORT:
-                    if (e.switchPort == null) return false;
-                    break;
-                case VLAN:
-                    // FIXME: vlan==null is ambiguous: it can mean: not present
-                    // or untagged
-                    //if (e.vlan == null) return false;
-                    break;
-                default:
-                    // we should never get here. unless somebody extended
-                    // DeviceFields
-                    throw new IllegalStateException();
-            }
-        }
-        return true;
-    }
-
-    private LinkedList<DeviceUpdate>
-    updateUpdates(LinkedList<DeviceUpdate> list, DeviceUpdate update) {
-        if (update == null) return list;
-        if (list == null)
-            list = new LinkedList<DeviceUpdate>();
-        list.add(update);
-
-        return list;
-    }
-
-    /**
-     * Get the secondary index for a class.  Will return null if the
-     * secondary index was created concurrently in another thread.
-     * @param clazz the class for the index
-     * @return
-     */
-    private ClassState getClassState(IEntityClass clazz) {
-        ClassState classState = classStateMap.get(clazz.getName());
-        if (classState != null) return classState;
-
-        classState = new ClassState(clazz);
-        ClassState r = classStateMap.putIfAbsent(clazz.getName(), classState);
-        if (r != null) {
-            // concurrent add
-            return r;
-        }
-        return classState;
-    }
-
-    /**
-     * Update both the primary and class indices for the provided device.
-     * If the update fails because of an concurrent update, will return false.
-     * @param device the device to update
-     * @param deviceKey the device key for the device
-     * @return true if the update succeeded, false otherwise.
-     */
-    private boolean updateIndices(Device device, Long deviceKey) {
-        if (!primaryIndex.updateIndex(device, deviceKey)) {
-            return false;
-        }
-        IEntityClass entityClass = device.getEntityClass();
-        ClassState classState = getClassState(entityClass);
-
-        if (classState.classIndex != null) {
-            if (!classState.classIndex.updateIndex(device,
-                                                   deviceKey))
-                return false;
-        }
-    return true;
-    }
-
-    /**
-     * Update the secondary indices for the given entity and associated
-     * entity classes
-     * @param entity the entity to update
-     * @param entityClass the entity class for the entity
-     * @param deviceKey the device key to set up
-     */
-    private void updateSecondaryIndices(Entity entity,
-                                        IEntityClass entityClass,
-                                        Long deviceKey) {
-        for (DeviceIndex index : secondaryIndexMap.values()) {
-            index.updateIndex(entity, deviceKey);
-        }
-        ClassState state = getClassState(entityClass);
-        for (DeviceIndex index : state.secondaryIndexMap.values()) {
-            index.updateIndex(entity, deviceKey);
-        }
-    }
-
-    /**
-     * Clean up expired entities/devices
-     */
-    protected void cleanupEntities () {
-        cntCleanupEntitiesRuns.updateCounterWithFlush();
-
-        Calendar c = Calendar.getInstance();
-        c.add(Calendar.MILLISECOND, -ENTITY_TIMEOUT);
-        Date cutoff = c.getTime();
-
-        ArrayList<Entity> toRemove = new ArrayList<Entity>();
-        ArrayList<Entity> toKeep = new ArrayList<Entity>();
-
-        Iterator<Device> diter = deviceMap.values().iterator();
-        LinkedList<DeviceUpdate> deviceUpdates =
-                new LinkedList<DeviceUpdate>();
-
-        while (diter.hasNext()) {
-            Device d = diter.next();
-
-            while (true) {
-                deviceUpdates.clear();
-                toRemove.clear();
-                toKeep.clear();
-                for (Entity e : d.getEntities()) {
-                    if (e.getLastSeenTimestamp() != null &&
-                         0 > e.getLastSeenTimestamp().compareTo(cutoff)) {
-                        // individual entity needs to be removed
-                        toRemove.add(e);
-                    } else {
-                        toKeep.add(e);
-                    }
-                }
-                if (toRemove.size() == 0) {
-                    break;
-                }
-
-                cntEntityRemovedTimeout.updateCounterWithFlush();
-                for (Entity e : toRemove) {
-                    removeEntity(e, d.getEntityClass(), d.getDeviceKey(), toKeep);
-                }
-
-                if (toKeep.size() > 0) {
-                    Device newDevice = allocateDevice(d.getDeviceKey(),
-                                                      d.getDHCPClientName(),
-                                                      d.oldAPs,
-                                                      d.attachmentPoints,
-                                                      toKeep,
-                                                      d.getEntityClass());
-
-                    EnumSet<DeviceField> changedFields =
-                            EnumSet.noneOf(DeviceField.class);
-                    for (Entity e : toRemove) {
-                        changedFields.addAll(findChangedFields(newDevice, e));
-                    }
-                    DeviceUpdate update = null;
-                    if (changedFields.size() > 0) {
-                        update = new DeviceUpdate(d, CHANGE, changedFields);
-                    }
-
-                    if (!deviceMap.replace(newDevice.getDeviceKey(),
-                                           d,
-                                           newDevice)) {
-                        // concurrent modification; try again
-                        // need to use device that is the map now for the next
-                        // iteration
-                        d = deviceMap.get(d.getDeviceKey());
-                        if (null != d)
-                            continue;
-                    }
-                    if (update != null) {
-                        // need to count after all possibly continue stmts in
-                        // this branch
-                        cntDeviceChanged.updateCounterWithFlush();
-                        deviceUpdates.add(update);
-                    }
-                } else {
-                    DeviceUpdate update = new DeviceUpdate(d, DELETE, null);
-                    if (!deviceMap.remove(d.getDeviceKey(), d)) {
-                        // concurrent modification; try again
-                        // need to use device that is the map now for the next
-                        // iteration
-                        d = deviceMap.get(d.getDeviceKey());
-                        if (null != d)
-                            continue;
-                        cntDeviceDeleted.updateCounterWithFlush();
-                    }
-                    deviceUpdates.add(update);
-                }
-                processUpdates(deviceUpdates);
-                break;
-            }
-        }
-        // Since cleanupEntities() is not called in the packet-in pipeline,
-        // debugEvents need to be flushed explicitly
-        debugEvents.flushEvents();
-    }
-
-    protected void removeEntity(Entity removed,
-                              IEntityClass entityClass,
-                              Long deviceKey,
-                              Collection<Entity> others) {
-        // Don't count in this method. This method CAN BE called to clean-up
-        // after concurrent device adds/updates and thus counting here
-        // is misleading
-        for (DeviceIndex index : secondaryIndexMap.values()) {
-            index.removeEntityIfNeeded(removed, deviceKey, others);
-        }
-        ClassState classState = getClassState(entityClass);
-        for (DeviceIndex index : classState.secondaryIndexMap.values()) {
-            index.removeEntityIfNeeded(removed, deviceKey, others);
-        }
-
-        primaryIndex.removeEntityIfNeeded(removed, deviceKey, others);
-
-        if (classState.classIndex != null) {
-            classState.classIndex.removeEntityIfNeeded(removed,
-                                                       deviceKey,
-                                                       others);
-        }
-    }
-
-    /**
-     * method to delete a given device, remove all entities first and then
-     * finally delete the device itself.
-     * @param device
-     */
-    protected void deleteDevice(Device device) {
-        // Don't count in this method. This method CAN BE called to clean-up
-        // after concurrent device adds/updates and thus counting here
-        // is misleading
-        ArrayList<Entity> emptyToKeep = new ArrayList<Entity>();
-        for (Entity entity : device.getEntities()) {
-            this.removeEntity(entity, device.getEntityClass(),
-                device.getDeviceKey(), emptyToKeep);
-        }
-        if (!deviceMap.remove(device.getDeviceKey(), device)) {
-            if (logger.isDebugEnabled())
-                logger.debug("device map does not have this device -" +
-                    device.toString());
-        }
-    }
-
-    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.
-        EnumSet<DeviceField> keys = EnumSet.noneOf(DeviceField.class);
-        if (macAddress != null) keys.add(DeviceField.MAC);
-        if (vlan != null) keys.add(DeviceField.VLAN);
-        if (ipv4Address != null) keys.add(DeviceField.IPV4);
-        if (switchDPID != null) keys.add(DeviceField.SWITCH);
-        if (switchPort != null) keys.add(DeviceField.PORT);
-        return keys;
-    }
-
-    protected Iterator<Device> queryClassByEntity(IEntityClass clazz,
-                                                  EnumSet<DeviceField> keyFields,
-                                                  Entity entity) {
-        ClassState classState = getClassState(clazz);
-        DeviceIndex index = classState.secondaryIndexMap.get(keyFields);
-        if (index == null) return Collections.<Device>emptySet().iterator();
-        return new DeviceIndexInterator(this, index.queryByEntity(entity));
-    }
-
-    protected Device allocateDevice(Long deviceKey,
-                                    Entity entity,
-                                    IEntityClass entityClass) {
-        return new Device(this, deviceKey, entity, entityClass);
-    }
-
-    // TODO: FIX THIS.
-    protected Device allocateDevice(Long deviceKey,
-                                    String dhcpClientName,
-                                    List<AttachmentPoint> aps,
-                                    List<AttachmentPoint> trueAPs,
-                                    Collection<Entity> entities,
-                                    IEntityClass entityClass) {
-        return new Device(this, deviceKey, dhcpClientName, aps, trueAPs,
-                          entities, entityClass);
-    }
-
-    protected Device allocateDevice(Device device,
-                                    Entity entity,
-                                    int insertionpoint) {
-        return new Device(device, entity, insertionpoint);
-    }
-
-    //not used
-    protected Device allocateDevice(Device device, Set <Entity> entities) {
-        List <AttachmentPoint> newPossibleAPs =
-                new ArrayList<AttachmentPoint>();
-        List <AttachmentPoint> newAPs =
-                new ArrayList<AttachmentPoint>();
-        for (Entity entity : entities) {
-            if (entity.switchDPID != null && entity.switchPort != null) {
-                AttachmentPoint aP =
-                        new AttachmentPoint(entity.switchDPID.longValue(),
-                                    entity.switchPort.shortValue(), 0);
-                newPossibleAPs.add(aP);
-            }
-        }
-        if (device.attachmentPoints != null) {
-            for (AttachmentPoint oldAP : device.attachmentPoints) {
-                if (newPossibleAPs.contains(oldAP)) {
-                    newAPs.add(oldAP);
-                }
-            }
-        }
-        if (newAPs.isEmpty())
-            newAPs = null;
-        Device d = new Device(this, device.getDeviceKey(),
-                              device.getDHCPClientName(), newAPs, null,
-                              entities, device.getEntityClass());
-        d.updateAttachmentPoint();
-        return d;
-    }
-
-    // *********************
-    // ITopologyListener
-    // *********************
-
-    /**
-     * Topology listener method.
-     */
-    @Override
-    public void topologyChanged(List<LDUpdate> updateList) {
-        Iterator<Device> diter = deviceMap.values().iterator();
-        if (updateList != null) {
-            if (logger.isTraceEnabled()) {
-                for(LDUpdate update: updateList) {
-                    logger.trace("Topo update: {}", update);
-                }
-            }
-        }
-
-        while (diter.hasNext()) {
-            Device d = diter.next();
-            if (d.updateAttachmentPoint()) {
-                if (logger.isDebugEnabled()) {
-                    logger.debug("Attachment point changed for device: {}", d);
-                }
-                sendDeviceMovedNotification(d);
-            }
-        }
-        // Since topologyChanged() does not occur in the packet-in pipeline,
-        // debugEvents need to be flushed explicitly
-        debugEvents.flushEvents();
-    }
-
-    /**
-     * Send update notifications to listeners
-     * @param updates the updates to process.
-     */
-    protected void sendDeviceMovedNotification(Device d) {
-        cntDeviceMoved.updateCounterNoFlush();
-        deviceSyncManager.storeDevice(d);
-        List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
-        if (listeners != null) {
-            for (IDeviceListener listener : listeners) {
-                listener.deviceMoved(d);
-            }
-        }
-    }
-
-    // *********************
-    // IEntityClassListener
-    // *********************
-
-    @Override
-    public void entityClassChanged (Set<String> entityClassNames) {
-        /* iterate through the devices, reclassify the devices that belong
-         * to these entity class names
-         */
-        Iterator<Device> diter = deviceMap.values().iterator();
-        while (diter.hasNext()) {
-            Device d = diter.next();
-            if (d.getEntityClass() == null ||
-                entityClassNames.contains(d.getEntityClass().getName()))
-                reclassifyDevice(d);
-        }
-    }
-
-    /**
-     * this method will reclassify and reconcile a device - possibilities
-     * are - create new device(s), remove entities from this device. If the
-     * device entity class did not change then it returns false else true.
-     * @param device
-     */
-    protected boolean reclassifyDevice(Device device)
-    {
-        // first classify all entities of this device
-        if (device == null) {
-            logger.debug("In reclassify for null device");
-            return false;
-        }
-        boolean needToReclassify = false;
-        for (Entity entity : device.entities) {
-            IEntityClass entityClass =
-                    this.entityClassifier.classifyEntity(entity);
-            if (entityClass == null || device.getEntityClass() == null) {
-                needToReclassify = true;
-                break;
-            }
-            if (!entityClass.getName().
-                    equals(device.getEntityClass().getName())) {
-                needToReclassify = true;
-                break;
-            }
-        }
-        if (needToReclassify == false) {
-            return false;
-        }
-
-        cntDeviceReclassifyDelete.updateCounterNoFlush();
-        LinkedList<DeviceUpdate> deviceUpdates =
-                new LinkedList<DeviceUpdate>();
-        // delete this device and then re-learn all the entities
-        this.deleteDevice(device);
-        deviceUpdates.add(new DeviceUpdate(device,
-                DeviceUpdate.Change.DELETE, null));
-        if (!deviceUpdates.isEmpty())
-            processUpdates(deviceUpdates);
-        for (Entity entity: device.entities ) {
-            this.learnDeviceByEntity(entity);
-        }
-        // Since reclassifyDevices() is not called in the packet-in pipeline,
-        // debugEvents need to be flushed explicitly
-        debugEvents.flushEvents();
-        return true;
-    }
-
-    /**
-     * For testing: sets the interval between writes of the same device
-     * to the device store.
-     * @param intervalMs
-     */
-    void setSyncStoreWriteInterval(int intervalMs) {
-        this.syncStoreWriteIntervalMs = intervalMs;
-    }
-
-    /**
-     * For testing: sets the time between transition to MASTER and
-     * consolidate store
-     * @param intervalMs
-     */
-    void setInitialSyncStoreConsolidateMs(int intervalMs) {
-        this.initialSyncStoreConsolidateMs = intervalMs;
-    }
-
-    /**
-     * For testing: consolidate the store NOW
-     */
-    void scheduleConsolidateStoreNow() {
-        this.storeConsolidateTask.reschedule(0, TimeUnit.MILLISECONDS);
-    }
-
-    private class DeviceSyncManager  {
-        // maps (opaque) deviceKey to the time in System.nanoTime() when we
-        // last wrote the device to the sync store
-        private final ConcurrentMap<Long, Long> lastWriteTimes =
-                new ConcurrentHashMap<Long, Long>();
-
-        /**
-         * Write the given device to storage if we are MASTER.
-         * Use this method if the device has significantly changed (e.g.,
-         * new AP, new IP, entities removed).
-         * @param d the device to store
-         */
-        public void storeDevice(Device d) {
-            if (!isMaster)
-                return;
-            if (d == null)
-                return;
-            long now = System.nanoTime();
-            writeUpdatedDeviceToStorage(d);
-            lastWriteTimes.put(d.getDeviceKey(), now);
-        }
-
-        /**
-         * Write the given device to storage if we are MASTER and if the
-         * last write for the device was more than this.syncStoreIntervalNs
-         * time ago.
-         * Use this method to updated last active times in the store.
-         * @param d the device to store
-         */
-        public void storeDeviceThrottled(Device d) {
-            long intervalNs = syncStoreWriteIntervalMs*1000L*1000L;
-            if (!isMaster)
-                return;
-            if (d == null)
-                return;
-            long now = System.nanoTime();
-            Long last = lastWriteTimes.get(d.getDeviceKey());
-            if (last == null ||
-                    now - last > intervalNs) {
-                writeUpdatedDeviceToStorage(d);
-                lastWriteTimes.put(d.getDeviceKey(), now);
-            } else {
-                cntDeviceStoreThrottled.updateCounterWithFlush();
-            }
-        }
-
-        /**
-         * Remove the given device from the store. If only some entities have
-         * been removed the updated device should be written using
-         * {@link #storeDevice(Device)}
-         * @param d
-         */
-        public void removeDevice(Device d) {
-            if (!isMaster)
-                return;
-            // FIXME: could we have a problem with concurrent put to the
-            // hashMap? I.e., we write a stale entry to the map after the
-            // delete and now are left with an entry we'll never clean up
-            lastWriteTimes.remove(d.getDeviceKey());
-            try {
-                // TODO: should probably do versioned delete. OTOH, even
-                // if we accidentally delete, we'll write it again after
-                // the next entity ....
-                cntDeviceRemovedFromStore.updateCounterWithFlush();
-                storeClient.delete(DeviceSyncRepresentation.computeKey(d));
-            } catch(ObsoleteVersionException e) {
-                // FIXME
-            } catch (SyncException e) {
-                cntSyncException.updateCounterWithFlush();
-                logger.error("Could not remove device " + d + " from store", e);
-            }
-        }
-
-        /**
-         * Remove the given Versioned device from the store. If the device
-         * was locally modified ignore the delete request.
-         * @param syncedDeviceKey
-         */
-        private void removeDevice(Versioned<DeviceSyncRepresentation> dev) {
-            try {
-                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.updateCounterWithFlush();
-                logger.error("Failed to remove device entry for " +
-                            dev.toString() + " from store.", e);
-            }
-        }
-
-        /**
-         * Synchronously transition from SLAVE to MASTER. By iterating through
-         * the store and learning all devices from the store
-         */
-        private void goToMaster() {
-            if (logger.isDebugEnabled()) {
-                logger.debug("Transitioning to MASTER role");
-            }
-            cntTransitionToMaster.updateCounterWithFlush();
-            IClosableIterator<Map.Entry<String,Versioned<DeviceSyncRepresentation>>>
-                    iter = null;
-            try {
-                iter = storeClient.entries();
-            } catch (SyncException e) {
-                cntSyncException.updateCounterWithFlush();
-                logger.error("Failed to read devices from sync store", e);
-                return;
-            }
-            try {
-                while(iter.hasNext()) {
-                    Versioned<DeviceSyncRepresentation> versionedDevice =
-                            iter.next().getValue();
-                    DeviceSyncRepresentation storedDevice =
-                            versionedDevice.getValue();
-                    if (storedDevice == null)
-                        continue;
-                    cntDevicesFromStore.updateCounterWithFlush();
-                    for(SyncEntity se: storedDevice.getEntities()) {
-                        learnDeviceByEntity(se.asEntity());
-                    }
-                }
-            } finally {
-                if (iter != null)
-                    iter.close();
-            }
-            storeConsolidateTask.reschedule(initialSyncStoreConsolidateMs,
-                                            TimeUnit.MILLISECONDS);
-        }
-
-        /**
-         * Actually perform the write of the device to the store
-         * FIXME: concurrent modification behavior
-         * @param device The device to write
-         */
-        private void writeUpdatedDeviceToStorage(Device device) {
-            try {
-                cntDeviceStrored.updateCounterWithFlush();
-                // FIXME: use a versioned put
-                DeviceSyncRepresentation storeDevice =
-                        new DeviceSyncRepresentation(device);
-                storeClient.put(storeDevice.getKey(), storeDevice);
-            } catch (ObsoleteVersionException e) {
-                // FIXME: what's the right behavior here. Can the store client
-                // even throw this error?
-            } catch (SyncException e) {
-                cntSyncException.updateCounterWithFlush();
-                logger.error("Could not write device " + device +
-                          " to sync store:", e);
-            }
-        }
-
-        /**
-         * Iterate through all entries in the sync store. For each device
-         * in the store check if any stored entity matches a live device. If
-         * no entities match a live device we remove the entry from the store.
-         *
-         * Note: we do not check if all devices known to device manager are
-         * in the store. We rely on regular packetIns for that.
-         * Note: it's possible that multiple entries in the store map to the
-         * same device. We don't check or handle this case.
-         *
-         * We need to perform this check after a SLAVE->MASTER transition to
-         * get rid of all entries the old master might have written to the
-         * store after we took over. We also run it regularly in MASTER
-         * state to ensure we don't have stale entries in the store
-         */
-        private void consolidateStore() {
-            if (!isMaster)
-                return;
-            cntConsolidateStoreRuns.updateCounterWithFlush();
-            if (logger.isDebugEnabled()) {
-                logger.debug("Running consolidateStore.");
-            }
-            IClosableIterator<Map.Entry<String,Versioned<DeviceSyncRepresentation>>>
-                    iter = null;
-            try {
-                iter = storeClient.entries();
-            } catch (SyncException e) {
-                cntSyncException.updateCounterWithFlush();
-                logger.error("Failed to read devices from sync store", e);
-                return;
-            }
-            try {
-                while(iter.hasNext()) {
-                    boolean found = false;
-                    Versioned<DeviceSyncRepresentation> versionedDevice =
-                            iter.next().getValue();
-                    DeviceSyncRepresentation storedDevice =
-                            versionedDevice.getValue();
-                    if (storedDevice == null)
-                        continue;
-                    for(SyncEntity se: storedDevice.getEntities()) {
-                        try {
-                            // Do we have a device for this entity??
-                            IDevice d = findDevice(se.macAddress, se.vlan,
-                                                   se.ipv4Address,
-                                                   se.switchDPID,
-                                                   se.switchPort);
-                            if (d != null) {
-                                found = true;
-                                break;
-                            }
-                        } catch (IllegalArgumentException e) {
-                            // not all key fields provided. Skip entity
-                        }
-                    }
-                    if (!found) {
-                        // We currently DO NOT have a live device that
-                        // matches the current device from the store.
-                        // Delete device from store.
-                        if (logger.isDebugEnabled()) {
-                            logger.debug("Removing device {} from store. No "
-                                         + "corresponding live device",
-                                         storedDevice.getKey());
-                        }
-                        cntConsolidateStoreDevicesRemoved.updateCounterWithFlush();
-                        removeDevice(versionedDevice);
-                    }
-                }
-            } finally {
-                if (iter != null)
-                    iter.close();
-            }
-        }
-    }
-
-
-    /**
-     * For testing. Sets the syncService. Only call after init but before
-     * startUp. Used by MockDeviceManager
-     * @param syncService
-     */
-    protected void setSyncServiceIfNotSet(ISyncService syncService) {
-        if (this.syncService == null)
-            this.syncService = syncService;
-    }
-
-    /**
-     * For testing.
-     * @return
-     */
-    IHAListener getHAListener() {
-        return this.haListenerDelegate;
-    }
-
-    /**
-     * Device Event Class used to log Device related events
-     */
-    private class DeviceEvent {
-        @EventColumn(name = "MAC", description = EventFieldType.MAC)
-        private final long macAddress;
-        @EventColumn(name = "IPs", description = EventFieldType.LIST_IPV4)
-        private final List<Integer> ipv4Addresses;
-        @EventColumn(name = "Old Attachment Points",
-                     description = EventFieldType.LIST_ATTACHMENT_POINT)
-        private final List<SwitchPort> oldAttachmentPoints;
-        @EventColumn(name = "Current Attachment Points",
-                     description = EventFieldType.LIST_ATTACHMENT_POINT)
-        private final List<SwitchPort> currentAttachmentPoints;
-        @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(long macAddress, List<Integer> ipv4Addresses,
-                List<SwitchPort> oldAttachmentPoints,
-                List<SwitchPort> currentAttachmentPoints,
-                List<Short> vlanIds, String reason) {
-            super();
-            this.macAddress = macAddress;
-            this.ipv4Addresses = ipv4Addresses;
-            this.oldAttachmentPoints = oldAttachmentPoints;
-            this.currentAttachmentPoints = currentAttachmentPoints;
-            this.vlanIds = vlanIds;
-            this.reason = reason;
-        }
-    }
+	 */
+
+	/**
+	 * Look up a {@link Device} based on the provided {@link Entity}.  Also
+	 * learns based on the new entity, and will update existing devices as
+	 * required.
+	 *
+	 * @param entity the {@link Entity}
+	 * @return The {@link Device} object if found
+	 */
+	protected Device learnDeviceByEntity(Entity entity) {
+		ArrayList<Long> deleteQueue = null;
+		LinkedList<DeviceUpdate> deviceUpdates = null;
+		Device device = null;
+
+		// we may need to restart the learning process if we detect
+		// concurrent modification.  Note that we ensure that at least
+		// one thread should always succeed so we don't get into infinite
+		// starvation loops
+		while (true) {
+			deviceUpdates = null;
+
+			// Look up the fully-qualified entity to see if it already
+			// exists in the primary entity index.
+			Long deviceKey = primaryIndex.findByEntity(entity);
+			IEntityClass entityClass = null;
+
+			if (deviceKey == null) {
+				// If the entity does not exist in the primary entity index,
+				// use the entity classifier for find the classes for the
+				// entity. Look up the entity in the returned class'
+				// class entity index.
+				entityClass = entityClassifier.classifyEntity(entity);
+				if (entityClass == null) {
+					// could not classify entity. No device
+					device = null;
+					break;
+				}
+				ClassState classState = getClassState(entityClass);
+
+				if (classState.classIndex != null) {
+					deviceKey = classState.classIndex.findByEntity(entity);
+				}
+			}
+			if (deviceKey != null) {
+				// If the primary or secondary index contains the entity
+				// use resulting device key to look up the device in the
+				// device map, and use the referenced Device below.
+				device = deviceMap.get(deviceKey);
+				if (device == null) {
+					// This can happen due to concurrent modification
+					if (logger.isDebugEnabled()) {
+						logger.debug("No device for deviceKey {} while "
+								+ "while processing entity {}",
+								deviceKey, entity);
+					}
+					// if so, then try again till we don't even get the device key
+					// and so we recreate the device
+					continue;
+				}
+			} else {
+				// If the secondary index does not contain the entity,
+				// create a new Device object containing the entity, and
+				// generate a new device ID if the the entity is on an
+				// attachment point port. Otherwise ignore.
+				if (entity.hasSwitchPort() && !topology.isAttachmentPointPort(entity.getSwitchDPID(), entity.getSwitchPort())) {
+					cntDeviceOnInternalPortNotLearned.increment();
+					if (logger.isDebugEnabled()) {
+						logger.debug("Not learning new device on internal"
+								+ " link: {}", entity);
+					}
+					device = null;
+					break;
+				}
+				// Before we create the new device also check if
+				// the entity is allowed (e.g., for spoofing protection)
+				if (!isEntityAllowed(entity, entityClass)) {
+					cntPacketNotAllowed.increment();
+					if (logger.isDebugEnabled()) {
+						logger.debug("PacketIn is not allowed {} {}",
+								entityClass.getName(), entity);
+					}
+					device = null;
+					break;
+				}
+				deviceKey = deviceKeyCounter.getAndIncrement();
+				device = allocateDevice(deviceKey, entity, entityClass);
+
+
+				// Add the new device to the primary map with a simple put
+				deviceMap.put(deviceKey, device);
+				// update indices
+				if (!updateIndices(device, deviceKey)) {
+					if (deleteQueue == null)
+						deleteQueue = new ArrayList<Long>();
+					deleteQueue.add(deviceKey);
+					continue;
+				}
+
+				updateSecondaryIndices(entity, entityClass, deviceKey);
+
+				// 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();
+				if (logger.isDebugEnabled()) {
+					logger.debug("New device created: {} deviceKey={}, entity={}",
+							new Object[]{device, deviceKey, entity});
+				}
+				// generate new device update
+				deviceUpdates = updateUpdates(deviceUpdates, new DeviceUpdate(device, ADD, null));
+
+				break;
+			}
+			// if it gets here, we have a pre-existing Device for this Entity
+			if (!isEntityAllowed(entity, device.getEntityClass())) {
+				cntPacketNotAllowed.increment();
+				if (logger.isDebugEnabled()) {
+					logger.info("PacketIn is not allowed {} {}",
+							device.getEntityClass().getName(), entity);
+				}
+				return null;
+			}
+			// If this is not an attachment point port we don't learn the new entity
+			// and don't update indexes. But we do allow the device to continue up
+			// the chain.
+			if (entity.hasSwitchPort() && !topology.isAttachmentPointPort(entity.getSwitchDPID(), entity.getSwitchPort())) {
+				cntPacketOnInternalPortForKnownDevice.increment();
+				break;
+			}
+			int entityindex = -1;
+			if ((entityindex = device.entityIndex(entity)) >= 0) {
+				// Entity already exists
+				// update timestamp on the found entity
+				Date lastSeen = entity.getLastSeenTimestamp();
+				if (lastSeen == null) {
+					lastSeen = new Date();
+					entity.setLastSeenTimestamp(lastSeen);
+				}
+				device.entities[entityindex].setLastSeenTimestamp(lastSeen);
+				// we break the loop after checking for changes to the AP
+			} else {
+				// New entity for this device
+				// compute the insertion point for the entity.
+				// see Arrays.binarySearch()
+				entityindex = -(entityindex + 1);
+				Device newDevice = allocateDevice(device, entity, entityindex);
+
+				// generate updates
+				EnumSet<DeviceField> changedFields = findChangedFields(device, entity);
+
+				// update the device map with a replace call
+				boolean res = deviceMap.replace(deviceKey, device, newDevice);
+				// If replace returns false, restart the process from the
+				// beginning (this implies another thread concurrently
+				// modified this Device).
+				if (!res)
+					continue;
+
+				device = newDevice;
+				// update indices
+				if (!updateIndices(device, deviceKey)) {
+					continue;
+				}
+				updateSecondaryIndices(entity,
+						device.getEntityClass(),
+						deviceKey);
+
+				// We need to count here after all the possible "continue"
+				// statements in this branch
+				cntNewEntity.increment();
+				if (changedFields.size() > 0) {
+					cntDeviceChanged.increment();
+					deviceUpdates =
+							updateUpdates(deviceUpdates,
+									new DeviceUpdate(newDevice, CHANGE,
+											changedFields));
+				}
+				// we break the loop after checking for changed AP
+			}
+			// Update attachment point (will only be hit if the device
+			// already existed and no concurrent modification)
+			if (entity.hasSwitchPort()) {
+				boolean moved = device.updateAttachmentPoint(entity.getSwitchDPID(),
+						entity.getSwitchPort(),
+						entity.getLastSeenTimestamp());
+				// TODO: use update mechanism instead of sending the
+				// notification directly
+				if (moved) {
+					// we count device moved events in sendDeviceMovedNotification()
+					sendDeviceMovedNotification(device);
+					if (logger.isTraceEnabled()) {
+						logger.trace("Device moved: attachment points {}," +
+								"entities {}", device.attachmentPoints,
+								device.entities);
+					}
+				} else {
+					if (logger.isTraceEnabled()) {
+						logger.trace("Device attachment point updated: " +
+								"attachment points {}," +
+								"entities {}", device.attachmentPoints,
+								device.entities);
+					}
+				}
+			}
+			break;
+		}
+
+		if (deleteQueue != null) {
+			for (Long l : deleteQueue) {
+				Device dev = deviceMap.get(l);
+				this.deleteDevice(dev);
+			}
+		}
+		processUpdates(deviceUpdates);
+		deviceSyncManager.storeDeviceThrottled(device);
+
+		return device;
+	}
+
+	protected boolean isEntityAllowed(Entity entity, IEntityClass entityClass) {
+		return true;
+	}
+
+
+
+
+
+	protected EnumSet<DeviceField> findChangedFields(Device device,
+			Entity newEntity) {
+		EnumSet<DeviceField> changedFields =
+				EnumSet.of(DeviceField.IPV4,
+						DeviceField.VLAN,
+						DeviceField.SWITCH);
+
+		if (newEntity.getIpv4Address() == null)
+			changedFields.remove(DeviceField.IPV4);
+		if (newEntity.getVlan() == null)
+			changedFields.remove(DeviceField.VLAN);
+		if (newEntity.getSwitchDPID() == null ||
+				newEntity.getSwitchPort() == null)
+			changedFields.remove(DeviceField.SWITCH);
+
+		if (changedFields.size() == 0) return changedFields;
+
+		for (Entity entity : device.getEntities()) {
+			if (newEntity.getIpv4Address() == null ||
+					(entity.getIpv4Address() != null &&
+					entity.getIpv4Address().equals(newEntity.getIpv4Address())))
+				changedFields.remove(DeviceField.IPV4);
+			if (newEntity.getVlan() == null ||
+					(entity.getVlan() != null &&
+					entity.getVlan().equals(newEntity.getVlan())))
+				changedFields.remove(DeviceField.VLAN);
+			if (newEntity.getSwitchDPID() == null ||
+					newEntity.getSwitchPort() == null ||
+					(entity.getSwitchDPID() != null &&
+					entity.getSwitchPort() != null &&
+					entity.getSwitchDPID().equals(newEntity.getSwitchDPID()) &&
+					entity.getSwitchPort().equals(newEntity.getSwitchPort())))
+				changedFields.remove(DeviceField.SWITCH);
+		}
+
+		return changedFields;
+	}
+
+	/**
+	 * Send update notifications to listeners
+	 * @param updates the updates to process.
+	 */
+	 protected void processUpdates(Queue<DeviceUpdate> updates) {
+		if (updates == null) return;
+		DeviceUpdate update = null;
+		while (null != (update = updates.poll())) {
+			if (logger.isTraceEnabled()) {
+				logger.trace("Dispatching device update: {}", update);
+			}
+			if (update.change == DeviceUpdate.Change.DELETE) {
+				deviceSyncManager.removeDevice(update.device);
+			} else {
+				deviceSyncManager.storeDevice(update.device);
+			}
+			List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
+			notifyListeners(listeners, update);
+		}
+	 }
+
+	 protected void notifyListeners(List<IDeviceListener> listeners, DeviceUpdate update) {
+		 if (listeners == null) {
+			 return;
+		 }
+		 for (IDeviceListener listener : listeners) {
+			 switch (update.change) {
+			 case ADD:
+				 listener.deviceAdded(update.device);
+				 break;
+			 case DELETE:
+				 listener.deviceRemoved(update.device);
+				 break;
+			 case CHANGE:
+				 for (DeviceField field : update.fieldsChanged) {
+					 switch (field) {
+					 case IPV4:
+						 listener.deviceIPV4AddrChanged(update.device);
+						 break;
+					 case SWITCH:
+					 case PORT:
+						 //listener.deviceMoved(update.device);
+						 break;
+					 case VLAN:
+						 listener.deviceVlanChanged(update.device);
+						 break;
+					 default:
+						 logger.debug("Unknown device field changed {}",
+								 update.fieldsChanged.toString());
+						 break;
+					 }
+				 }
+				 break;
+			 }
+		 }
+	 }
+
+	 /**
+	  * Check if the entity e has all the keyFields set. Returns false if not
+	  * @param e entity to check
+	  * @param keyFields the key fields to check e against
+	  * @return
+	  */
+	 protected boolean allKeyFieldsPresent(Entity e, EnumSet<DeviceField> keyFields) {
+		 for (DeviceField f : keyFields) {
+			 switch (f) {
+			 case MAC:
+				 // MAC address is always present
+				 break;
+			 case IPV4:
+				 if (e.ipv4Address == null) return false;
+				 break;
+			 case SWITCH:
+				 if (e.switchDPID == null) return false;
+				 break;
+			 case PORT:
+				 if (e.switchPort == null) return false;
+				 break;
+			 case VLAN:
+				 // FIXME: vlan==null is ambiguous: it can mean: not present
+				 // or untagged
+				 //if (e.vlan == null) return false;
+				 break;
+			 default:
+				 // we should never get here. unless somebody extended
+				 // DeviceFields
+				 throw new IllegalStateException();
+			 }
+		 }
+		 return true;
+	 }
+
+	 private LinkedList<DeviceUpdate> updateUpdates(LinkedList<DeviceUpdate> list, DeviceUpdate update) {
+		 if (update == null) return list;
+		 if (list == null)
+			 list = new LinkedList<DeviceUpdate>();
+		 list.add(update);
+
+		 return list;
+	 }
+
+	 /**
+	  * Get the secondary index for a class.  Will return null if the
+	  * secondary index was created concurrently in another thread.
+	  * @param clazz the class for the index
+	  * @return
+	  */
+	 private ClassState getClassState(IEntityClass clazz) {
+		 ClassState classState = classStateMap.get(clazz.getName());
+		 if (classState != null) return classState;
+
+		 classState = new ClassState(clazz);
+		 ClassState r = classStateMap.putIfAbsent(clazz.getName(), classState);
+		 if (r != null) {
+			 // concurrent add
+			 return r;
+		 }
+		 return classState;
+	 }
+
+	 /**
+	  * Update both the primary and class indices for the provided device.
+	  * If the update fails because of an concurrent update, will return false.
+	  * @param device the device to update
+	  * @param deviceKey the device key for the device
+	  * @return true if the update succeeded, false otherwise.
+	  */
+	 private boolean updateIndices(Device device, Long deviceKey) {
+		 if (!primaryIndex.updateIndex(device, deviceKey)) {
+			 return false;
+		 }
+		 IEntityClass entityClass = device.getEntityClass();
+		 ClassState classState = getClassState(entityClass);
+
+		 if (classState.classIndex != null) {
+			 if (!classState.classIndex.updateIndex(device,
+					 deviceKey))
+				 return false;
+		 }
+		 return true;
+	 }
+
+	 /**
+	  * Update the secondary indices for the given entity and associated
+	  * entity classes
+	  * @param entity the entity to update
+	  * @param entityClass the entity class for the entity
+	  * @param deviceKey the device key to set up
+	  */
+	 private void updateSecondaryIndices(Entity entity,
+			 IEntityClass entityClass,
+			 Long deviceKey) {
+		 for (DeviceIndex index : secondaryIndexMap.values()) {
+			 index.updateIndex(entity, deviceKey);
+		 }
+		 ClassState state = getClassState(entityClass);
+		 for (DeviceIndex index : state.secondaryIndexMap.values()) {
+			 index.updateIndex(entity, deviceKey);
+		 }
+	 }
+
+	 /**
+	  * Clean up expired entities/devices
+	  */
+	 protected void cleanupEntities () {
+		 cntCleanupEntitiesRuns.increment();
+
+		 Calendar c = Calendar.getInstance();
+		 c.add(Calendar.MILLISECOND, -ENTITY_TIMEOUT);
+		 Date cutoff = c.getTime();
+
+		 ArrayList<Entity> toRemove = new ArrayList<Entity>();
+		 ArrayList<Entity> toKeep = new ArrayList<Entity>();
+
+		 Iterator<Device> diter = deviceMap.values().iterator();
+		 LinkedList<DeviceUpdate> deviceUpdates =
+				 new LinkedList<DeviceUpdate>();
+
+		 while (diter.hasNext()) {
+			 Device d = diter.next();
+
+			 while (true) {
+				 deviceUpdates.clear();
+				 toRemove.clear();
+				 toKeep.clear();
+				 for (Entity e : d.getEntities()) {
+					 if (e.getLastSeenTimestamp() != null &&
+							 0 > e.getLastSeenTimestamp().compareTo(cutoff)) {
+						 // individual entity needs to be removed
+						 toRemove.add(e);
+					 } else {
+						 toKeep.add(e);
+					 }
+				 }
+				 if (toRemove.size() == 0) {
+					 break;
+				 }
+
+				 cntEntityRemovedTimeout.increment();
+				 for (Entity e : toRemove) {
+					 removeEntity(e, d.getEntityClass(), d.getDeviceKey(), toKeep);
+				 }
+
+				 if (toKeep.size() > 0) {
+					 Device newDevice = allocateDevice(d.getDeviceKey(),
+							 d.getDHCPClientName(),
+							 d.oldAPs,
+							 d.attachmentPoints,
+							 toKeep,
+							 d.getEntityClass());
+
+					 EnumSet<DeviceField> changedFields =
+							 EnumSet.noneOf(DeviceField.class);
+					 for (Entity e : toRemove) {
+						 changedFields.addAll(findChangedFields(newDevice, e));
+					 }
+					 DeviceUpdate update = null;
+					 if (changedFields.size() > 0) {
+						 update = new DeviceUpdate(d, CHANGE, changedFields);
+					 }
+
+					 if (!deviceMap.replace(newDevice.getDeviceKey(),
+							 d,
+							 newDevice)) {
+						 // concurrent modification; try again
+						 // need to use device that is the map now for the next
+						 // iteration
+						 d = deviceMap.get(d.getDeviceKey());
+								 if (null != d)
+									 continue;
+					 }
+					 if (update != null) {
+						 // need to count after all possibly continue stmts in
+						 // this branch
+						 cntDeviceChanged.increment();
+						 deviceUpdates.add(update);
+					 }
+				 } else {
+					 DeviceUpdate update = new DeviceUpdate(d, DELETE, null);
+					 if (!deviceMap.remove(d.getDeviceKey(), d)) {
+						 // concurrent modification; try again
+						 // need to use device that is the map now for the next
+						 // iteration
+						 d = deviceMap.get(d.getDeviceKey());
+						 if (null != d)
+							 continue;
+						 cntDeviceDeleted.increment();
+					 }
+					 deviceUpdates.add(update);
+				 }
+				 processUpdates(deviceUpdates);
+				 break;
+			 }
+		 }
+		 // Since cleanupEntities() is not called in the packet-in pipeline,
+		 // debugEvents need to be flushed explicitly
+		 debugEventService.flushEvents();
+	 }
+
+	 protected void removeEntity(Entity removed,
+			 IEntityClass entityClass,
+			 Long deviceKey,
+			 Collection<Entity> others) {
+		 // Don't count in this method. This method CAN BE called to clean-up
+		 // after concurrent device adds/updates and thus counting here
+		 // is misleading
+		 for (DeviceIndex index : secondaryIndexMap.values()) {
+			 index.removeEntityIfNeeded(removed, deviceKey, others);
+		 }
+		 ClassState classState = getClassState(entityClass);
+		 for (DeviceIndex index : classState.secondaryIndexMap.values()) {
+			 index.removeEntityIfNeeded(removed, deviceKey, others);
+		 }
+
+		 primaryIndex.removeEntityIfNeeded(removed, deviceKey, others);
+
+		 if (classState.classIndex != null) {
+			 classState.classIndex.removeEntityIfNeeded(removed,
+					 deviceKey,
+					 others);
+		 }
+	 }
+
+	 /**
+	  * method to delete a given device, remove all entities first and then
+	  * finally delete the device itself.
+	  * @param device
+	  */
+	 protected void deleteDevice(Device device) {
+		 // Don't count in this method. This method CAN BE called to clean-up
+		 // after concurrent device adds/updates and thus counting here
+		 // is misleading
+		 ArrayList<Entity> emptyToKeep = new ArrayList<Entity>();
+		 for (Entity entity : device.getEntities()) {
+			 this.removeEntity(entity, device.getEntityClass(),
+					 device.getDeviceKey(), emptyToKeep);
+		 }
+		 if (!deviceMap.remove(device.getDeviceKey(), device)) {
+			 if (logger.isDebugEnabled())
+				 logger.debug("device map does not have this device -" +
+						 device.toString());
+		 }
+	 }
+
+	 private EnumSet<DeviceField> getEntityKeys(MacAddress macAddress,
+			 VlanVid vlan,
+			 IPv4Address ipv4Address,
+			 DatapathId switchDPID,
+			 OFPort 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.
+		 EnumSet<DeviceField> keys = EnumSet.noneOf(DeviceField.class);
+		 if (macAddress != null) keys.add(DeviceField.MAC);
+		 if (vlan != null) keys.add(DeviceField.VLAN);
+		 if (ipv4Address != null) keys.add(DeviceField.IPV4);
+		 if (switchDPID != null) keys.add(DeviceField.SWITCH);
+		 if (switchPort != null) keys.add(DeviceField.PORT);
+		 return keys;
+	 }
+
+	 protected Iterator<Device> queryClassByEntity(IEntityClass clazz,
+			 EnumSet<DeviceField> keyFields,
+			 Entity entity) {
+		 ClassState classState = getClassState(clazz);
+		 DeviceIndex index = classState.secondaryIndexMap.get(keyFields);
+		 if (index == null) return Collections.<Device>emptySet().iterator();
+		 return new DeviceIndexInterator(this, index.queryByEntity(entity));
+	 }
+
+	 protected Device allocateDevice(Long deviceKey,
+			 Entity entity,
+			 IEntityClass entityClass) {
+		 return new Device(this, deviceKey, entity, entityClass);
+	 }
+
+	 // TODO: FIX THIS.
+	 protected Device allocateDevice(Long deviceKey,
+			 String dhcpClientName,
+			 List<AttachmentPoint> aps,
+			 List<AttachmentPoint> trueAPs,
+			 Collection<Entity> entities,
+			 IEntityClass entityClass) {
+		 return new Device(this, deviceKey, dhcpClientName, aps, trueAPs,
+				 entities, entityClass);
+	 }
+
+	 protected Device allocateDevice(Device device,
+			 Entity entity,
+			 int insertionpoint) {
+		 return new Device(device, entity, insertionpoint);
+	 }
+
+	 //not used
+	 protected Device allocateDevice(Device device, Set <Entity> entities) {
+		 List <AttachmentPoint> newPossibleAPs =
+				 new ArrayList<AttachmentPoint>();
+		 List <AttachmentPoint> newAPs =
+				 new ArrayList<AttachmentPoint>();
+		 for (Entity entity : entities) {
+			 if (entity.switchDPID != null && entity.switchPort != null) {
+				 AttachmentPoint aP =
+						 new AttachmentPoint(entity.switchDPID,
+								 entity.switchPort, new Date(0));
+				 newPossibleAPs.add(aP);
+			 }
+		 }
+		 if (device.attachmentPoints != null) {
+			 for (AttachmentPoint oldAP : device.attachmentPoints) {
+				 if (newPossibleAPs.contains(oldAP)) {
+					 newAPs.add(oldAP);
+				 }
+			 }
+		 }
+		 if (newAPs.isEmpty())
+			 newAPs = null;
+		 Device d = new Device(this, device.getDeviceKey(),
+				 device.getDHCPClientName(), newAPs, null,
+				 entities, device.getEntityClass());
+		 d.updateAttachmentPoint();
+		 return d;
+	 }
+
+	 // *********************
+	 // ITopologyListener
+	 // *********************
+
+	 /**
+	  * Topology listener method.
+	  */
+	 @Override
+	 public void topologyChanged(List<LDUpdate> updateList) {
+		 Iterator<Device> diter = deviceMap.values().iterator();
+		 if (updateList != null) {
+			 if (logger.isTraceEnabled()) {
+				 for(LDUpdate update: updateList) {
+					 logger.trace("Topo update: {}", update);
+				 }
+			 }
+		 }
+
+		 while (diter.hasNext()) {
+			 Device d = diter.next();
+			 if (d.updateAttachmentPoint()) {
+				 if (logger.isDebugEnabled()) {
+					 logger.debug("Attachment point changed for device: {}", d);
+				 }
+				 sendDeviceMovedNotification(d);
+			 }
+		 }
+		 // Since topologyChanged() does not occur in the packet-in pipeline,
+		 // debugEvents need to be flushed explicitly
+		 debugEventService.flushEvents();
+	 }
+
+	 /**
+	  * Send update notifications to listeners
+	  * @param updates the updates to process.
+	  */
+	 protected void sendDeviceMovedNotification(Device d) {
+		 cntDeviceMoved.increment();
+		 deviceSyncManager.storeDevice(d);
+		 List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
+		 if (listeners != null) {
+			 for (IDeviceListener listener : listeners) {
+				 listener.deviceMoved(d);
+			 }
+		 }
+	 }
+
+	 // *********************
+	 // IEntityClassListener
+	 // *********************
+
+	 @Override
+	 public void entityClassChanged (Set<String> entityClassNames) {
+		 /* iterate through the devices, reclassify the devices that belong
+		  * to these entity class names
+		  */
+		 Iterator<Device> diter = deviceMap.values().iterator();
+		 while (diter.hasNext()) {
+			 Device d = diter.next();
+			 if (d.getEntityClass() == null ||
+					 entityClassNames.contains(d.getEntityClass().getName()))
+				 reclassifyDevice(d);
+		 }
+	 }
+
+	 /**
+	  * this method will reclassify and reconcile a device - possibilities
+	  * are - create new device(s), remove entities from this device. If the
+	  * device entity class did not change then it returns false else true.
+	  * @param device
+	  */
+	 protected boolean reclassifyDevice(Device device)
+	 {
+		 // first classify all entities of this device
+		 if (device == null) {
+			 logger.debug("In reclassify for null device");
+			 return false;
+		 }
+		 boolean needToReclassify = false;
+		 for (Entity entity : device.entities) {
+			 IEntityClass entityClass =
+					 this.entityClassifier.classifyEntity(entity);
+			 if (entityClass == null || device.getEntityClass() == null) {
+				 needToReclassify = true;
+				 break;
+			 }
+			 if (!entityClass.getName().
+					 equals(device.getEntityClass().getName())) {
+				 needToReclassify = true;
+				 break;
+			 }
+		 }
+		 if (needToReclassify == false) {
+			 return false;
+		 }
+
+		 cntDeviceReclassifyDelete.increment();
+		 LinkedList<DeviceUpdate> deviceUpdates =
+				 new LinkedList<DeviceUpdate>();
+		 // delete this device and then re-learn all the entities
+		 this.deleteDevice(device);
+		 deviceUpdates.add(new DeviceUpdate(device,
+				 DeviceUpdate.Change.DELETE, null));
+		 if (!deviceUpdates.isEmpty())
+			 processUpdates(deviceUpdates);
+		 for (Entity entity: device.entities ) {
+			 this.learnDeviceByEntity(entity);
+		 }
+		 // Since reclassifyDevices() is not called in the packet-in pipeline,
+		 // debugEvents need to be flushed explicitly
+		 debugEventService.flushEvents();
+		 return true;
+	 }
+
+	 /**
+	  * For testing: sets the interval between writes of the same device
+	  * to the device store.
+	  * @param intervalMs
+	  */
+	 void setSyncStoreWriteInterval(int intervalMs) {
+		 this.syncStoreWriteIntervalMs = intervalMs;
+	 }
+
+	 /**
+	  * For testing: sets the time between transition to MASTER and
+	  * consolidate store
+	  * @param intervalMs
+	  */
+	 void setInitialSyncStoreConsolidateMs(int intervalMs) {
+		 this.initialSyncStoreConsolidateMs = intervalMs;
+	 }
+
+	 /**
+	  * For testing: consolidate the store NOW
+	  */
+	 void scheduleConsolidateStoreNow() {
+		 this.storeConsolidateTask.reschedule(0, TimeUnit.MILLISECONDS);
+	 }
+
+	 private class DeviceSyncManager  {
+		 // maps (opaque) deviceKey to the time in System.nanoTime() when we
+		 // last wrote the device to the sync store
+		 private final ConcurrentMap<Long, Long> lastWriteTimes = new ConcurrentHashMap<Long, Long>();
+
+		 /**
+		  * Write the given device to storage if we are MASTER.
+		  * Use this method if the device has significantly changed (e.g.,
+		  * new AP, new IP, entities removed).
+		  * @param d the device to store
+		  */
+		 public void storeDevice(Device d) {
+			 if (!isMaster)
+				 return;
+			 if (d == null)
+				 return;
+			 long now = System.nanoTime();
+			 writeUpdatedDeviceToStorage(d);
+			 lastWriteTimes.put(d.getDeviceKey(), now);
+		 }
+
+		 /**
+		  * Write the given device to storage if we are MASTER and if the
+		  * last write for the device was more than this.syncStoreIntervalNs
+		  * time ago.
+		  * Use this method to updated last active times in the store.
+		  * @param d the device to store
+		  */
+		 public void storeDeviceThrottled(Device d) {
+			 long intervalNs = syncStoreWriteIntervalMs*1000L*1000L;
+			 if (!isMaster)
+				 return;
+			 if (d == null)
+				 return;
+			 long now = System.nanoTime();
+			 Long last = lastWriteTimes.get(d.getDeviceKey());
+			 if (last == null || (now - last) > intervalNs) {
+				 writeUpdatedDeviceToStorage(d);
+				 lastWriteTimes.put(d.getDeviceKey(), now);
+			 } else {
+				 cntDeviceStoreThrottled.increment();
+			 }
+		 }
+
+		 /**
+		  * Remove the given device from the store. If only some entities have
+		  * been removed the updated device should be written using
+		  * {@link #storeDevice(Device)}
+		  * @param d
+		  */
+		 public void removeDevice(Device d) {
+			 if (!isMaster)
+				 return;
+			 // FIXME: could we have a problem with concurrent put to the
+			 // hashMap? I.e., we write a stale entry to the map after the
+			 // delete and now are left with an entry we'll never clean up
+			 lastWriteTimes.remove(d.getDeviceKey());
+			 try {
+				 // TODO: should probably do versioned delete. OTOH, even
+				 // if we accidentally delete, we'll write it again after
+				 // the next entity ....
+				 cntDeviceRemovedFromStore.increment();
+				 storeClient.delete(DeviceSyncRepresentation.computeKey(d));
+			 } catch(ObsoleteVersionException e) {
+				 // FIXME
+			 } catch (SyncException e) {
+				 cntSyncException.increment();
+				 logger.error("Could not remove device " + d + " from store", e);
+			 }
+		 }
+
+		 /**
+		  * Remove the given Versioned device from the store. If the device
+		  * was locally modified ignore the delete request.
+		  * @param syncedDeviceKey
+		  */
+		 private void removeDevice(Versioned<DeviceSyncRepresentation> dev) {
+			 try {
+				 cntDeviceRemovedFromStore.increment();
+				 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();
+				 logger.error("Failed to remove device entry for " +
+						 dev.toString() + " from store.", e);
+			 }
+		 }
+
+		 /**
+		  * Synchronously transition from SLAVE to MASTER. By iterating through
+		  * the store and learning all devices from the store
+		  */
+		 private void goToMaster() {
+			 if (logger.isDebugEnabled()) {
+				 logger.debug("Transitioning to MASTER role");
+			 }
+			 cntTransitionToMaster.increment();
+			 IClosableIterator<Map.Entry<String,Versioned<DeviceSyncRepresentation>>>
+			 iter = null;
+			 try {
+				 iter = storeClient.entries();
+			 } catch (SyncException e) {
+				 cntSyncException.increment();
+				 logger.error("Failed to read devices from sync store", e);
+				 return;
+			 }
+			 try {
+				 while(iter.hasNext()) {
+					 Versioned<DeviceSyncRepresentation> versionedDevice =
+							 iter.next().getValue();
+					 DeviceSyncRepresentation storedDevice =
+							 versionedDevice.getValue();
+					 if (storedDevice == null)
+						 continue;
+					 cntDevicesFromStore.increment();
+					 for(SyncEntity se: storedDevice.getEntities()) {
+						 learnDeviceByEntity(se.asEntity());
+					 }
+				 }
+			 } finally {
+				 if (iter != null)
+					 iter.close();
+			 }
+			 storeConsolidateTask.reschedule(initialSyncStoreConsolidateMs,
+					 TimeUnit.MILLISECONDS);
+		 }
+
+		 /**
+		  * Actually perform the write of the device to the store
+		  * FIXME: concurrent modification behavior
+		  * @param device The device to write
+		  */
+		 private void writeUpdatedDeviceToStorage(Device device) {
+			 try {
+				 cntDeviceStrored.increment();
+				 // FIXME: use a versioned put
+				 DeviceSyncRepresentation storeDevice = new DeviceSyncRepresentation(device);
+				 storeClient.put(storeDevice.getKey(), storeDevice);
+			 } catch (ObsoleteVersionException e) {
+				 // FIXME: what's the right behavior here. Can the store client
+				 // even throw this error?
+			 } catch (SyncException e) {
+				 cntSyncException.increment();
+				 logger.error("Could not write device " + device +
+						 " to sync store:", e);
+			 } catch (Exception e) {
+				 logger.error("Count not write device to sync storage " + e.getMessage());
+			 }
+		 }
+
+		 /**
+		  * Iterate through all entries in the sync store. For each device
+		  * in the store check if any stored entity matches a live device. If
+		  * no entities match a live device we remove the entry from the store.
+		  *
+		  * Note: we do not check if all devices known to device manager are
+		  * in the store. We rely on regular packetIns for that.
+		  * Note: it's possible that multiple entries in the store map to the
+		  * same device. We don't check or handle this case.
+		  *
+		  * We need to perform this check after a SLAVE->MASTER transition to
+		  * get rid of all entries the old master might have written to the
+		  * store after we took over. We also run it regularly in MASTER
+		  * state to ensure we don't have stale entries in the store
+		  */
+		 private void consolidateStore() {
+			 if (!isMaster)
+				 return;
+			 cntConsolidateStoreRuns.increment();
+			 if (logger.isDebugEnabled()) {
+				 logger.debug("Running consolidateStore.");
+			 }
+			 IClosableIterator<Map.Entry<String,Versioned<DeviceSyncRepresentation>>>
+			 iter = null;
+			 try {
+				 iter = storeClient.entries();
+			 } catch (SyncException e) {
+				 cntSyncException.increment();
+				 logger.error("Failed to read devices from sync store", e);
+				 return;
+			 }
+			 try {
+				 while(iter.hasNext()) {
+					 boolean found = false;
+					 Versioned<DeviceSyncRepresentation> versionedDevice =
+							 iter.next().getValue();
+					 DeviceSyncRepresentation storedDevice =
+							 versionedDevice.getValue();
+					 if (storedDevice == null)
+						 continue;
+					 for(SyncEntity se: storedDevice.getEntities()) {
+						 try {
+							 // Do we have a device for this entity??
+									 IDevice d = findDevice(se.macAddress, se.vlan,
+											 se.ipv4Address,
+											 se.switchDPID,
+											 se.switchPort);
+									 if (d != null) {
+										 found = true;
+										 break;
+									 }
+						 } catch (IllegalArgumentException e) {
+							 // not all key fields provided. Skip entity
+						 }
+					 }
+					 if (!found) {
+						 // We currently DO NOT have a live device that
+						 // matches the current device from the store.
+						 // Delete device from store.
+						 if (logger.isDebugEnabled()) {
+							 logger.debug("Removing device {} from store. No "
+									 + "corresponding live device",
+									 storedDevice.getKey());
+						 }
+						 cntConsolidateStoreDevicesRemoved.increment();
+						 removeDevice(versionedDevice);
+					 }
+				 }
+			 } finally {
+				 if (iter != null)
+					 iter.close();
+			 }
+		 }
+	 }
+
+
+	 /**
+	  * For testing. Sets the syncService. Only call after init but before
+	  * startUp. Used by MockDeviceManager
+	  * @param syncService
+	  */
+	 protected void setSyncServiceIfNotSet(ISyncService syncService) {
+		 if (this.syncService == null)
+			 this.syncService = syncService;
+	 }
+
+	 /**
+	  * For testing.
+	  * @return
+	  */
+	 IHAListener getHAListener() {
+		 return this.haListenerDelegate;
+	 }
+
+	 /**
+	  * Device Event Class used to log Device related events
+	  */
+	 private class DeviceEvent {
+		 @EventColumn(name = "MAC", description = EventFieldType.MAC)
+		 private final MacAddress macAddress;
+		 @EventColumn(name = "IPs", description = EventFieldType.IPv4)
+		 private final List<IPv4Address> ipv4Addresses;
+		 @EventColumn(name = "Old Attachment Points",
+				 description = EventFieldType.COLLECTION_ATTACHMENT_POINT)
+		 private final List<SwitchPort> oldAttachmentPoints;
+		 @EventColumn(name = "Current Attachment Points",
+				 description = EventFieldType.COLLECTION_ATTACHMENT_POINT)
+		 private final List<SwitchPort> currentAttachmentPoints;
+		 @EventColumn(name = "VLAN IDs", description = EventFieldType.COLLECTION_OBJECT)
+		 private final List<VlanVid> vlanIds;
+		 @EventColumn(name = "Reason", description = EventFieldType.STRING)
+		 private final String reason;
+
+		 public DeviceEvent(MacAddress macAddress, List<IPv4Address> ipv4Addresses,
+				 List<SwitchPort> oldAttachmentPoints,
+				 List<SwitchPort> currentAttachmentPoints,
+				 List<VlanVid> vlanIds, String reason) {
+			 super();
+			 this.macAddress = macAddress;
+			 this.ipv4Addresses = ipv4Addresses;
+			 this.oldAttachmentPoints = oldAttachmentPoints;
+			 this.currentAttachmentPoints = currentAttachmentPoints;
+			 this.vlanIds = vlanIds;
+			 this.reason = reason;
+		 }
+	 }
 }
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java
index c6aa9808e78a598c350ad388a7f5c06711ee8436..df47d32b2558df200cf8f02154cbde6444411ff4 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceMultiIndex.java
@@ -74,11 +74,11 @@ public class DeviceMultiIndex extends DeviceIndex {
     }
     
     @Override
-    public void updateIndex(Entity entity, Long deviceKey) {
+    public boolean updateIndex(Entity entity, Long deviceKey) {
         Collection<Long> devices = null;
 
         IndexedEntity ie = new IndexedEntity(keyFields, entity);
-        if (!ie.hasNonNullKeys()) return;
+        if (!ie.hasNonNullKeys()) return false;
 
         devices = index.get(ie);
         if (devices == null) {
@@ -90,6 +90,7 @@ public class DeviceMultiIndex extends DeviceIndex {
         }
         
         devices.add(deviceKey);
+        return true;
     }
 
     @Override
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java
index 42bfb01321cfc704d9578672630893bff31d4e0e..b1c395d4c9664553550685125f686bdf87508283 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceSyncRepresentation.java
@@ -6,9 +6,14 @@ 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;
@@ -16,15 +21,15 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class DeviceSyncRepresentation {
     public static class SyncEntity implements Comparable<SyncEntity> {
         @JsonProperty
-        public long macAddress;
+        public MacAddress macAddress;
         @JsonProperty
-        public Integer ipv4Address;
+        public IPv4Address ipv4Address;
         @JsonProperty
-        public Short vlan;
+        public VlanVid vlan;
         @JsonProperty
-        public Long switchDPID;
+        public DatapathId switchDPID;
         @JsonProperty
-        public Integer switchPort;
+        public OFPort switchPort;
         @JsonProperty
         public Date lastSeenTimestamp;
         @JsonProperty
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java
index 4811013e77258654c9577b0271a51f72c31bfd8d..e373018bff2bc02a02a41384ae58daadaf45cb0b 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceUniqueIndex.java
@@ -78,10 +78,11 @@ public class DeviceUniqueIndex extends DeviceIndex {
     }
 
     @Override
-    public void updateIndex(Entity entity, Long deviceKey) {
+    public boolean updateIndex(Entity entity, Long deviceKey) {
         IndexedEntity ie = new IndexedEntity(keyFields, entity);
-        if (!ie.hasNonNullKeys()) return;
+        if (!ie.hasNonNullKeys()) return false;
         index.put(ie, deviceKey);
+        return true;
     }
 
     @Override
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
index db8d8e9fb3ff92256e0e9db55751e9345e6765fa..eda51cc1d45e5d1f713bb9a301d770a962ad2fdc 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
@@ -22,11 +22,15 @@ 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.openflow.util.HexString;
+
+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;
 
 /**
  * An entity on the network is a visible trace of a device that corresponds
@@ -52,30 +56,30 @@ public class Entity implements Comparable<Entity> {
     /**
      * The MAC address associated with this entity
      */
-    protected long macAddress;
+    protected MacAddress macAddress;
     
     /**
      * The IP address associated with this entity, or null if no IP learned
      * from the network observation associated with this entity
      */
-    protected Integer ipv4Address;
+    protected IPv4Address ipv4Address;
     
     /**
      * The VLAN tag on this entity, or null if untagged
      */
-    protected Short vlan;
+    protected VlanVid vlan;
     
     /**
      * The DPID of the switch for the ingress point for this entity,
      * or null if not present
      */
-    protected Long switchDPID;
+    protected DatapathId switchDPID;
     
     /**
      * The port number of the switch for the ingress point for this entity,
      * or null if not present
      */
-    protected Integer switchPort;
+    protected OFPort switchPort;
     
     /**
      * The last time we observed this entity on the network
@@ -108,8 +112,8 @@ public class Entity implements Comparable<Entity> {
      * @param switchPort
      * @param lastSeenTimestamp
      */
-    public Entity(long macAddress, Short vlan, 
-                  Integer ipv4Address, Long switchDPID, Integer switchPort, 
+    public Entity(MacAddress macAddress, VlanVid vlan, 
+                  IPv4Address ipv4Address, DatapathId switchDPID, OFPort switchPort, 
                   Date lastSeenTimestamp) {
         this.macAddress = macAddress;
         this.ipv4Address = ipv4Address;
@@ -125,25 +129,25 @@ public class Entity implements Comparable<Entity> {
     // ***************
 
     @JsonSerialize(using=MACSerializer.class)
-    public long getMacAddress() {
+    public MacAddress getMacAddress() {
         return macAddress;
     }
 
     @JsonSerialize(using=IPv4Serializer.class)
-    public Integer getIpv4Address() {
+    public IPv4Address getIpv4Address() {
         return ipv4Address;
     }
 
-    public Short getVlan() {
+    public VlanVid getVlan() {
         return vlan;
     }
 
     @JsonSerialize(using=DPIDSerializer.class)
-    public Long getSwitchDPID() {
+    public DatapathId getSwitchDPID() {
         return switchDPID;
     }
 
-    public Integer getSwitchPort() {
+    public OFPort getSwitchPort() {
         return switchPort;
     }
     
@@ -163,9 +167,7 @@ public class Entity implements Comparable<Entity> {
      * @see {@link Entity#activeSince}
      */
     public void setLastSeenTimestamp(Date lastSeenTimestamp) {
-        if (activeSince == null ||
-            (activeSince.getTime() +  ACTIVITY_TIMEOUT) <
-                lastSeenTimestamp.getTime())
+        if (activeSince == null || (activeSince.getTime() + ACTIVITY_TIMEOUT) < lastSeenTimestamp.getTime())
             this.activeSince = lastSeenTimestamp;
         this.lastSeenTimestamp = lastSeenTimestamp;
     }
@@ -185,7 +187,7 @@ public class Entity implements Comparable<Entity> {
         hashCode = 1;
         hashCode = prime * hashCode
                  + ((ipv4Address == null) ? 0 : ipv4Address.hashCode());
-        hashCode = prime * hashCode + (int) (macAddress ^ (macAddress >>> 32));
+        hashCode = prime * hashCode + (int) (macAddress.getLong() ^ (macAddress.getLong() >>> 32));
         hashCode = prime * hashCode
                  + ((switchDPID == null) ? 0 : switchDPID.hashCode());
         hashCode = prime * hashCode
@@ -204,7 +206,7 @@ public class Entity implements Comparable<Entity> {
         if (ipv4Address == null) {
             if (other.ipv4Address != null) return false;
         } else if (!ipv4Address.equals(other.ipv4Address)) return false;
-        if (macAddress != other.macAddress) return false;
+        if (!macAddress.equals(other.macAddress)) return false;
         if (switchDPID == null) {
             if (other.switchDPID != null) return false;
         } else if (!switchDPID.equals(other.switchDPID)) return false;
@@ -223,28 +225,55 @@ public class Entity implements Comparable<Entity> {
     public String toString() {
         StringBuilder builder = new StringBuilder();
         builder.append("Entity [macAddress=");
-        builder.append(HexString.toHexString(macAddress, 6));
+        if (macAddress != null) {
+        	builder.append(macAddress.toString());
+        } else {
+        	builder.append("null");
+        }
         builder.append(", ipv4Address=");
-        builder.append(IPv4.fromIPv4Address(ipv4Address==null ?
-                       0 : ipv4Address.intValue()));
+        if (ipv4Address != null) {
+        	builder.append(ipv4Address.toString());
+        } else {
+        	builder.append("null");
+        }
         builder.append(", vlan=");
-        builder.append(vlan);
+        if (vlan != null) {
+        	builder.append(vlan.getVlan());
+        } else {
+        	builder.append("null");
+        }
         builder.append(", switchDPID=");
-        builder.append(switchDPID);
+        if (switchDPID != null) {
+        	builder.append(switchDPID.toString());
+        } else {
+        	builder.append("null");
+        }
         builder.append(", switchPort=");
-        builder.append(switchPort);
+        if (switchPort != null) {
+        	builder.append(switchPort.getPortNumber());
+        } else {
+        	builder.append("null");
+        }
         builder.append(", lastSeenTimestamp=");
-        builder.append(lastSeenTimestamp == null? "null" : lastSeenTimestamp.getTime());
+        if (lastSeenTimestamp != null) {
+        	builder.append(lastSeenTimestamp == null? "null" : lastSeenTimestamp.getTime());
+        } else {
+        	builder.append("null");
+        }
         builder.append(", activeSince=");
-        builder.append(activeSince == null? "null" : activeSince.getTime());
+        if (activeSince != null) {
+        	builder.append(activeSince == null? "null" : activeSince.getTime());
+        } else {
+        	builder.append("null");
+        }
         builder.append("]");
         return builder.toString();
     }
 
     @Override
     public int compareTo(Entity o) {
-        if (macAddress < o.macAddress) return -1;
-        if (macAddress > o.macAddress) return 1;
+        if (macAddress.getLong() < o.macAddress.getLong()) return -1;
+        if (macAddress.getLong() > o.macAddress.getLong()) 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 13a78a49accfa001c51fb3260325179abc362a46..6fb1dda1305e4e35e86cf95131a2edf17f843895 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 ^ 
-                                (entity.macAddress >>> 32));
+                        + (int) (entity.macAddress.getLong() ^ 
+                                (entity.macAddress.getLong() >>> 32));
                     break;
                 case IPV4:
                     hashCode = prime * hashCode
@@ -134,32 +134,28 @@ public class IndexedEntity {
         for (IDeviceService.DeviceField f : keyFields) {
             switch (f) {
                 case MAC:
-                    if (entity.macAddress != other.entity.macAddress)
+                    if (!entity.macAddress.equals(other.entity.macAddress))
                         return false;
                     break;
                 case IPV4:
                     if (entity.ipv4Address == null) {
                         if (other.entity.ipv4Address != null) return false;
-                    } else if (!entity.ipv4Address.
-                            equals(other.entity.ipv4Address)) return false;
+                    } else if (!entity.ipv4Address.equals(other.entity.ipv4Address)) return false;
                     break;
                 case SWITCH:
                     if (entity.switchDPID == null) {
                         if (other.entity.switchDPID != null) return false;
-                    } else if (!entity.switchDPID.
-                            equals(other.entity.switchDPID)) return false;
+                    } else if (!entity.switchDPID.equals(other.entity.switchDPID)) return false;
                     break;
                 case PORT:
                     if (entity.switchPort == null) {
                         if (other.entity.switchPort != null) return false;
-                    } else if (!entity.switchPort.
-                            equals(other.entity.switchPort)) return false;
+                    } else if (!entity.switchPort.equals(other.entity.switchPort)) return false;
                     break;
                 case VLAN:
                     if (entity.vlan == null) {
                         if (other.entity.vlan != null) return false;
-                    } else if (!entity.vlan.
-                            equals(other.entity.vlan)) return false;
+                    } else if (!entity.vlan.equals(other.entity.vlan)) return false;
                     break;
             }
         }
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java b/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java
index 7866b7914a57f0e7e91f6e2b2283a12c3df64d46..512e4912babe760a3dbf44049465fd4424f0e96e 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/web/AbstractDeviceResource.java
@@ -23,10 +23,13 @@ import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.devicemanager.internal.Device;
-import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.util.FilterIterator;
 
-import org.openflow.util.HexString;
+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.restlet.data.Form;
 import org.restlet.data.Status;
 import org.restlet.resource.ServerResource;
@@ -54,11 +57,11 @@ public abstract class AbstractDeviceResource extends ServerResource {
                 (IDeviceService)getContext().getAttributes().
                     get(IDeviceService.class.getCanonicalName());  
                 
-        Long macAddress = null;
-        Short vlan = null;
-        Integer ipv4Address = null;
-        Long switchDPID = null;
-        Integer switchPort = null;
+        MacAddress macAddress = null;
+        VlanVid vlan = null;
+        IPv4Address ipv4Address = null;
+        DatapathId switchDPID = null;
+        OFPort switchPort = null;
         
         Form form = getQuery();
         String macAddrStr = form.getFirstValue("mac", true);
@@ -69,7 +72,7 @@ public abstract class AbstractDeviceResource extends ServerResource {
         
         if (macAddrStr != null) {
             try {
-                macAddress = HexString.toLong(macAddrStr);
+                macAddress = MacAddress.of(macAddrStr);
             } catch (Exception e) {
                 setStatus(Status.CLIENT_ERROR_BAD_REQUEST, MAC_ERROR);
                 return null;
@@ -77,8 +80,8 @@ public abstract class AbstractDeviceResource extends ServerResource {
         }
         if (vlanStr != null) {
             try {
-                vlan = Short.parseShort(vlanStr);
-                if (vlan > 4095 || vlan < 0) {
+                vlan = VlanVid.ofVlan(Integer.parseInt(vlanStr));
+                if (vlan.getVlan() > 4095 || vlan.getVlan() < 0) {
                     setStatus(Status.CLIENT_ERROR_BAD_REQUEST, VLAN_ERROR);
                     return null;
                 }
@@ -89,7 +92,7 @@ public abstract class AbstractDeviceResource extends ServerResource {
         }
         if (ipv4Str != null) {
             try {
-                ipv4Address = IPv4.toIPv4Address(ipv4Str);
+                ipv4Address = IPv4Address.of(ipv4Str);
             } catch (Exception e) {
                 setStatus(Status.CLIENT_ERROR_BAD_REQUEST, IPV4_ERROR);
                 return null;
@@ -97,7 +100,7 @@ public abstract class AbstractDeviceResource extends ServerResource {
         }
         if (dpid != null) {
             try {
-                switchDPID = HexString.toLong(dpid);
+                switchDPID = DatapathId.of(dpid);
             } catch (Exception e) {
                 setStatus(Status.CLIENT_ERROR_BAD_REQUEST, DPID_ERROR);
                 return null;
@@ -105,8 +108,8 @@ public abstract class AbstractDeviceResource extends ServerResource {
         }
         if (port != null) {
             try {
-                switchPort = Integer.parseInt(port);
-                if (switchPort < 0) {
+                switchPort = OFPort.of(Integer.parseInt(port));
+                if (switchPort.getPortNumber() < 0) {
                     setStatus(Status.CLIENT_ERROR_BAD_REQUEST, PORT_ERROR);
                     return null;
                 }
@@ -144,7 +147,7 @@ public abstract class AbstractDeviceResource extends ServerResource {
                 }
                 if (vlanStartsWith != null) {
                     boolean match = false;
-                    for (Short v : value.getVlanId()) {
+                    for (VlanVid v : value.getVlanId()) {
                         if (v != null && 
                             v.toString().startsWith(vlanStartsWith)) {
                             match = true;
@@ -155,10 +158,10 @@ public abstract class AbstractDeviceResource extends ServerResource {
                 }
                 if (ipv4StartsWith != null) {
                     boolean match = false;
-                    for (Integer v : value.getIPv4Addresses()) {
+                    for (IPv4Address v : value.getIPv4Addresses()) {
                         String str;
                         if (v != null && 
-                            (str = IPv4.fromIPv4Address(v)) != null &&
+                            (str = v.toString()) != null &&
                             str.startsWith(ipv4StartsWith)) {
                             match = true;
                             break;
@@ -171,8 +174,7 @@ public abstract class AbstractDeviceResource extends ServerResource {
                     for (SwitchPort v : value.getAttachmentPoints(true)) {
                         String str;
                         if (v != null && 
-                            (str = HexString.toHexString(v.getSwitchDPID(), 
-                                                         8)) != null &&
+                            (str = v.getSwitchDPID().toString()) != null &&
                             str.startsWith(dpidStartsWith)) {
                             match = true;
                             break;
@@ -185,7 +187,7 @@ public abstract class AbstractDeviceResource extends ServerResource {
                     for (SwitchPort v : value.getAttachmentPoints(true)) {
                         String str;
                         if (v != null && 
-                            (str = Integer.toString(v.getPort())) != null &&
+                            (str = v.getPort().toString()) != null &&
                             str.startsWith(portStartsWith)) {
                             match = true;
                             break;
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java
index 26b2027aaa34ece55d1541a3f60bb058d27e74e3..0cd43e245ac822fcb46a88cbf5d8cf59c3a29d0f 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceSerializer.java
@@ -19,15 +19,16 @@ package net.floodlightcontroller.devicemanager.web;
 
 import java.io.IOException;
 
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.VlanVid;
+
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.devicemanager.internal.Device;
-import net.floodlightcontroller.packet.IPv4;
 
 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 device object
@@ -43,18 +44,18 @@ public class DeviceSerializer extends JsonSerializer<Device> {
         jGen.writeStringField("entityClass", device.getEntityClass().getName());
         
         jGen.writeArrayFieldStart("mac");
-        jGen.writeString(HexString.toHexString(device.getMACAddress(), 6));
+        jGen.writeString(device.getMACAddress().toString());
         jGen.writeEndArray();
 
         jGen.writeArrayFieldStart("ipv4");
-        for (Integer ip : device.getIPv4Addresses())
-            jGen.writeString(IPv4.fromIPv4Address(ip));
+        for (IPv4Address ip : device.getIPv4Addresses())
+            jGen.writeString(ip.toString());
         jGen.writeEndArray();
 
         jGen.writeArrayFieldStart("vlan");
-        for (Short vlan : device.getVlanId())
-            if (vlan >= 0)
-                jGen.writeNumber(vlan);
+        for (VlanVid vlan : device.getVlanId())
+            if (vlan.getVlan() >= 0)
+                jGen.writeNumber(vlan.toString());
         jGen.writeEndArray();
         jGen.writeArrayFieldStart("attachmentPoint");
         for (SwitchPort ap : device.getAttachmentPoints(true)) {
diff --git a/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java b/src/main/java/net/floodlightcontroller/firewall/AllowDropPair.java
similarity index 75%
rename from src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java
rename to src/main/java/net/floodlightcontroller/firewall/AllowDropPair.java
index db4cf7441a11de5931a7b9b2db4205a9d66c54e6..719e067b9633eb4145dafb23ee1d725c424bd9bc 100644
--- a/src/main/java/net/floodlightcontroller/firewall/WildcardsPair.java
+++ b/src/main/java/net/floodlightcontroller/firewall/AllowDropPair.java
@@ -17,9 +17,12 @@
 
 package net.floodlightcontroller.firewall;
 
-import org.openflow.protocol.OFMatch;
+import org.projectfloodlight.openflow.protocol.match.Match;
 
-public class WildcardsPair {
-    public int allow = OFMatch.OFPFW_ALL;
-    public int drop = OFMatch.OFPFW_ALL;
+
+public class AllowDropPair {
+    //public int allow = OFMatch.OFPFW_ALL;
+    //public int drop = OFMatch.OFPFW_ALL;
+    public Match.Builder allow;
+    public Match.Builder drop;
 }
diff --git a/src/main/java/net/floodlightcontroller/firewall/Firewall.java b/src/main/java/net/floodlightcontroller/firewall/Firewall.java
index 21dc8aed6ca937f3123e9a00971ee8b0fc13fd80..e95a7d4e47b10fd662b414f62ae2c2d61d0cb843 100644
--- a/src/main/java/net/floodlightcontroller/firewall/Firewall.java
+++ b/src/main/java/net/floodlightcontroller/firewall/Firewall.java
@@ -24,9 +24,16 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFType;
+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 net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IOFMessageListener;
@@ -35,11 +42,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;
@@ -88,15 +95,15 @@ public class Firewall implements IFirewallService, IOFMessageListener,
     public static final String COLUMN_TP_SRC = "tp_src";
     public static final String COLUMN_TP_DST = "tp_dst";
     public static final String COLUMN_WILDCARD_DPID = "wildcard_dpid";
-    public static final String COLUMN_WILDCARD_IN_PORT = "wildcard_in_port";
-    public static final String COLUMN_WILDCARD_DL_SRC = "wildcard_dl_src";
-    public static final String COLUMN_WILDCARD_DL_DST = "wildcard_dl_dst";
-    public static final String COLUMN_WILDCARD_DL_TYPE = "wildcard_dl_type";
-    public static final String COLUMN_WILDCARD_NW_SRC = "wildcard_nw_src";
-    public static final String COLUMN_WILDCARD_NW_DST = "wildcard_nw_dst";
-    public static final String COLUMN_WILDCARD_NW_PROTO = "wildcard_nw_proto";
-    public static final String COLUMN_WILDCARD_TP_SRC = "wildcard_tp_src";
-    public static final String COLUMN_WILDCARD_TP_DST = "wildcard_tp_dst";
+    public static final String COLUMN_WILDCARD_IN_PORT = "any_in_port";
+    public static final String COLUMN_WILDCARD_DL_SRC = "any_dl_src";
+    public static final String COLUMN_WILDCARD_DL_DST = "any_dl_dst";
+    public static final String COLUMN_WILDCARD_DL_TYPE = "any_dl_type";
+    public static final String COLUMN_WILDCARD_NW_SRC = "any_nw_src";
+    public static final String COLUMN_WILDCARD_NW_DST = "any_nw_dst";
+    public static final String COLUMN_WILDCARD_NW_PROTO = "any_nw_proto";
+    public static final String COLUMN_WILDCARD_TP_SRC = "any_tp_src";
+    public static final String COLUMN_WILDCARD_TP_DST = "any_tp_dst";
     public static final String COLUMN_PRIORITY = "priority";
     public static final String COLUMN_ACTION = "action";
     public static String ColumnNames[] = { COLUMN_RULEID, COLUMN_DPID,
@@ -166,161 +173,86 @@ public class Firewall implements IFirewallService, IOFMessageListener,
             Map<String, Object> row;
 
             // (..., null, null) for no predicate, no ordering
-            IResultSet resultSet = storageSource.executeQuery(TABLE_NAME,
-                    ColumnNames, null, null);
+            IResultSet resultSet = storageSource.executeQuery(TABLE_NAME, ColumnNames, null, null);
 
             // put retrieved rows into FirewallRules
             for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
                 row = it.next().getRow();
                 // now, parse row
                 FirewallRule r = new FirewallRule();
-                if (!row.containsKey(COLUMN_RULEID)
-                        || !row.containsKey(COLUMN_DPID)) {
-                    logger.error(
-                            "skipping entry with missing required 'ruleid' or 'switchid' entry: {}",
-                            row);
+                if (!row.containsKey(COLUMN_RULEID) || !row.containsKey(COLUMN_DPID)) {
+                    logger.error( "skipping entry with missing required 'ruleid' or 'switchid' entry: {}", row);
                     return l;
                 }
                 try {
                     r.ruleid = Integer
                             .parseInt((String) row.get(COLUMN_RULEID));
-                    r.dpid = Long.parseLong((String) row.get(COLUMN_DPID));
+                    r.dpid = DatapathId.of((String) row.get(COLUMN_DPID));
 
                     for (String key : row.keySet()) {
-                        if (row.get(key) == null)
+                        if (row.get(key) == null) {
                             continue;
-                        if (key.equals(COLUMN_RULEID)
-                                || key.equals(COLUMN_DPID)
-                                || key.equals("id")) {
+                        }
+                        if (key.equals(COLUMN_RULEID) || key.equals(COLUMN_DPID) || key.equals("id")) {
                             continue; // already handled
-                        } 
-                        
-                        else if (key.equals(COLUMN_IN_PORT)) {
-                            r.in_port = Short.parseShort((String) row
-                                    .get(COLUMN_IN_PORT));
-                        } 
-                        
-                        else if (key.equals(COLUMN_DL_SRC)) {
-                            r.dl_src = Long.parseLong((String) row
-                                    .get(COLUMN_DL_SRC));
-                        } 
-                        
-                        else if (key.equals(COLUMN_DL_DST)) {
-                            r.dl_dst = Long.parseLong((String) row
-                                    .get(COLUMN_DL_DST));
-                        } 
-                        
-                        else if (key.equals(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 = Integer.parseInt((String) row
-                                    .get(COLUMN_NW_SRC_PREFIX));
-                        } 
-                        
-                        else if (key.equals(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 = Integer.parseInt((String) row
-                                    .get(COLUMN_NW_DST_PREFIX));
-                        } 
-                        
-                        else if (key.equals(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 = Short.parseShort((String) row
-                                    .get(COLUMN_NW_PROTO));
-                        } 
-                        
-                        else if (key.equals(COLUMN_TP_SRC)) {
-                            r.tp_src = Short.parseShort((String) row
-                                    .get(COLUMN_TP_SRC));
-                        } 
-                        
-                        else if (key.equals(COLUMN_TP_DST)) {
-                            r.tp_dst = Short.parseShort((String) row
-                                    .get(COLUMN_TP_DST));
-                        } 
-                        
-                        else if (key.equals(COLUMN_WILDCARD_DPID)) {
-                            r.wildcard_dpid = Boolean.parseBoolean((String) row
-                                    .get(COLUMN_WILDCARD_DPID));
-                        } 
-                        
-                        else if (key.equals(COLUMN_WILDCARD_IN_PORT)) {
-                            r.wildcard_in_port = Boolean
-                                    .parseBoolean((String) row
-                                            .get(COLUMN_WILDCARD_IN_PORT));
-                        } 
-                        
-                        else if (key.equals(COLUMN_WILDCARD_DL_SRC)) {
-                            r.wildcard_dl_src = Boolean
-                                    .parseBoolean((String) row
-                                            .get(COLUMN_WILDCARD_DL_SRC));
-                        } 
-                        
-                        else if (key.equals(COLUMN_WILDCARD_DL_DST)) {
-                            r.wildcard_dl_dst = Boolean
-                                    .parseBoolean((String) row
-                                            .get(COLUMN_WILDCARD_DL_DST));
-                        } 
-                        
-                        else if (key.equals(COLUMN_WILDCARD_DL_TYPE)) {
-                            r.wildcard_dl_type = Boolean
-                                    .parseBoolean((String) row
-                                            .get(COLUMN_WILDCARD_DL_TYPE));
-                        } 
-                        
-                        else if (key.equals(COLUMN_WILDCARD_NW_SRC)) {
-                            r.wildcard_nw_src = Boolean
-                                    .parseBoolean((String) row
-                                            .get(COLUMN_WILDCARD_NW_SRC));
-                        } 
-                        
-                        else if (key.equals(COLUMN_WILDCARD_NW_DST)) {
-                            r.wildcard_nw_dst = Boolean
-                                    .parseBoolean((String) row
-                                            .get(COLUMN_WILDCARD_NW_DST));
-                        } 
-                        
-                        else if (key.equals(COLUMN_WILDCARD_NW_PROTO)) {
-                            r.wildcard_nw_proto = Boolean
-                                    .parseBoolean((String) row
-                                            .get(COLUMN_WILDCARD_NW_PROTO));
-                        } 
-                        
-                        else if (key.equals(COLUMN_PRIORITY)) {
-                            r.priority = Integer.parseInt((String) row
-                                    .get(COLUMN_PRIORITY));
-                        } 
-                        
-                        else if (key.equals(COLUMN_ACTION)) {
+                        } else if (key.equals(COLUMN_IN_PORT)) {
+                            r.in_port = OFPort.of(Integer.parseInt((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)));
+                        }  else if (key.equals(COLUMN_DL_DST)) {
+                            r.dl_dst = MacAddress.of(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)));
+                        } 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());
+                        } 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)));
+                        } 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());
+                        } 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)));
+                        } else if (key.equals(COLUMN_NW_PROTO)) {
+                            r.nw_proto = IpProtocol.of(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)));
+                        } else if (key.equals(COLUMN_TP_DST)) {
+                            r.tp_dst = TransportPort.of(Integer.parseInt((String) row.get(COLUMN_TP_DST)));
+                        } else if (key.equals(COLUMN_WILDCARD_DPID)) {
+                            r.any_dpid = Boolean.parseBoolean((String) row.get(COLUMN_WILDCARD_DPID));
+                        } else if (key.equals(COLUMN_WILDCARD_IN_PORT)) {
+                            r.any_in_port = Boolean.parseBoolean((String) row.get(COLUMN_WILDCARD_IN_PORT));
+                        } else if (key.equals(COLUMN_WILDCARD_DL_SRC)) {
+                            r.any_dl_src = Boolean.parseBoolean((String) row.get(COLUMN_WILDCARD_DL_SRC));
+                        } else if (key.equals(COLUMN_WILDCARD_DL_DST)) {
+                            r.any_dl_dst = Boolean.parseBoolean((String) row.get(COLUMN_WILDCARD_DL_DST));
+                        } else if (key.equals(COLUMN_WILDCARD_DL_TYPE)) {
+                            r.any_dl_type = Boolean.parseBoolean((String) row.get(COLUMN_WILDCARD_DL_TYPE));
+                        } else if (key.equals(COLUMN_WILDCARD_NW_SRC)) {
+                            r.any_nw_src = Boolean.parseBoolean((String) row.get(COLUMN_WILDCARD_NW_SRC));
+                        } else if (key.equals(COLUMN_WILDCARD_NW_DST)) {
+                            r.any_nw_dst = Boolean.parseBoolean((String) row.get(COLUMN_WILDCARD_NW_DST));
+                        } else if (key.equals(COLUMN_WILDCARD_NW_PROTO)) {
+                            r.any_nw_proto = Boolean.parseBoolean((String) row.get(COLUMN_WILDCARD_NW_PROTO));
+                        } else if (key.equals(COLUMN_PRIORITY)) {
+                            r.priority = Integer.parseInt((String) row.get(COLUMN_PRIORITY));
+                        } else if (key.equals(COLUMN_ACTION)) {
                             int tmp = Integer.parseInt((String) row.get(COLUMN_ACTION));
-                            if (tmp == FirewallRule.FirewallAction.DENY.ordinal())
-                                r.action = FirewallRule.FirewallAction.DENY;
-                            else if (tmp == FirewallRule.FirewallAction.ALLOW.ordinal())
+                            if (tmp == FirewallRule.FirewallAction.DROP.ordinal()) {
+                                r.action = FirewallRule.FirewallAction.DROP;
+                            } else if (tmp == FirewallRule.FirewallAction.ALLOW.ordinal()) {
                                 r.action = FirewallRule.FirewallAction.ALLOW;
-                            else {
+                            } else {
                                 r.action = null;
                                 logger.error("action not recognized");
                             }
                         }
                     }
                 } catch (ClassCastException e) {
-                    logger.error(
-                            "skipping rule {} with bad data : "
-                                    + e.getMessage(), r.ruleid);
+                    logger.error("skipping rule {} with bad data : " + e.getMessage(), r.ruleid);
                 }
-                if (r.action != null)
+                if (r.action != null) {
                     l.add(r);
+                }
             }
         } catch (StorageException e) {
             logger.error("failed to access storage: {}", e.getMessage());
@@ -335,10 +267,8 @@ public class Firewall implements IFirewallService, IOFMessageListener,
     }
 
     @Override
-    public void init(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-        floodlightProvider = context
-                .getServiceImpl(IFloodlightProviderService.class);
+    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
         storageSource = context.getServiceImpl(IStorageSourceService.class);
         restApi = context.getServiceImpl(IRestApiService.class);
         rules = new ArrayList<FirewallRule>();
@@ -364,18 +294,16 @@ public class Firewall implements IFirewallService, IOFMessageListener,
 
     @Override
     public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
-        if (!this.enabled)
+        if (!this.enabled) {
             return Command.CONTINUE;
+        }
 
         switch (msg.getType()) {
         case PACKET_IN:
             IRoutingDecision decision = null;
             if (cntx != null) {
-                decision = IRoutingDecision.rtStore.get(cntx,
-                        IRoutingDecision.CONTEXT_DECISION);
-
-                return this.processPacketInMessage(sw, (OFPacketIn) msg,
-                        decision, cntx);
+                decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+                return this.processPacketInMessage(sw, (OFPacketIn) msg, decision, cntx);
             }
             break;
         default:
@@ -404,8 +332,7 @@ public class Firewall implements IFirewallService, IOFMessageListener,
         ArrayList<Map<String, Object>> l = new ArrayList<Map<String, Object>>();
         try {
             // null1=no predicate, null2=no ordering
-            IResultSet resultSet = storageSource.executeQuery(TABLE_NAME,
-                    ColumnNames, null, null);
+            IResultSet resultSet = storageSource.executeQuery(TABLE_NAME, ColumnNames, null, null);
             for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
                 l.add(it.next().getRow());
             }
@@ -452,38 +379,28 @@ 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));
-        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,
-                Boolean.toString(rule.wildcard_in_port));
-        entry.put(COLUMN_WILDCARD_DL_SRC,
-                Boolean.toString(rule.wildcard_dl_src));
-        entry.put(COLUMN_WILDCARD_DL_DST,
-                Boolean.toString(rule.wildcard_dl_dst));
-        entry.put(COLUMN_WILDCARD_DL_TYPE,
-                Boolean.toString(rule.wildcard_dl_type));
-        entry.put(COLUMN_WILDCARD_NW_SRC,
-                Boolean.toString(rule.wildcard_nw_src));
-        entry.put(COLUMN_WILDCARD_NW_DST,
-                Boolean.toString(rule.wildcard_nw_dst));
-        entry.put(COLUMN_WILDCARD_NW_PROTO,
-                Boolean.toString(rule.wildcard_nw_proto));
-        entry.put(COLUMN_WILDCARD_TP_SRC,
-                Boolean.toString(rule.wildcard_tp_src));
-        entry.put(COLUMN_WILDCARD_TP_DST,
-                Boolean.toString(rule.wildcard_tp_dst));
+        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_WILDCARD_DPID, Boolean.toString(rule.any_dpid));
+        entry.put(COLUMN_WILDCARD_IN_PORT, Boolean.toString(rule.any_in_port));
+        entry.put(COLUMN_WILDCARD_DL_SRC, Boolean.toString(rule.any_dl_src));
+        entry.put(COLUMN_WILDCARD_DL_DST, Boolean.toString(rule.any_dl_dst));
+        entry.put(COLUMN_WILDCARD_DL_TYPE, Boolean.toString(rule.any_dl_type));
+        entry.put(COLUMN_WILDCARD_NW_SRC, Boolean.toString(rule.any_nw_src));
+        entry.put(COLUMN_WILDCARD_NW_DST, Boolean.toString(rule.any_nw_dst));
+        entry.put(COLUMN_WILDCARD_NW_PROTO, Boolean.toString(rule.any_nw_proto));
+        entry.put(COLUMN_WILDCARD_TP_SRC, Boolean.toString(rule.any_tp_src));
+        entry.put(COLUMN_WILDCARD_TP_DST, Boolean.toString(rule.any_tp_dst));
         entry.put(COLUMN_PRIORITY, Integer.toString(rule.priority));
         entry.put(COLUMN_ACTION, Integer.toString(rule.action.ordinal()));
         storageSource.insertRow(TABLE_NAME, entry);
@@ -535,12 +452,10 @@ public class Firewall implements IFirewallService, IOFMessageListener,
      * @return an instance of RuleWildcardsPair that specify rule that matches
      *         and the wildcards for the firewall decision
      */
-    protected RuleWildcardsPair matchWithRule(IOFSwitch sw, OFPacketIn pi,
-            FloodlightContext cntx) {
+    protected RuleMatchPair matchWithRule(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
         FirewallRule matched_rule = null;
-        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
-                IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-        WildcardsPair wildcards = new WildcardsPair();
+        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+        AllowDropPair adp = new AllowDropPair();
 
         synchronized (rules) {
             Iterator<FirewallRule> iter = this.rules.iterator();
@@ -551,7 +466,9 @@ public class Firewall implements IFirewallService, IOFMessageListener,
                 rule = iter.next();
 
                 // check if rule matches
-                if (rule.matchesFlow(sw.getId(), pi.getInPort(), eth, wildcards) == true) {
+                // AllowDropPair adp's allow and drop matches will modified with what matches
+                // TODO @Ryan might need to re-init adp each time (look into later) 
+                if (rule.matchesThisPacket(sw.getId(), pi.getInPort(), eth, adp) == true) {
                     matched_rule = rule;
                     break;
                 }
@@ -559,14 +476,14 @@ public class Firewall implements IFirewallService, IOFMessageListener,
         }
 
         // make a pair of rule and wildcards, then return it
-        RuleWildcardsPair ret = new RuleWildcardsPair();
-        ret.rule = matched_rule;
-        if (matched_rule == null || matched_rule.action == FirewallRule.FirewallAction.DENY) {
-            ret.wildcards = wildcards.drop;
+        RuleMatchPair rmp = new RuleMatchPair();
+        rmp.rule = matched_rule;
+        if (matched_rule == null || matched_rule.action == FirewallRule.FirewallAction.DROP) {
+            rmp.match = adp.drop.build();
         } else {
-            ret.wildcards = wildcards.allow;
+            rmp.match = adp.allow.build();
         }
-        return ret;
+        return rmp;
     }
 
     /**
@@ -583,42 +500,34 @@ public class Firewall implements IFirewallService, IOFMessageListener,
         return ((IPAddress & inv_subnet_mask) == inv_subnet_mask);
     }
 
-    public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi,
-            IRoutingDecision decision, FloodlightContext cntx) {
-        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
-                IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+    public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
+        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
 
         // Allowing L2 broadcast + ARP broadcast request (also deny malformed
         // broadcasts -> L2 broadcast + L3 unicast)
         if (eth.isBroadcast() == true) {
             boolean allowBroadcast = true;
             // the case to determine if we have L2 broadcast + L3 unicast
-            // don't allow this broadcast packet if such is the case (malformed
-            // packet)
-            if ((eth.getPayload() instanceof IPv4)
-                    && this.IPIsBroadcast(((IPv4) eth.getPayload())
-                            .getDestinationAddress()) == false) {
+            // don't allow this broadcast packet if such is the case (malformed packet)
+            if ((eth.getPayload() instanceof IPv4) && (((IPv4) eth.getPayload()).getDestinationAddress().isBroadcast() == false)) {
                 allowBroadcast = false;
             }
             if (allowBroadcast == true) {
-                if (logger.isTraceEnabled())
-                    logger.trace("Allowing broadcast traffic for PacketIn={}",
-                            pi);
+                if (logger.isTraceEnabled()) {
+                    logger.trace("Allowing broadcast traffic for PacketIn={}", pi);
+                }
                                         
-                decision = new RoutingDecision(sw.getId(), pi.getInPort()
-                		, IDeviceService.fcStore.
-                        get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
+                decision = new RoutingDecision(sw.getId(), pi.getInPort(), 
+                		IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
                         IRoutingDecision.RoutingAction.MULTICAST);
                 decision.addToContext(cntx);
             } else {
-                if (logger.isTraceEnabled())
-                    logger.trace(
-                            "Blocking malformed broadcast traffic for PacketIn={}",
-                            pi);
-
-                decision = new RoutingDecision(sw.getId(), pi.getInPort()
-                		, IDeviceService.fcStore.
-                        get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
+                if (logger.isTraceEnabled()) {
+                    logger.trace("Blocking malformed broadcast traffic for PacketIn={}", pi);
+                }
+
+                decision = new RoutingDecision(sw.getId(), pi.getInPort(),
+                		IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
                         IRoutingDecision.RoutingAction.DROP);
                 decision.addToContext(cntx);
             }
@@ -635,39 +544,36 @@ public class Firewall implements IFirewallService, IOFMessageListener,
          * decision.addToContext(cntx); return Command.CONTINUE; }
          */
 
-        // check if we have a matching rule for this packet/flow
-        // and no decision is taken yet
+        // check if we have a matching rule for this packet/flow and no decision has been made yet
         if (decision == null) {
-            RuleWildcardsPair match_ret = this.matchWithRule(sw, pi, cntx);
-            FirewallRule rule = match_ret.rule;
-
-            if (rule == null || rule.action == FirewallRule.FirewallAction.DENY) {
-                decision = new RoutingDecision(sw.getId(), pi.getInPort()
-                		, IDeviceService.fcStore.
-                        get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
-                        IRoutingDecision.RoutingAction.DROP);
-                decision.setWildcards(match_ret.wildcards);
+        	// check if the packet we received matches an existing rule
+            RuleMatchPair rmp = this.matchWithRule(sw, pi, cntx);
+            FirewallRule rule = rmp.rule;
+
+            // Drop the packet if we don't have a rule allowing or dropping it or if we explicitly drop it
+            if (rule == null || rule.action == FirewallRule.FirewallAction.DROP) {
+                decision = new RoutingDecision(sw.getId(), pi.getInPort(), 
+                		IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE), 
+                		IRoutingDecision.RoutingAction.DROP);
+                decision.setMatch(rmp.match);
                 decision.addToContext(cntx);
                 if (logger.isTraceEnabled()) {
-                    if (rule == null)
-                        logger.trace(
-                                "No firewall rule found for PacketIn={}, blocking flow",
-                                pi);
-                    else if (rule.action == FirewallRule.FirewallAction.DENY) {
-                        logger.trace("Deny rule={} match for PacketIn={}",
-                                rule, pi);
+                    if (rule == null) {
+                        logger.trace("No firewall rule found for PacketIn={}, blocking flow", pi);
+                    } else if (rule.action == FirewallRule.FirewallAction.DROP) {
+                        logger.trace("Deny rule={} match for PacketIn={}", rule, pi);
                     }
                 }
+            // Found a rule and the rule is not a drop, so allow the packet
             } else {
-                decision = new RoutingDecision(sw.getId(), pi.getInPort()
-                		, IDeviceService.fcStore.
-                        get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
+                decision = new RoutingDecision(sw.getId(), pi.getInPort(), 
+                		IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE),
                         IRoutingDecision.RoutingAction.FORWARD_OR_FLOOD);
-                decision.setWildcards(match_ret.wildcards);
+                decision.setMatch(rmp.match);
                 decision.addToContext(cntx);
-                if (logger.isTraceEnabled())
-                    logger.trace("Allow rule={} match for PacketIn={}", rule,
-                            pi);
+                if (logger.isTraceEnabled()) {
+                    logger.trace("Allow rule={} match for PacketIn={}", rule, pi);
+                }
             }
         }
 
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
index f457ce8d9e85510f91fdefe2bb2f3ac84276eec4..b32d9c10ace35606a59447094f74585d58443f41 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRule.java
@@ -18,7 +18,16 @@
 package net.floodlightcontroller.firewall;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import org.openflow.protocol.OFMatch;
+
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TransportPort;
 
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
@@ -30,29 +39,31 @@ import net.floodlightcontroller.packet.UDP;
 public class FirewallRule implements Comparable<FirewallRule> {
     public int ruleid;
 
-    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; 
-    public boolean wildcard_dl_src;
-    public boolean wildcard_dl_dst;
-    public boolean wildcard_dl_type;
-    public boolean wildcard_nw_src;
-    public boolean wildcard_nw_dst;
-    public boolean wildcard_nw_proto;
-    public boolean wildcard_tp_src;
-    public boolean wildcard_tp_dst;
+    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 IPv4AddressWithMask nw_dst_prefix_and_mask;
+    public IpProtocol nw_proto;
+    public TransportPort tp_src;
+    public TransportPort tp_dst;
+
+    /* Specify whether or not a match field is relevant.
+     * true = anything goes; don't care what it is
+     * false = field must match (w or w/o mask depending on field)
+     */
+    public boolean any_dpid;
+    public boolean any_in_port; 
+    public boolean any_dl_src;
+    public boolean any_dl_dst;
+    public boolean any_dl_type;
+    public boolean any_nw_src;
+    public boolean any_nw_dst;
+    public boolean any_nw_proto;
+    public boolean any_tp_src;
+    public boolean any_tp_dst;
 
     public int priority = 0;
 
@@ -60,35 +71,38 @@ public class FirewallRule implements Comparable<FirewallRule> {
 
     public enum FirewallAction {
         /*
-         * DENY: Deny rule
+         * DROP: Drop rule
          * ALLOW: Allow rule
          */
-        DENY, ALLOW
+        DROP, ALLOW
     }
 
+    /**
+     * The default rule is to match on anything.
+     */
     public FirewallRule() {
-        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; 
-        this.wildcard_dl_dst = true; 
-        this.wildcard_dl_type = true; 
-        this.wildcard_nw_src = true; 
-        this.wildcard_nw_dst = true; 
-        this.wildcard_nw_proto = true; 
-        this.wildcard_tp_src = true; 
-        this.wildcard_tp_dst = true; 
+        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.any_dpid = true; 
+        this.any_in_port = true; 
+        this.any_dl_src = true; 
+        this.any_dl_dst = true; 
+        this.any_dl_type = true; 
+        this.any_nw_src = true; 
+        this.any_nw_dst = true; 
+        this.any_nw_proto = true; 
+        this.any_tp_src = true; 
+        this.any_tp_dst = true;
         this.priority = 0; 
         this.action = FirewallAction.ALLOW; 
         this.ruleid = 0; 
@@ -131,33 +145,33 @@ 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 != r.dl_type)
-                || this.wildcard_tp_src != r.wildcard_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 != r.tp_dst)
-                || this.wildcard_dpid != r.wildcard_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 != r.in_port)
-                || this.wildcard_nw_src != r.wildcard_nw_src
-                || (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 != r.dl_src)
-                || this.wildcard_nw_proto != r.wildcard_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 != 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)) {
+                || this.any_dl_type != r.any_dl_type
+                || (this.any_dl_type == false && !this.dl_type.equals(r.dl_type))
+                || this.any_tp_src != r.any_tp_src
+                || (this.any_tp_src == false && !this.tp_src.equals(r.tp_src))
+                || this.any_tp_dst != r.any_tp_dst
+                || (this.any_tp_dst == false && !this.tp_dst.equals(r.tp_dst))
+                || this.any_dpid != r.any_dpid
+                || (this.any_dpid == false && !this.dpid.equals(r.dpid))
+                || this.any_in_port != r.any_in_port
+                || (this.any_in_port == false && !this.in_port.equals(r.in_port))
+                || this.any_nw_src != r.any_nw_src
+                || (this.any_nw_src == false && !this.nw_src_prefix_and_mask.equals(r.nw_src_prefix_and_mask))
+                || this.any_dl_src != r.any_dl_src
+                || (this.any_dl_src == false && !this.dl_src.equals(r.dl_src))
+                || this.any_nw_proto != r.any_nw_proto
+                || (this.any_nw_proto == false && !this.nw_proto.equals(r.nw_proto))
+                || this.any_nw_dst != r.any_nw_dst
+                || (this.any_nw_dst == false && !this.nw_dst_prefix_and_mask.equals(r.nw_dst_prefix_and_mask))
+                || this.any_dl_dst != r.any_dl_dst                
+                || (this.any_dl_dst == false && this.dl_dst != r.dl_dst)) {
             return false;
         }
         return true;
     }
 
     /**
-     * Matches this rule to a given flow - incoming packet
+     * Checks if this rule is a match for the incoming packet's MatchFields
      * 
      * @param switchDpid
      *            the Id of the connected switch
@@ -165,14 +179,13 @@ public class FirewallRule implements Comparable<FirewallRule> {
      *            the switch port where the packet originated from
      * @param packet
      *            the Ethernet packet that arrives at the switch
-     * @param wildcards
-     *            the pair of wildcards (allow and deny) given by Firewall
+     * @param allow-drop-pair
+     *            the pair of matches (allow and drop) given by the Firewall
      *            module that is used by the Firewall module's matchWithRule
-     *            method to derive wildcards for the decision to be taken
+     *            method to derive the match object for the decision to be taken
      * @return true if the rule matches the given packet-in, false otherwise
      */
-    public boolean matchesFlow(long switchDpid, short inPort, Ethernet packet,
-            WildcardsPair wildcards) {
+    public boolean matchesThisPacket(DatapathId switchDpid, OFPort inPort, Ethernet packet, AllowDropPair adp) {
         IPacket pkt = packet.getPayload();
 
         // dl_type type
@@ -183,143 +196,174 @@ public class FirewallRule implements Comparable<FirewallRule> {
         UDP pkt_udp = null;
 
         // tp_src and tp_dst (tp port numbers)
-        short pkt_tp_src = 0;
-        short pkt_tp_dst = 0;
+        TransportPort pkt_tp_src = TransportPort.NONE;
+        TransportPort pkt_tp_dst = TransportPort.NONE;
 
         // switchID matches?
-        if (wildcard_dpid == false && dpid != switchDpid)
+        if (any_dpid == false && !dpid.equals(switchDpid))
             return false;
 
         // in_port matches?
-        if (wildcard_in_port == false && in_port != inPort)
+        if (any_in_port == false && !in_port.equals(inPort))
             return false;
-        if (action == FirewallRule.FirewallAction.DENY) {
-            wildcards.drop &= ~OFMatch.OFPFW_IN_PORT;
+        if (action == FirewallRule.FirewallAction.DROP) {
+            //wildcards.drop &= ~OFMatch.OFPFW_IN_PORT;
+            adp.drop.setExact(MatchField.IN_PORT, this.in_port);
         } else {
-            wildcards.allow &= ~OFMatch.OFPFW_IN_PORT;
+            //wildcards.allow &= ~OFMatch.OFPFW_IN_PORT;
+            adp.allow.setExact(MatchField.IN_PORT, this.in_port);
         }
 
         // mac address (src and dst) match?
-        if (wildcard_dl_src == false
-                && dl_src != packet.getSourceMAC().toLong())
+        if (any_dl_src == false && !dl_src.equals(packet.getSourceMACAddress()))
             return false;
-        if (action == FirewallRule.FirewallAction.DENY) {
-            wildcards.drop &= ~OFMatch.OFPFW_DL_SRC;
+        if (action == FirewallRule.FirewallAction.DROP) {
+            //wildcards.drop &= ~OFMatch.OFPFW_DL_SRC;
+            adp.drop.setExact(MatchField.ETH_SRC, this.dl_src);
         } else {
-            wildcards.allow &= ~OFMatch.OFPFW_DL_SRC;
+            //wildcards.allow &= ~OFMatch.OFPFW_DL_SRC;
+            adp.allow.setExact(MatchField.ETH_SRC, this.dl_src);
         }
 
-        if (wildcard_dl_dst == false
-                && dl_dst != packet.getDestinationMAC().toLong())
+        if (any_dl_dst == false && !dl_dst.equals(packet.getDestinationMACAddress()))
             return false;
-        if (action == FirewallRule.FirewallAction.DENY) {
-            wildcards.drop &= ~OFMatch.OFPFW_DL_DST;
+        if (action == FirewallRule.FirewallAction.DROP) {
+            //wildcards.drop &= ~OFMatch.OFPFW_DL_DST;
+            adp.drop.setExact(MatchField.ETH_DST, this.dl_dst);
         } else {
-            wildcards.allow &= ~OFMatch.OFPFW_DL_DST;
+            //wildcards.allow &= ~OFMatch.OFPFW_DL_DST;
+            adp.allow.setExact(MatchField.ETH_DST, this.dl_dst);
         }
 
         // dl_type check: ARP, IP
 
         // 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 == Ethernet.TYPE_ARP) {
-                if (packet.getEtherType() != Ethernet.TYPE_ARP)
+        if (any_dl_type == false) {
+            if (dl_type.equals(EthType.ARP)) {
+                if (packet.getEtherType() != EthType.ARP.getValue())
                     return false;
                 else {
-                    if (action == FirewallRule.FirewallAction.DENY) {
-                        wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
+                    if (action == FirewallRule.FirewallAction.DROP) {
+                        //wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
+                    	adp.drop.setExact(MatchField.ETH_TYPE, this.dl_type);
                     } else {
-                        wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
+                        //wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
+                    	adp.allow.setExact(MatchField.ETH_TYPE, this.dl_type);
                     }
                 }
-            } else if (dl_type == Ethernet.TYPE_IPv4) {
-                if (packet.getEtherType() != Ethernet.TYPE_IPv4)
+            } else if (dl_type.equals(EthType.IPv4)) {
+                if (packet.getEtherType() != EthType.IPv4.getValue())
                     return false;
                 else {
-                    if (action == FirewallRule.FirewallAction.DENY) {
-                        wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
+                    if (action == FirewallRule.FirewallAction.DROP) {
+                        //wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
+                    	adp.drop.setExact(MatchField.IP_PROTO, this.nw_proto);
                     } else {
-                        wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
+                        //wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
+                    	adp.allow.setExact(MatchField.IP_PROTO, this.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,
-                                    nw_src_maskbits, pkt_ip.getSourceAddress()) == false)
+                    if (any_nw_src == false && this.matchIPAddress(nw_src_prefix_and_mask.getValue().getInt(), nw_src_prefix_and_mask.getMask().getInt(), 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);
+                    if (action == FirewallRule.FirewallAction.DROP) {
+                        //wildcards.drop &= ~OFMatch.OFPFW_NW_SRC_ALL;
+                        //wildcards.drop |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT);
+                    	adp.drop.setMasked(MatchField.IPV4_SRC, nw_src_prefix_and_mask);
                     } else {
-                        wildcards.allow &= ~OFMatch.OFPFW_NW_SRC_ALL;
-                        wildcards.allow |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT);
+                        //wildcards.allow &= ~OFMatch.OFPFW_NW_SRC_ALL;
+                        //wildcards.allow |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT);
+                    	adp.allow.setMasked(MatchField.IPV4_SRC, nw_src_prefix_and_mask);
                     }
 
-                    if (wildcard_nw_dst == false
-                            && this.matchIPAddress(nw_dst_prefix,
-                                    nw_dst_maskbits,
-                                    pkt_ip.getDestinationAddress()) == false)
+                    if (any_nw_dst == false && this.matchIPAddress(nw_dst_prefix_and_mask.getValue().getInt(), nw_dst_prefix_and_mask.getMask().getInt(), 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);
+                    if (action == FirewallRule.FirewallAction.DROP) {
+                        //wildcards.drop &= ~OFMatch.OFPFW_NW_DST_ALL;
+                        //wildcards.drop |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT);
+                    	adp.drop.setMasked(MatchField.IPV4_DST, nw_dst_prefix_and_mask);
                     } else {
-                        wildcards.allow &= ~OFMatch.OFPFW_NW_DST_ALL;
-                        wildcards.allow |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT);
+                        //wildcards.allow &= ~OFMatch.OFPFW_NW_DST_ALL;
+                        //wildcards.allow |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT);
+                    	adp.allow.setMasked(MatchField.IPV4_DST, nw_dst_prefix_and_mask);
                     }
 
                     // nw_proto check
-                    if (wildcard_nw_proto == false) {
-                        if (nw_proto == IPv4.PROTOCOL_TCP) {
-                            if (pkt_ip.getProtocol() != IPv4.PROTOCOL_TCP)
+                    if (any_nw_proto == false) {
+                        if (nw_proto.equals(IpProtocol.TCP)) {
+                            if (!pkt_ip.getProtocol().equals(IpProtocol.TCP)) {
                                 return false;
-                            else {
+                            } else {
                                 pkt_tcp = (TCP) pkt_ip.getPayload();
                                 pkt_tp_src = pkt_tcp.getSourcePort();
                                 pkt_tp_dst = pkt_tcp.getDestinationPort();
                             }
-                        } else if (nw_proto == IPv4.PROTOCOL_UDP) {
-                            if (pkt_ip.getProtocol() != IPv4.PROTOCOL_UDP)
+                        } else if (nw_proto.equals(IpProtocol.UDP)) {
+                            if (!pkt_ip.getProtocol().equals(IpProtocol.UDP)) {
                                 return false;
-                            else {
+                            } else {
                                 pkt_udp = (UDP) pkt_ip.getPayload();
                                 pkt_tp_src = pkt_udp.getSourcePort();
                                 pkt_tp_dst = pkt_udp.getDestinationPort();
                             }
-                        } else if (nw_proto == IPv4.PROTOCOL_ICMP) {
-                            if (pkt_ip.getProtocol() != IPv4.PROTOCOL_ICMP)
+                        } else if (nw_proto.equals(IpProtocol.ICMP)) {
+                            if (!pkt_ip.getProtocol().equals(IpProtocol.ICMP)) {
                                 return false;
-                            else {
+                            } else {
                                 // nothing more needed for ICMP
                             }
                         }
-                        if (action == FirewallRule.FirewallAction.DENY) {
-                            wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
+                        if (action == FirewallRule.FirewallAction.DROP) {
+                            //wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
+                        	adp.drop.setExact(MatchField.IP_PROTO, this.nw_proto);
                         } else {
-                            wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
+                            //wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
+                        	adp.allow.setExact(MatchField.IP_PROTO, this.nw_proto);
                         }
 
                         // TCP/UDP source and destination ports match?
                         if (pkt_tcp != null || pkt_udp != null) {
                             // does the source port match?
-                            if (tp_src != 0 && tp_src != pkt_tp_src)
+                            if (tp_src.getPort() != 0 && tp_src.getPort() != pkt_tp_src.getPort()) {
                                 return false;
-                            if (action == FirewallRule.FirewallAction.DENY) {
-                                wildcards.drop &= ~OFMatch.OFPFW_TP_SRC;
+                            }
+                            if (action == FirewallRule.FirewallAction.DROP) {
+                                //wildcards.drop &= ~OFMatch.OFPFW_TP_SRC;
+                                if (pkt_tcp != null) {
+                                	adp.drop.setExact(MatchField.TCP_SRC, this.tp_src);
+                                } else {
+                                	adp.drop.setExact(MatchField.UDP_SRC, this.tp_src);   
+                                }
                             } else {
-                                wildcards.allow &= ~OFMatch.OFPFW_TP_SRC;
+                                //wildcards.allow &= ~OFMatch.OFPFW_TP_SRC;
+                                if (pkt_tcp != null) {
+                                	adp.allow.setExact(MatchField.TCP_SRC, this.tp_src);
+                                } else {
+                                	adp.allow.setExact(MatchField.UDP_SRC, this.tp_src);   
+                                }
                             }
 
                             // does the destination port match?
-                            if (tp_dst != 0 && tp_dst != pkt_tp_dst)
+                            if (tp_dst.getPort() != 0 && tp_dst.getPort() != pkt_tp_dst.getPort()) {
                                 return false;
-                            if (action == FirewallRule.FirewallAction.DENY) {
-                                wildcards.drop &= ~OFMatch.OFPFW_TP_DST;
+                            }
+                            if (action == FirewallRule.FirewallAction.DROP) {
+                                //wildcards.drop &= ~OFMatch.OFPFW_TP_DST;
+                                if (pkt_tcp != null) {
+                                	adp.drop.setExact(MatchField.TCP_DST, this.tp_dst);
+                                } else {
+                                	adp.drop.setExact(MatchField.UDP_DST, this.tp_dst);   
+                                }
                             } else {
-                                wildcards.allow &= ~OFMatch.OFPFW_TP_DST;
+                                //wildcards.allow &= ~OFMatch.OFPFW_TP_DST;
+                            	if (pkt_tcp != null) {
+                            		adp.allow.setExact(MatchField.TCP_DST, this.tp_dst);
+                                } else {
+                                	adp.allow.setExact(MatchField.UDP_DST, this.tp_dst);   
+                                }
                             }
                         }
                     }
@@ -330,10 +374,12 @@ public class FirewallRule implements Comparable<FirewallRule> {
                 return false;
             }
         }
-        if (action == FirewallRule.FirewallAction.DENY) {
-            wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
+        if (action == FirewallRule.FirewallAction.DROP) {
+            //wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
+        	adp.drop.setExact(MatchField.ETH_TYPE, this.dl_type);
         } else {
-            wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
+            //wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
+        	adp.allow.setExact(MatchField.ETH_TYPE, this.dl_type);
         }
 
         // all applicable checks passed
@@ -352,13 +398,12 @@ public class FirewallRule implements Comparable<FirewallRule> {
      * @return true if CIDR address matches the packet's IP address, false
      *         otherwise
      */
-    protected boolean matchIPAddress(int rulePrefix, int ruleBits,
-            int packetAddress) {
+    protected boolean matchIPAddress(int rulePrefix, int ruleBits, IPv4Address packetAddress) {
         boolean matched = true;
 
         int rule_iprng = 32 - ruleBits;
         int rule_ipint = rulePrefix;
-        int pkt_ipint = packetAddress;
+        int pkt_ipint = packetAddress.getInt();
         // if there's a subnet range (bits to be wildcarded > 0)
         if (rule_iprng > 0) {
             // right shift bits to remove rule_iprng of LSB that are to be
@@ -382,30 +427,30 @@ public class FirewallRule implements Comparable<FirewallRule> {
     public int hashCode() {
         final int prime = 2521;
         int result = super.hashCode();
-        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 + (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 + action.ordinal();
         result = prime * result + priority;
-        result = prime * result + (new Boolean(wildcard_dpid)).hashCode();
-        result = prime * result + (new Boolean(wildcard_in_port)).hashCode();
-        result = prime * result + (new Boolean(wildcard_dl_src)).hashCode();
-        result = prime * result + (new Boolean(wildcard_dl_dst)).hashCode();
-        result = prime * result + (new Boolean(wildcard_dl_type)).hashCode();
-        result = prime * result + (new Boolean(wildcard_nw_src)).hashCode();
-        result = prime * result + (new Boolean(wildcard_nw_dst)).hashCode();
-        result = prime * result + (new Boolean(wildcard_nw_proto)).hashCode();
-        result = prime * result + (new Boolean(wildcard_tp_src)).hashCode();
-        result = prime * result + (new Boolean(wildcard_tp_dst)).hashCode();
+        result = prime * result + (new Boolean(any_dpid)).hashCode();
+        result = prime * result + (new Boolean(any_in_port)).hashCode();
+        result = prime * result + (new Boolean(any_dl_src)).hashCode();
+        result = prime * result + (new Boolean(any_dl_dst)).hashCode();
+        result = prime * result + (new Boolean(any_dl_type)).hashCode();
+        result = prime * result + (new Boolean(any_nw_src)).hashCode();
+        result = prime * result + (new Boolean(any_nw_dst)).hashCode();
+        result = prime * result + (new Boolean(any_nw_proto)).hashCode();
+        result = prime * result + (new Boolean(any_tp_src)).hashCode();
+        result = prime * result + (new Boolean(any_tp_dst)).hashCode();
         return result;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java
index 3180968d1dd1786ef183933bc8584a5b896b123d..334d02236d4188969a30b644b486598d908aa8ff 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRuleSerializer.java
@@ -19,14 +19,10 @@ 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
@@ -42,28 +38,28 @@ public class FirewallRuleSerializer extends JsonSerializer<FirewallRule> {
         jGen.writeStartObject();
         
         jGen.writeNumberField("ruleid", rule.ruleid);
-        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);
-        jGen.writeBooleanField("wildcard_dl_dst", rule.wildcard_dl_dst);
-        jGen.writeBooleanField("wildcard_dl_type", rule.wildcard_dl_type);
-        jGen.writeBooleanField("wildcard_nw_src", rule.wildcard_nw_src);
-        jGen.writeBooleanField("wildcard_nw_dst", rule.wildcard_nw_dst);
-        jGen.writeBooleanField("wildcard_nw_proto", rule.wildcard_nw_proto);
-        jGen.writeBooleanField("wildcard_tp_src", rule.wildcard_tp_src);
-        jGen.writeBooleanField("wildcard_tp_dst", rule.wildcard_tp_dst);
+        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.writeBooleanField("any_dpid", rule.any_dpid);
+        jGen.writeBooleanField("any_in_port", rule.any_in_port);
+        jGen.writeBooleanField("any_dl_src", rule.any_dl_src);
+        jGen.writeBooleanField("any_dl_dst", rule.any_dl_dst);
+        jGen.writeBooleanField("any_dl_type", rule.any_dl_type);
+        jGen.writeBooleanField("any_nw_src", rule.any_nw_src);
+        jGen.writeBooleanField("any_nw_dst", rule.any_nw_dst);
+        jGen.writeBooleanField("any_nw_proto", rule.any_nw_proto);
+        jGen.writeBooleanField("any_tp_src", rule.any_tp_src);
+        jGen.writeBooleanField("any_tp_dst", rule.any_tp_dst);
         jGen.writeNumberField("priority", rule.priority);
         jGen.writeStringField("action", String.valueOf(rule.action));
         
diff --git a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java b/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
index 7af219cc63f70879eda9cdd5ab7971b1a3111cea..90c3d13a2d24f9aa128c8480852dd3a15d4baf77 100644
--- a/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
+++ b/src/main/java/net/floodlightcontroller/firewall/FirewallRulesResource.java
@@ -25,7 +25,14 @@ 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.openflow.util.HexString;
+
+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.restlet.resource.Delete;
 import org.restlet.resource.Post;
 import org.restlet.resource.Get;
@@ -33,7 +40,6 @@ 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 {
@@ -166,96 +172,92 @@ public class FirewallRulesResource extends ServerResource {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("-1") == false) {
                     // user inputs hex format dpid
-                    rule.dpid = HexString.toLong(tmp);
-                    rule.wildcard_dpid = false;
+                    rule.dpid = DatapathId.of(tmp);
+                    rule.any_dpid = false;
                 }
             }
 
             else if (n == "src-inport") {
-                rule.in_port = Short.parseShort(jp.getText());
-                rule.wildcard_in_port = false;
+                rule.in_port = OFPort.of(Integer.parseInt(jp.getText()));
+                rule.any_in_port = false;
             }
 
             else if (n == "src-mac") {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("ANY") == false) {
-                    rule.wildcard_dl_src = false;
-                    rule.dl_src = Ethernet.toLong(Ethernet.toMACAddress(tmp));
+                    rule.any_dl_src = false;
+                    rule.dl_src = MacAddress.of(tmp);
                 }
             }
 
             else if (n == "dst-mac") {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("ANY") == false) {
-                    rule.wildcard_dl_dst = false;
-                    rule.dl_dst = Ethernet.toLong(Ethernet.toMACAddress(tmp));
+                    rule.any_dl_dst = false;
+                    rule.dl_dst = MacAddress.of(tmp);
                 }
             }
 
             else if (n == "dl-type") {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("ARP")) {
-                    rule.wildcard_dl_type = false;
-                    rule.dl_type = Ethernet.TYPE_ARP;
+                    rule.any_dl_type = false;
+                    rule.dl_type = EthType.ARP;
                 }
                 if (tmp.equalsIgnoreCase("IPv4")) {
-                    rule.wildcard_dl_type = false;
-                    rule.dl_type = Ethernet.TYPE_IPv4;
+                    rule.any_dl_type = false;
+                    rule.dl_type = EthType.IPv4;
                 }
             }
 
             else if (n == "src-ip") {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("ANY") == false) {
-                    rule.wildcard_nw_src = false;
-                    rule.wildcard_dl_type = false;
-                    rule.dl_type = Ethernet.TYPE_IPv4;
-                    int[] cidr = IPCIDRToPrefixBits(tmp);
-                    rule.nw_src_prefix = cidr[0];
-                    rule.nw_src_maskbits = cidr[1];
+                    rule.any_nw_src = false;
+                    rule.any_dl_type = false;
+                    rule.dl_type = EthType.IPv4;
+                    rule.nw_src_prefix_and_mask = IPv4AddressWithMask.of(tmp);
                 }
             }
 
             else if (n == "dst-ip") {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("ANY") == false) {
-                    rule.wildcard_nw_dst = false;
-                    rule.wildcard_dl_type = false;
-                    rule.dl_type = Ethernet.TYPE_IPv4;
-                    int[] cidr = IPCIDRToPrefixBits(tmp);
-                    rule.nw_dst_prefix = cidr[0];
-                    rule.nw_dst_maskbits = cidr[1];
+                    rule.any_nw_dst = false;
+                    rule.any_dl_type = false;
+                    rule.dl_type = EthType.IPv4;
+                    rule.nw_dst_prefix_and_mask = IPv4AddressWithMask.of(tmp);
                 }
             }
 
             else if (n == "nw-proto") {
                 tmp = jp.getText();
                 if (tmp.equalsIgnoreCase("TCP")) {
-                    rule.wildcard_nw_proto = false;
-                    rule.nw_proto = IPv4.PROTOCOL_TCP;
-                    rule.wildcard_dl_type = false;
-                    rule.dl_type = Ethernet.TYPE_IPv4;
+                    rule.any_nw_proto = false;
+                    rule.nw_proto = IpProtocol.TCP;
+                    rule.any_dl_type = false;
+                    rule.dl_type = EthType.IPv4;
                 } else if (tmp.equalsIgnoreCase("UDP")) {
-                    rule.wildcard_nw_proto = false;
-                    rule.nw_proto = IPv4.PROTOCOL_UDP;
-                    rule.wildcard_dl_type = false;
-                    rule.dl_type = Ethernet.TYPE_IPv4;
+                    rule.any_nw_proto = false;
+                    rule.nw_proto = IpProtocol.UDP;
+                    rule.any_dl_type = false;
+                    rule.dl_type = EthType.IPv4;
                 } else if (tmp.equalsIgnoreCase("ICMP")) {
-                    rule.wildcard_nw_proto = false;
-                    rule.nw_proto = IPv4.PROTOCOL_ICMP;
-                    rule.wildcard_dl_type = false;
-                    rule.dl_type = Ethernet.TYPE_IPv4;
+                    rule.any_nw_proto = false;
+                    rule.nw_proto = IpProtocol.ICMP;
+                    rule.any_dl_type = false;
+                    rule.dl_type = EthType.IPv4;
                 }
             }
 
             else if (n == "tp-src") {
-                rule.wildcard_tp_src = false;
-                rule.tp_src = Short.parseShort(jp.getText());
+                rule.any_tp_src = false;
+                rule.tp_src = TransportPort.of(Integer.parseInt(jp.getText()));
             }
 
             else if (n == "tp-dst") {
-                rule.wildcard_tp_dst = false;
-                rule.tp_dst = Short.parseShort(jp.getText());
+                rule.any_tp_dst = false;
+                rule.tp_dst = TransportPort.of(Integer.parseInt(jp.getText()));
             }
 
             else if (n == "priority") {
@@ -266,7 +268,7 @@ public class FirewallRulesResource extends ServerResource {
                 if (jp.getText().equalsIgnoreCase("allow") == true) {
                     rule.action = FirewallRule.FirewallAction.ALLOW;
                 } else if (jp.getText().equalsIgnoreCase("deny") == true) {
-                    rule.action = FirewallRule.FirewallAction.DENY;
+                    rule.action = FirewallRule.FirewallAction.DROP;
                 }
             }
         }
diff --git a/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java b/src/main/java/net/floodlightcontroller/firewall/RuleMatchPair.java
similarity index 86%
rename from src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java
rename to src/main/java/net/floodlightcontroller/firewall/RuleMatchPair.java
index d2aa2e5ff458b4fdef9c00bb4544e9851df3fe5c..ed9fb45024c308b2a88dc944b20796fb27887f59 100644
--- a/src/main/java/net/floodlightcontroller/firewall/RuleWildcardsPair.java
+++ b/src/main/java/net/floodlightcontroller/firewall/RuleMatchPair.java
@@ -17,9 +17,9 @@
 
 package net.floodlightcontroller.firewall;
 
-import org.openflow.protocol.OFMatch;
+import org.projectfloodlight.openflow.protocol.match.Match;
 
-public class RuleWildcardsPair {
+public class RuleMatchPair {
     public FirewallRule rule;
-    public int wildcards = OFMatch.OFPFW_ALL;
+    public Match match;
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java
index 12fac87914b6292112fedd8e8d88e5c40d394f22..60fab0d760c64ca419938534f71284bf3e5473ad 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchMac.java
@@ -16,7 +16,7 @@
 
 package net.floodlightcontroller.flowcache;
 
-import net.floodlightcontroller.util.MACAddress;
+import org.projectfloodlight.openflow.types.MacAddress;
 
 /**
  * The Class for FlowReconcileQuery for link down event.
@@ -63,7 +63,7 @@ public class FRQueryBvsMatchMac extends FlowReconcileQuery {
         StringBuilder builder = new StringBuilder();
         builder.append("[");
         builder.append("MAC: ");
-        builder.append(MACAddress.valueOf(mac).toString());
+        builder.append(MacAddress.of(mac).toString());
         builder.append("]");
         return builder.toString();
     }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java
index 27ecc8dfbda9628a9cec5a121e8edb959385cffb..933b9324a8c35d527932af29c4690d6f1b7280f9 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryBvsMatchSwitchPort.java
@@ -18,13 +18,13 @@ package net.floodlightcontroller.flowcache;
 
 import java.util.List;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
 /**
  * The Class for FlowReconcileQuery for BVS config interface match switch port.
  */
 public class FRQueryBvsMatchSwitchPort extends FlowReconcileQuery {
     /*switch DPID*/
-    public long swId;
+    public DatapathId swId;
     /*List of ports:*/
     public List<String> matchPortList;
 
@@ -32,7 +32,7 @@ public class FRQueryBvsMatchSwitchPort extends FlowReconcileQuery {
         super(ReconcileQueryEvType.BVS_INTERFACE_RULE_CHANGED_MATCH_SWITCH_PORT);
     }
 
-    public FRQueryBvsMatchSwitchPort(Long swId, List<String> portList) {
+    public FRQueryBvsMatchSwitchPort(DatapathId swId, List<String> portList) {
         this();
         this.swId = swId;
         this.matchPortList = portList;
@@ -42,7 +42,7 @@ public class FRQueryBvsMatchSwitchPort extends FlowReconcileQuery {
     public int hashCode() {
         final int prime = 347;
         int result = super.hashCode();
-        result = prime * result + (int)swId;
+        result = (int) (prime * result + swId.getLong());
         return result;
     }
 
@@ -58,8 +58,8 @@ public class FRQueryBvsMatchSwitchPort extends FlowReconcileQuery {
             return false;
         }
         FRQueryBvsMatchSwitchPort other = (FRQueryBvsMatchSwitchPort) obj;
-        if (swId != other.swId) return false;
-        if (! matchPortList.equals(other.matchPortList)) return false;
+        if (swId.equals(other.swId)) return false;
+        if (!matchPortList.equals(other.matchPortList)) return false;
         return true;
     }
 
@@ -68,7 +68,7 @@ public class FRQueryBvsMatchSwitchPort extends FlowReconcileQuery {
         StringBuilder builder = new StringBuilder();
         builder.append("[");
         builder.append("Switch: ");
-        builder.append(HexString.toHexString(swId));
+        builder.append(swId.toString());
         builder.append(", Match Port List:");
         builder.append(matchPortList);
         builder.append("]");
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java b/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java
index 48a2eb304040f0e4b45a7b5213b91a4cf0c21e48..64b9d2aaeaeda72169f48b675b80d7e01e58393d 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FRQueryDevicePropertyChanged.java
@@ -17,7 +17,6 @@
 package net.floodlightcontroller.flowcache;
 
 import net.floodlightcontroller.devicemanager.IDevice;
-import net.floodlightcontroller.util.MACAddress;
 
 /**
  * The Class for FlowReconcileQuery for device property changed event.
@@ -62,7 +61,7 @@ public class FRQueryDevicePropertyChanged extends FlowReconcileQuery {
         StringBuilder builder = new StringBuilder();
         builder.append("[");
         builder.append("Device: ");
-        builder.append(MACAddress.valueOf(device.getMACAddress()));
+        builder.append(device.getMACAddress().toString());
         builder.append("]");
         return builder.toString();
     }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
index 4ae2caed69063207f88d4fbd8422ddce5a4fd2f5..578a15e60d15cc41294155e052082b107b9562b2 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
@@ -26,50 +26,44 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.util.ListenerDispatcher;
 import net.floodlightcontroller.core.util.SingletonTask;
-import net.floodlightcontroller.counter.CounterStore;
-import net.floodlightcontroller.counter.ICounter;
-import net.floodlightcontroller.counter.ICounterStoreService;
-import net.floodlightcontroller.counter.SimpleCounter;
+import net.floodlightcontroller.debugcounter.DebugCounterResource;
 import net.floodlightcontroller.debugcounter.IDebugCounter;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import net.floodlightcontroller.debugcounter.NullDebugCounter;
-import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
-import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
 import net.floodlightcontroller.flowcache.FlowReconcileQuery.FlowReconcileQueryDebugEvent;
 import net.floodlightcontroller.flowcache.IFlowReconcileListener;
 import net.floodlightcontroller.flowcache.OFMatchReconcile;
 import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 
-import org.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class FlowReconcileManager
-        implements IFloodlightModule, IFlowReconcileService {
+import com.sun.j3d.utils.scenegraph.io.retained.Controller;
 
+public class FlowReconcileManager implements IFloodlightModule, IFlowReconcileService {
     /** The logger. */
-    private static Logger logger =
-                        LoggerFactory.getLogger(FlowReconcileManager.class);
+    private static Logger logger =  LoggerFactory.getLogger(FlowReconcileManager.class);
 
     /** Reference to dependent modules */
-    protected IThreadPoolService threadPool;
-    protected ICounterStoreService counterStore;
-    protected IDebugCounterService debugCounters;
+    protected IThreadPoolService threadPoolService;
+    protected IDebugCounterService debugCounterService;
+    protected IFloodlightProviderService floodlightProviderService;
+    
     /**
      * The list of flow reconcile listeners that have registered to get
      * flow reconcile callbacks. Such callbacks are invoked, for example, when
      * a switch with existing flow-mods joins this controller and those flows
      * need to be reconciled with the current configuration of the controller.
      */
-    protected ListenerDispatcher<OFType, IFlowReconcileListener>
-                                               flowReconcileListeners;
+    protected ListenerDispatcher<OFType, IFlowReconcileListener> flowReconcileListeners;
 
     /** A FIFO queue to keep all outstanding flows for reconciliation */
     PriorityPendingQueue <OFMatchReconcile> flowQueue;
@@ -77,8 +71,8 @@ public class FlowReconcileManager
     /** Asynchronous task to feed the flowReconcile pipeline */
     protected SingletonTask flowReconcileTask;
 
-    String controllerPktInCounterName;
-    protected SimpleCounter lastPacketInCounter;
+    protected DebugCounterResource ctrControllerPktIn;
+    protected IDebugCounter lastPacketInCounter;
 
     protected final static int MAX_SYSTEM_LOAD_PER_SECOND = 10000;
     /** a minimum flow reconcile rate so that it won't stave */
@@ -99,6 +93,7 @@ public class FlowReconcileManager
     private IDebugCounter ctrFlowReconcileRequest;
     private IDebugCounter ctrReconciledFlows;
     protected boolean flowReconcileEnabled;
+    private DebugCounterResource ctrPacketInRsrc = null;
 
     public AtomicInteger flowReconcileThreadRunCount;
 
@@ -143,7 +138,7 @@ public class FlowReconcileManager
         OFMatchReconcile myOfmRc = new OFMatchReconcile(ofmRcIn);
 
         flowQueue.offer(myOfmRc, priority);
-        ctrFlowReconcileRequest.updateCounterWithFlush();
+        ctrFlowReconcileRequest.increment();
 
         Date currTime = new Date();
         long delay = 0;
@@ -192,19 +187,18 @@ public class FlowReconcileManager
         Collection<Class<? extends IFloodlightService>> l =
                 new ArrayList<Class<? extends IFloodlightService>>();
         l.add(IThreadPoolService.class);
-        l.add(ICounterStoreService.class);
+        l.add(IDebugCounterService.class);
         return null;
     }
 
     @Override
     public void init(FloodlightModuleContext context)
             throws FloodlightModuleException {
-        threadPool = context.getServiceImpl(IThreadPoolService.class);
-        counterStore = context.getServiceImpl(ICounterStoreService.class);
-        debugCounters = context.getServiceImpl(IDebugCounterService.class);
+    	floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+        threadPoolService = context.getServiceImpl(IThreadPoolService.class);
+        debugCounterService = context.getServiceImpl(IDebugCounterService.class);
         flowQueue = new PriorityPendingQueue<OFMatchReconcile>();
-        flowReconcileListeners =
-                new ListenerDispatcher<OFType, IFlowReconcileListener>();
+        flowReconcileListeners = new ListenerDispatcher<OFType, IFlowReconcileListener>();
 
         Map<String, String> configParam = context.getConfigParams(this);
         String enableValue = configParam.get(EnableConfigKey);
@@ -221,18 +215,16 @@ public class FlowReconcileManager
     }
 
     private void registerFlowReconcileManagerDebugCounters() throws FloodlightModuleException {
-        if (debugCounters == null) {
+        if (debugCounterService == null) {
             logger.error("Debug Counter Service not found.");
-            debugCounters = new NullDebugCounter();
         }
         try {
-            ctrFlowReconcileRequest = debugCounters.registerCounter(PACKAGE, "flow-reconcile-request",
-                "All flow reconcile request received by this module",
-                CounterType.ALWAYS_COUNT);
-            ctrReconciledFlows = debugCounters.registerCounter(PACKAGE, "reconciled-flows",
-                "All flows reconciled successfully by this module",
-                CounterType.ALWAYS_COUNT);
-        } catch (CounterException e) {
+        	debugCounterService.registerModule(PACKAGE);
+            ctrFlowReconcileRequest = debugCounterService.registerCounter(PACKAGE, "flow-reconcile-request",
+                "All flow reconcile request received by this module");
+            ctrReconciledFlows = debugCounterService.registerCounter(PACKAGE, "reconciled-flows",
+                "All flows reconciled successfully by this module");
+        } catch (Exception e) {
             throw new FloodlightModuleException(e.getMessage());
         }
     }
@@ -241,7 +233,7 @@ public class FlowReconcileManager
     @Override
     public void startUp(FloodlightModuleContext context) {
         // thread to do flow reconcile
-        ScheduledExecutorService ses = threadPool.getScheduledExecutor();
+        ScheduledExecutorService ses = threadPoolService.getScheduledExecutor();
         flowReconcileTask = new SingletonTask(ses, new Runnable() {
             @Override
             public void run() {
@@ -257,14 +249,8 @@ public class FlowReconcileManager
             }
         });
 
-        String packetInName = OFType.PACKET_IN.toClass().getName();
+        String packetInName = OFType.PACKET_IN.getClass().getName();
         packetInName = packetInName.substring(packetInName.lastIndexOf('.')+1);
-
-        // Construct controller counter for the packet_in
-        controllerPktInCounterName =
-            CounterStore.createCounterName(ICounterStoreService.CONTROLLER_NAME,
-                                           -1,
-                                           packetInName);
     }
 
     protected void updateFlush() {
@@ -296,7 +282,7 @@ public class FlowReconcileManager
             reconcileCapacity--;
             if (ofmRc != null) {
                 ofmRcList.add(ofmRc);
-                ctrReconciledFlows.updateCounterWithFlush();
+                ctrReconciledFlows.increment();
                 if (logger.isTraceEnabled()) {
                     logger.trace("Add flow {} to be the reconcileList", ofmRc.cookie);
                 }
@@ -332,7 +318,7 @@ public class FlowReconcileManager
             for (OFMatchReconcile ofmRc : ofmRcList) {
                 if (ofmRc.origReconcileQueryEvent != null) {
                     ofmRc.origReconcileQueryEvent.evType.getDebugEvent()
-                        .updateEventWithFlush(new FlowReconcileQueryDebugEvent(
+                    .newEventWithFlush(new FlowReconcileQueryDebugEvent(
                             ofmRc.origReconcileQueryEvent,
                             "Flow Reconciliation Complete",
                             ofmRc));
@@ -376,34 +362,32 @@ public class FlowReconcileManager
      * @return
      */
     protected int getCurrentCapacity() {
-        ICounter pktInCounter =
-            counterStore.getCounter(controllerPktInCounterName);
-        int minFlows = MIN_FLOW_RECONCILE_PER_SECOND *
-                        FLOW_RECONCILE_DELAY_MILLISEC / 1000;
-
+        /*int minFlows = MIN_FLOW_RECONCILE_PER_SECOND * FLOW_RECONCILE_DELAY_MILLISEC / 1000;
+        
+        List<DebugCounterResource> contCtrRsrcList = debugCounterService.getModuleCounterValues(Controller.class.getName());
+        for (DebugCounterResource dcr : contCtrRsrcList) {
+        	if (dcr.getCounterHierarchy().equals("packet-in")) {
+                ctrPacketInRsrc = dcr;
+                break;
+        	}
+        }
+        
         // If no packetInCounter, then there shouldn't be any flow.
-        if (pktInCounter == null ||
-            pktInCounter.getCounterDate() == null ||
-            pktInCounter.getCounterValue() == null) {
-            logger.debug("counter {} doesn't exist",
-                        controllerPktInCounterName);
+        if (ctrPacketInRsrc == null || ctrPacketInRsrc.getCounterValue() == null || ctrPacketInRsrc.getCounterValue() == 0) {
+            logger.debug("counter {} doesn't exist", ctrPacketInRsrc);
             return minFlows;
         }
 
-        // Haven't get any counter yet.
-        if (lastPacketInCounter == null) {
-            logger.debug("First time get the count for {}",
-                        controllerPktInCounterName);
-            lastPacketInCounter = (SimpleCounter)
-            SimpleCounter.createCounter(pktInCounter);
+        // We're the first packet_in
+        if (lastPacketInCounter.getCounterValue() == 0) {
+            logger.debug("First time get the count for {}", lastPacketInCounter);
             return minFlows;
         }
 
-        int pktInRate = getPktInRate(pktInCounter, new Date());
+        int pktInRate = getPktInRate(ctrPacketInRsrc, new Date());
 
         // Update the last packetInCounter
-        lastPacketInCounter = (SimpleCounter)
-        SimpleCounter.createCounter(pktInCounter);
+        lastPacketInCounter = new DebugCounterResource(counter);
         int capacity = minFlows;
         if ((pktInRate + MIN_FLOW_RECONCILE_PER_SECOND) <=
                                MAX_SYSTEM_LOAD_PER_SECOND) {
@@ -414,11 +398,11 @@ public class FlowReconcileManager
         if (logger.isTraceEnabled()) {
             logger.trace("Capacity is {}", capacity);
         }
-        return capacity;
+        return capacity; */ return 0;
     }
 
-    protected int getPktInRate(ICounter newCnt, Date currentTime) {
-        if (newCnt == null ||
+    protected int getPktInRate(DebugCounterResource newCnt, Date currentTime) {
+        /*if (newCnt == null ||
             newCnt.getCounterDate() == null ||
             newCnt.getCounterValue() == null) {
             return 0;
@@ -466,7 +450,7 @@ public class FlowReconcileManager
                 break;
         }
 
-        return (int)(diff/elapsedTimeInSecond);
+        return (int)(diff/elapsedTimeInSecond); */ return 0;
     }
 }
 
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java
index ad6ce1289f6a3976e00008b82310b09b09cdd2fe..538e01d873eb874248aae07d1688995a5563958e 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQuery.java
@@ -21,9 +21,9 @@ import java.lang.ref.SoftReference;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
-import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
+import net.floodlightcontroller.debugevent.IEventCategory;
 import net.floodlightcontroller.debugevent.IDebugEventService;
-import net.floodlightcontroller.debugevent.IEventUpdater;
+import net.floodlightcontroller.debugevent.MockDebugEventService;
 import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority;
 
 /**
@@ -93,38 +93,37 @@ public class FlowReconcileQuery {
 
         private String description;
         private EventPriority priority;
-        private IEventUpdater<FlowReconcileQueryDebugEvent>
-                evReconcileQueryDebugEvent;
+        private IEventCategory<FlowReconcileQueryDebugEvent> eventCategory;
+        private IDebugEventService debugEventService;
 
-        private ReconcileQueryEvType(EventPriority priority,
-                                     String description) {
+        private ReconcileQueryEvType(EventPriority priority, String description) {
             this.priority = priority;
             this.description = description;
         }
+        
         public EventPriority getPriority() {
              return this.priority;
         }
+        
         public String getDescription() {
             return description;
         }
-        public void registerDebugEvent(String packageName,
-                                       IDebugEventService debugEvents)
-                                       throws MaxEventsRegistered {
-            try {
-                evReconcileQueryDebugEvent =
-                    debugEvents.registerEvent(
-                        packageName,
-                        this.toString().toLowerCase().replace("_", "-"),
-                        this.getDescription(),
-                        EventType.ALWAYS_LOG,
-                        FlowReconcileQueryDebugEvent.class,
-                        500);
-            } catch (MaxEventsRegistered e) {
-                throw e;
-            }
+        
+        public void registerDebugEvent(String packageName, IDebugEventService debugEvents) {
+        	 if (debugEventService == null) {
+                 debugEventService = new MockDebugEventService();
+             }
+                eventCategory = debugEventService.buildEvent(FlowReconcileQueryDebugEvent.class)
+                    .setModuleName(packageName)
+                    .setEventName(this.toString().toLowerCase().replace("_", "-"))
+                    .setEventDescription(this.getDescription())
+                    .setEventType(EventType.ALWAYS_LOG)
+                    .setBufferCapacity(500)
+                    .register();
         }
-        public IEventUpdater<FlowReconcileQueryDebugEvent> getDebugEvent() {
-            return evReconcileQueryDebugEvent;
+    
+        public IEventCategory<FlowReconcileQueryDebugEvent> getDebugEvent() {
+            return eventCategory;
         }
     }
     public FlowReconcileQuery(ReconcileQueryEvType evType) {
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java
index 245ebdf3993233397e808ec0d8c42a442daca5ef..27134c6844a8a02e1a8a56728bd5c329403bb0cb 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryDeviceMove.java
@@ -20,7 +20,6 @@ import java.util.Arrays;
 
 import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.SwitchPort;
-import net.floodlightcontroller.util.MACAddress;
 
 /**
  * The Class for FlowReconcileQuery for device move event.
@@ -74,7 +73,7 @@ public class FlowReconcileQueryDeviceMove extends FlowReconcileQuery {
         StringBuilder builder = new StringBuilder();
         builder.append("[");
         builder.append("Device: ");
-        builder.append(MACAddress.valueOf(deviceMoved.getMACAddress()).toString());
+        builder.append(deviceMoved.getMACAddress().toString());
         builder.append(", Old Attachment Points:");
         builder.append(Arrays.toString(oldAp));
         builder.append("]");
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java
index 23c03352383ae9f070df48d596e35860c3159d6f..65361e6e99f5627f0b78fd483f8211cf284eba75 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileQueryPortDown.java
@@ -16,22 +16,23 @@
 
 package net.floodlightcontroller.flowcache;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
 
 /**
  * The Class for FlowReconcileQuery for link down event.
  */
 public class FlowReconcileQueryPortDown extends FlowReconcileQuery {
     /*down port switch DPID*/
-    public long swId;
+    public DatapathId swId;
     /*down port ID */
-    public short port;
+    public OFPort port;
 
     public FlowReconcileQueryPortDown() {
         super(ReconcileQueryEvType.LINK_DOWN);
     }
 
-    public FlowReconcileQueryPortDown(long swId, short portDown) {
+    public FlowReconcileQueryPortDown(DatapathId swId, OFPort portDown) {
         this();
         this.swId = swId;
         this.port = portDown;
@@ -41,8 +42,8 @@ public class FlowReconcileQueryPortDown extends FlowReconcileQuery {
     public int hashCode() {
         final int prime = 347;
         int result = super.hashCode();
-        result = prime * result + (int)swId;
-        result = prime * result + port;
+        result = prime * result + (int) swId.getLong();
+        result = prime * result + port.getPortNumber();
         return result;
     }
 
@@ -68,9 +69,9 @@ public class FlowReconcileQueryPortDown extends FlowReconcileQuery {
         StringBuilder builder = new StringBuilder();
         builder.append("[");
         builder.append("Switch: ");
-        builder.append(HexString.toHexString(swId));
+        builder.append(swId.toString());
         builder.append(", Port: ");
-        builder.append(port);
+        builder.append(port.getPortNumber());
         builder.append("]");
         return builder.toString();
     }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java
index f01bd0b54fa0b5063f7e4d29536817fd1c82e7e9..3fee84743a7061343649c16049f2e77819fefc77 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowReconcileListener.java
@@ -19,7 +19,7 @@ package net.floodlightcontroller.flowcache;
 import java.util.ArrayList;
 
 import net.floodlightcontroller.core.IListener;
-import org.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFType;
 
 /**
  * The Interface IFlowReconciler.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java b/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java
index 70b4d42a38efe6a06c6cc823ad58f0e660e89f25..2f81dc6ad71bd2e98401610147e00d538d1f3503 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/OFMatchReconcile.java
@@ -17,7 +17,9 @@
 package net.floodlightcontroller.flowcache;
 
 import net.floodlightcontroller.core.FloodlightContext;
-import org.openflow.protocol.OFMatchWithSwDpid;
+import net.floodlightcontroller.util.OFMatchWithSwDpid;
+
+import org.projectfloodlight.openflow.types.OFPort;
 
 /**
  * OFMatchReconcile class to indicate result of a flow-reconciliation.
@@ -66,7 +68,7 @@ public class OFMatchReconcile  {
     /** The reconcile action. */
     public ReconcileAction rcAction;
     /** Outport in the event of UPDATE_PATH action**/
-    public short outPort;
+    public OFPort outPort;
 
     // The context for the reconcile action
     public FloodlightContext cntx;
@@ -79,15 +81,15 @@ public class OFMatchReconcile  {
      * Instantiates a new oF match reconcile object.
      */
     public OFMatchReconcile() {
-        ofmWithSwDpid      = new OFMatchWithSwDpid();
+        ofmWithSwDpid = new OFMatchWithSwDpid();
         rcAction = ReconcileAction.NO_CHANGE;
         cntx = new FloodlightContext();
     }
     
     public OFMatchReconcile(OFMatchReconcile copy) {
         ofmWithSwDpid =
-            new OFMatchWithSwDpid(copy.ofmWithSwDpid.getOfMatch(),
-                    copy.ofmWithSwDpid.getSwitchDataPathId());
+            new OFMatchWithSwDpid(copy.ofmWithSwDpid.getMatch(),
+                    copy.ofmWithSwDpid.getDpid());
         priority = copy.priority;
         action = copy.action;
         cookie = copy.cookie;
@@ -119,7 +121,7 @@ public class OFMatchReconcile  {
                  + ((newAppInstName == null) ? 0 : newAppInstName.hashCode());
         result = prime * result
                  + ((ofmWithSwDpid == null) ? 0 : ofmWithSwDpid.hashCode());
-        result = prime * result + outPort;
+        result = prime * result + outPort.getPortNumber();
         result = prime * result + priority;
         result = prime * result
                  + ((rcAction == null) ? 0 : rcAction.hashCode());
diff --git a/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java b/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java
index a2f57bb9cc166e073e2ebacf4b950fdc292b6a12..55e408d88e01cb9bfbf6545cb9b5a23a0d01c6c5 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java
@@ -17,7 +17,6 @@ package net.floodlightcontroller.flowcache;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -25,24 +24,22 @@ import java.util.Map.Entry;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFMatchWithSwDpid;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFStatisticsRequest;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.statistics.OFFlowStatisticsReply;
-import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
-import org.openflow.protocol.statistics.OFStatistics;
-import org.openflow.protocol.statistics.OFStatisticsType;
-import org.openflow.util.HexString;
-import org.openflow.util.U16;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.OFFlowDelete;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -58,6 +55,7 @@ import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.floodlightcontroller.routing.Link;
 import net.floodlightcontroller.topology.ITopologyListener;
 import net.floodlightcontroller.topology.ITopologyService;
+import net.floodlightcontroller.util.OFMatchWithSwDpid;
 
 /**
  * Flow reconciliation module that is triggered by PORT_DOWN events. This module
@@ -74,14 +72,14 @@ public class PortDownReconciliation implements IFloodlightModule,
     protected static Logger log = LoggerFactory.getLogger(PortDownReconciliation.class);
 
     protected ITopologyService topology;
-    protected IFloodlightProviderService floodlightProvider;
+    protected IOFSwitchService switchService;
     protected IFlowReconcileService frm;
     protected ILinkDiscoveryService lds;
     protected Map<Link, LinkInfo> links;
     protected FloodlightContext cntx;
     protected static boolean waiting = false;
     protected int statsQueryXId;
-    protected static List<OFFlowStatisticsReply> statsReply;
+    protected static List<OFFlowStatsReply> statsReply;
 
     // ITopologyListener
     @Override
@@ -91,18 +89,16 @@ public class PortDownReconciliation implements IFloodlightModule,
                    .equals(ILinkDiscovery.UpdateOperation.PORT_DOWN)) {
 
                 // Get the switch ID for the OFMatchWithSwDpid object
-                long affectedSwitch = floodlightProvider.getSwitch(ldu.getSrc())
-                                                        .getId();
+                IOFSwitch affectedSwitch = switchService.getSwitch(ldu.getSrc());
 
                 // Create an OFMatchReconcile object
                 OFMatchReconcile ofmr = new OFMatchReconcile();
 
                 // Generate an OFMatch objects for the OFMatchWithSwDpid object
-                OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
+                Match match = affectedSwitch.getOFFactory().buildMatch().build(); // nothing specific set, so all wildcarded
 
                 // Generate the OFMatchWithSwDpid
-                OFMatchWithSwDpid ofmatchsw = new OFMatchWithSwDpid(match,
-                                                                    affectedSwitch);
+                OFMatchWithSwDpid ofmatchsw = new OFMatchWithSwDpid(match, affectedSwitch.getId());
 
                 // Set the action to update the path to remove flows routing
                 // towards the downed port
@@ -150,7 +146,7 @@ public class PortDownReconciliation implements IFloodlightModule,
             void
             init(FloodlightModuleContext context)
                                                  throws FloodlightModuleException {
-        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+        switchService = context.getServiceImpl(IOFSwitchService.class);
         topology = context.getServiceImpl(ITopologyService.class);
         frm = context.getServiceImpl(IFlowReconcileService.class);
         lds = context.getServiceImpl(ILinkDiscoveryService.class);
@@ -185,8 +181,7 @@ public class PortDownReconciliation implements IFloodlightModule,
      * @return the Command whether to STOP or Continue
      */
     @Override
-    public net.floodlightcontroller.core.IListener.Command
-            reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList) {
+    public net.floodlightcontroller.core.IListener.Command reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList) {
         if (lds != null) {
             links = new HashMap<Link, LinkInfo>();
             // Get all the switch links from the topology
@@ -197,38 +192,37 @@ public class PortDownReconciliation implements IFloodlightModule,
                 // update the path to a switch
                 if (ofmr.rcAction.equals(OFMatchReconcile.ReconcileAction.UPDATE_PATH)) {
                     // Get the switch object from the OFMatchReconcile
-                    IOFSwitch sw = floodlightProvider
-                            .getSwitch(ofmr.ofmWithSwDpid.getSwitchDataPathId());
+                    IOFSwitch sw = switchService.getSwitch(ofmr.ofmWithSwDpid.getDpid());
 
                     // Map data structure that holds the invalid matches and the
                     // ingress ports of those matches
-                    Map<Short, List<OFMatch>> invalidBaseIngressAndMatches = new HashMap<Short, List<OFMatch>>();
+                    Map<OFPort, List<Match>> invalidBaseIngressAndMatches = new HashMap<OFPort, List<Match>>();
 
                     // Get the invalid flows
-                    List<OFFlowStatisticsReply> flows = getFlows(sw,
-                                                                 ofmr.outPort);
+                    List<OFFlowStatsReply> flows = getFlows(sw, ofmr.outPort);
 
                     // Analyze all the flows with outPorts equaling the downed
                     // port and extract OFMatch's to trace back to neighbors
-                    for (OFFlowStatisticsReply flow : flows) {
-                        // Create a reference to the match for ease
-                        OFMatch match = flow.getMatch();
-
-                        // Here we utilize an index of input ports which point
-                        // to multiple invalid matches
-                        if (invalidBaseIngressAndMatches.containsKey(match.getInputPort()))
-                            // If the input port is already in the index, add
-                            // the match to it's list
-                            invalidBaseIngressAndMatches.get(match.getInputPort())
-                                                        .add(match);
-                        else {
-                            // Otherwise create a new list and add it to the
-                            // index
-                            List<OFMatch> matches = new ArrayList<OFMatch>();
-                            matches.add(match);
-                            invalidBaseIngressAndMatches.put(match.getInputPort(),
-                                                             matches);
-                        }
+                    for (OFFlowStatsReply flow : flows) {
+                    	// Create a reference to the match for ease
+                    	for (OFFlowStatsEntry entry : flow.getEntries()) {
+                    		Match match = entry.getMatch();
+
+                    		// Here we utilize an index of input ports which point
+                    		// to multiple invalid matches
+                    		if (invalidBaseIngressAndMatches.containsKey(match.get(MatchField.IN_PORT)))
+                    			// If the input port is already in the index, add
+                    			// the match to it's list
+                    			invalidBaseIngressAndMatches.get(match.get(MatchField.IN_PORT))
+                    			.add(match);
+                    		else {
+                    			// Otherwise create a new list and add it to the
+                    			// index
+                    			List<Match> matches = new ArrayList<Match>();
+                    			matches.add(match);
+                    			invalidBaseIngressAndMatches.put(match.get(MatchField.IN_PORT), matches);
+                    		}
+                    	}
                     }
 
                     // Remove invalid flows from the base switch, if they exist
@@ -240,7 +234,7 @@ public class PortDownReconciliation implements IFloodlightModule,
 
                     // Create a list of neighboring switches we need to remove
                     // invalid flows from
-                    Map<IOFSwitch, Map<Short, List<OFMatch>>> neighborSwitches = new HashMap<IOFSwitch, Map<Short, List<OFMatch>>>();
+                    Map<IOFSwitch, Map<OFPort, List<Match>>> neighborSwitches = new HashMap<IOFSwitch, Map<OFPort, List<Match>>>();
 
                     // Loop through all the links
                     for (Link link : links.keySet()) {
@@ -248,20 +242,19 @@ public class PortDownReconciliation implements IFloodlightModule,
                         if (link.getDst() == sw.getId()) {
                             // Loop through the links to neighboring switches
                             // which have invalid flows
-                            for (Entry<Short, List<OFMatch>> invalidBaseIngressAndMatch : invalidBaseIngressAndMatches.entrySet()) {
+                            for (Entry<OFPort, List<Match>> invalidBaseIngressAndMatch : invalidBaseIngressAndMatches.entrySet()) {
                                 // Find links on the network which link to the
                                 // ingress ports that have invalidly routed
                                 // flows
                                 if (link.getDstPort() == invalidBaseIngressAndMatch.getKey()) {
-                                    Map<Short, List<OFMatch>> invalidNeighborOutportAndMatch = new HashMap<Short, List<OFMatch>>();
+                                    Map<OFPort, List<Match>> invalidNeighborOutportAndMatch = new HashMap<OFPort, List<Match>>();
                                     // Insert the neighbor's outPort to the base
                                     // switch and the invalid match
                                     invalidNeighborOutportAndMatch.put(link.getSrcPort(),
                                                                        invalidBaseIngressAndMatch.getValue());
                                     // Link a neighbor switch's invalid match
                                     // and outport to their Switch object
-                                    neighborSwitches.put(floodlightProvider.getSwitch(link.getSrc()),
-                                                         invalidNeighborOutportAndMatch);
+                                    neighborSwitches.put(switchService.getSwitch(link.getSrc()), invalidNeighborOutportAndMatch);
                                 }
                             }
                         }
@@ -271,11 +264,9 @@ public class PortDownReconciliation implements IFloodlightModule,
                     // Loop through all the switches we found to have potential
                     // issues
                     for (IOFSwitch neighborSwitch : neighborSwitches.keySet()) {
-                        log.debug("NeighborSwitch ID : "
-                                  + neighborSwitch.getId());
+                        log.debug("NeighborSwitch ID : " + neighborSwitch.getId());
                         if (neighborSwitches.get(neighborSwitch) != null)
-                                                                         deleteInvalidFlows(neighborSwitch,
-                                                                                            neighborSwitches.get(neighborSwitch));
+                             deleteInvalidFlows(neighborSwitch, neighborSwitches.get(neighborSwitch));
                     }
                 }
                 return Command.CONTINUE;
@@ -293,31 +284,26 @@ public class PortDownReconciliation implements IFloodlightModule,
      *            the output action port we wish to find flows with
      * @return a list of OFFlowStatisticsReply objects or essentially flows
      */
-    public List<OFFlowStatisticsReply> getFlows(IOFSwitch sw, Short outPort) {
+    public List<OFFlowStatsReply> getFlows(IOFSwitch sw, OFPort outPort) {
 
-        statsReply = new ArrayList<OFFlowStatisticsReply>();
-        List<OFStatistics> values = null;
-        Future<List<OFStatistics>> future;
+        statsReply = new ArrayList<OFFlowStatsReply>();
+        List<OFFlowStatsReply> values = null;
+        Future<List<OFFlowStatsReply>> future;
 
         // Statistics request object for getting flows
-        OFStatisticsRequest req = new OFStatisticsRequest();
-        req.setStatisticType(OFStatisticsType.FLOW);
-        int requestLength = req.getLengthU();
-        OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest();
-        specificReq.setMatch(new OFMatch().setWildcards(0xffffffff));
-        specificReq.setOutPort(outPort);
-        specificReq.setTableId((byte) 0xff);
-        req.setStatistics(Collections.singletonList((OFStatistics) specificReq));
-        requestLength += specificReq.getLength();
-        req.setLengthU(requestLength);
+        OFFlowStatsRequest req = sw.getOFFactory().buildFlowStatsRequest()
+        		.setMatch(sw.getOFFactory().buildMatch().build())
+        		.setOutPort(outPort)
+        		.setTableId(TableId.ALL) //TODO @Ryan I suppose 0xFF is all tables, maybe not though...
+        		.build();
 
         try {
             // System.out.println(sw.getStatistics(req));
-            future = sw.queryStatistics(req);
+            future = sw.writeStatsRequest(req);
             values = future.get(10, TimeUnit.SECONDS);
             if (values != null) {
-                for (OFStatistics stat : values) {
-                    statsReply.add((OFFlowStatisticsReply) stat);
+                for (OFFlowStatsReply stat : values) {
+                    statsReply.add(stat);
                 }
             }
         } catch (Exception e) {
@@ -334,22 +320,19 @@ public class PortDownReconciliation implements IFloodlightModule,
      *            The specific Output Action OutPort of specific flows we wish
      *            to delete
      */
-    public void clearFlowMods(IOFSwitch sw, Short outPort) {
-        // Delete all pre-existing flows with the same output action port or
-        // outPort
-        OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
-        OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory()
-                                                      .getMessage(OFType.FLOW_MOD)).setMatch(match)
-                                                                                   .setCommand(OFFlowMod.OFPFC_DELETE)
-                                                                                   .setOutPort(outPort)
-                                                                                   .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
-        try {
-            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-            msglist.add(fm);
-            sw.write(msglist, cntx);
-        } catch (Exception e) {
-            log.error("Failed to clear flows on switch {} - {}", this, e);
-        }
+    public void clearFlowMods(IOFSwitch sw, OFPort outPort) {
+    	// Delete all pre-existing flows with the same output action port or
+    	// outPort
+    	Match match = sw.getOFFactory().buildMatch().build();
+    	OFFlowDelete fm = sw.getOFFactory().buildFlowDelete()
+    			.setMatch(match)
+    			.setOutPort(outPort)
+    			.build();
+    	try {
+    		sw.write(fm);
+    	} catch (Exception e) {
+    		log.error("Failed to clear flows on switch {} - {}", this, e);
+    	}
     }
 
     /**
@@ -362,19 +345,15 @@ public class PortDownReconciliation implements IFloodlightModule,
      *            The specific Output Action OutPort of specific flows we wish
      *            to delete
      */
-    public void clearFlowMods(IOFSwitch sw, OFMatch match, Short outPort) {
+    public void clearFlowMods(IOFSwitch sw, Match match, OFPort outPort) {
         // Delete pre-existing flows with the same match, and output action port
         // or outPort
-        match.setWildcards(OFMatch.OFPFW_ALL);
-        OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory()
-                                                      .getMessage(OFType.FLOW_MOD)).setMatch(match)
-                                                                                   .setCommand(OFFlowMod.OFPFC_DELETE)
-                                                                                   .setOutPort(outPort)
-                                                                                   .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
+        OFFlowDelete fm = sw.getOFFactory().buildFlowDelete()
+        		.setMatch(match)
+        		.setOutPort(outPort)
+        		.build();
         try {
-            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-            msglist.add(fm);
-            sw.write(msglist, cntx);
+            sw.write(fm);
         } catch (Exception e) {
             log.error("Failed to clear flows on switch {} - {}", this, e);
         }
@@ -393,91 +372,82 @@ public class PortDownReconciliation implements IFloodlightModule,
      *            the output action port wanted from the flows, which follows
      *            the route to the base switch
      */
-    public
-            void
-            deleteInvalidFlows(IOFSwitch sw,
-                               Map<Short, List<OFMatch>> invalidOutportAndMatch) {
+    public void deleteInvalidFlows(IOFSwitch sw, Map<OFPort, List<Match>> invalidOutportAndMatch) {
         log.debug("Deleting invalid flows on switch : " + sw.getId());
 
         // A map that holds the input ports and invalid matches on a switch
-        Map<Short, List<OFMatch>> invalidNeighborIngressAndMatches = new HashMap<Short, List<OFMatch>>();
+        Map<OFPort, List<Match>> invalidNeighborIngressAndMatches = new HashMap<OFPort, List<Match>>();
 
-        for (Short outPort : invalidOutportAndMatch.keySet()) {
+        for (OFPort outPort : invalidOutportAndMatch.keySet()) {
             // Get the flows on the switch
-            List<OFFlowStatisticsReply> flows = getFlows(sw, outPort);
+            List<OFFlowStatsReply> flows = getFlows(sw, outPort);
 
             // Analyze all the flows with outPorts pointing to problematic route
-            for (OFFlowStatisticsReply flow : flows) {
-                // Loop through all the problematic matches
-                for (OFMatch match : invalidOutportAndMatch.get(outPort)) {
-                    // Compare the problematic matches with the match of the
-                    // flow on the switch
-                    if (HexString.toHexString(flow.getMatch()
-                                                  .getDataLayerDestination())
-                                 .equals(HexString.toHexString(match.getDataLayerDestination()))
-                        && HexString.toHexString(flow.getMatch()
-                                                     .getDataLayerSource())
-                                    .equals(HexString.toHexString(match.getDataLayerSource()))
-                        && flow.getMatch().getDataLayerType() == match.getDataLayerType()
-                        && flow.getMatch().getDataLayerVirtualLan() == match.getDataLayerVirtualLan()
-                        && flow.getMatch().getNetworkDestination() == match.getNetworkDestination()
-                        && flow.getMatch().getNetworkDestinationMaskLen() == match.getNetworkDestinationMaskLen()
-                        && flow.getMatch().getNetworkProtocol() == match.getNetworkProtocol()
-                        && flow.getMatch().getNetworkSource() == match.getNetworkSource()
-                        && flow.getMatch().getNetworkSourceMaskLen() == match.getNetworkSourceMaskLen()
-                        && flow.getMatch().getNetworkTypeOfService() == match.getNetworkTypeOfService()) {
-
-                        // Here we utilize an index of input ports which point
-                        // to multiple invalid matches
-                        if (invalidNeighborIngressAndMatches.containsKey(match.getInputPort()))
-                            // If the input port is already in the index, add
-                            // the match to it's list
-                            invalidNeighborIngressAndMatches.get(match.getInputPort())
-                                                            .add(match);
-                        else {
-                            // Otherwise create a new list and add it to the
-                            // index
-                            List<OFMatch> matches = new ArrayList<OFMatch>();
-                            matches.add(match);
-                            invalidNeighborIngressAndMatches.put(match.getInputPort(),
-                                                                 matches);
-                        }
-                        // Remove flows from the switch with the invalid match
-                        // and outPort
-                        clearFlowMods(sw, flow.getMatch(), outPort);
-                    }
-                }
+            for (OFFlowStatsReply flow : flows) {
+            	for (OFFlowStatsEntry entry : flow.getEntries()) {
+            		// Loop through all the problematic matches
+            		for (Match match : invalidOutportAndMatch.get(outPort)) {
+            			// Compare the problematic matches with the match of the
+            			// flow on the switch
+            			if (entry.getMatch().get(MatchField.ETH_DST).equals(match.get(MatchField.ETH_DST))
+            				&& entry.getMatch().get(MatchField.ETH_SRC).equals(match.get(MatchField.ETH_SRC))
+            				&& entry.getMatch().get(MatchField.ETH_TYPE).equals(match.get(MatchField.ETH_TYPE))
+            				&& entry.getMatch().get(MatchField.VLAN_VID).equals(match.get(MatchField.VLAN_VID))
+            				&& entry.getMatch().get(MatchField.IPV4_DST).equals(match.get(MatchField.IPV4_DST)) //TODO @Ryan mask lengths built into the MatchField for IPV4, I think
+            				&& entry.getMatch().get(MatchField.IP_PROTO).equals(match.get(MatchField.IP_PROTO))
+            				&& entry.getMatch().get(MatchField.IPV4_SRC).equals(match.get(MatchField.IPV4_SRC)) // same here I think
+            				&& entry.getMatch().get(MatchField.IP_DSCP).equals(match.get(MatchField.IP_DSCP)) // dscp and ecn replace tos
+            				&& entry.getMatch().get(MatchField.IP_ECN).equals(match.get(MatchField.IP_ECN))) {
+
+            					// Here we utilize an index of input ports which point
+            					// to multiple invalid matches
+            					if (invalidNeighborIngressAndMatches.containsKey(match.get(MatchField.IN_PORT)))
+            						// If the input port is already in the index, add
+            						// the match to it's list
+            						invalidNeighborIngressAndMatches.get(match.get(MatchField.IN_PORT))
+            						.add(match);
+            					else {
+            						// Otherwise create a new list and add it to the
+            						// index
+            						List<Match> matches = new ArrayList<Match>();
+            						matches.add(match);
+            						invalidNeighborIngressAndMatches.put(match.get(MatchField.IN_PORT), matches);
+            					}
+            					// Remove flows from the switch with the invalid match
+            					// and outPort
+            					clearFlowMods(sw, entry.getMatch(), outPort);
+            				}
+            		}
+            	}
             }
 
             // Create a list of neighboring switches we need to check for
             // invalid flows
-            Map<IOFSwitch, Map<Short, List<OFMatch>>> neighborSwitches = new HashMap<IOFSwitch, Map<Short, List<OFMatch>>>();
+            Map<IOFSwitch, Map<OFPort, List<Match>>> neighborSwitches = new HashMap<IOFSwitch, Map<OFPort, List<Match>>>();
 
             // Loop through all the links
             for (Link link : links.keySet()) {
                 // Filter out links we care about
-                if (link.getDst() == sw.getId()) {
+                if (link.getDst().equals(sw.getId())) {
                     // Loop through the ingressPorts that are involved in
                     // invalid flows on neighboring switches
-                    for (Entry<Short, List<OFMatch>> ingressPort : invalidNeighborIngressAndMatches.entrySet()) {
+                    for (Entry<OFPort, List<Match>> ingressPort : invalidNeighborIngressAndMatches.entrySet()) {
                         // Filter out invalid links by matching the link
                         // destination port to our invalid flows ingress port
-                        if (link.getDstPort() == ingressPort.getKey()) {
+                        if (link.getDstPort().equals(ingressPort.getKey())) {
                             // Generate a match and outPort map since I don't
                             // want to create an object
-                            Map<Short, List<OFMatch>> invalidNeighborOutportAndMatch = new HashMap<Short, List<OFMatch>>();
+                            Map<OFPort, List<Match>> invalidNeighborOutportAndMatch = new HashMap<OFPort, List<Match>>();
                             invalidNeighborOutportAndMatch.put(link.getSrcPort(),
                                                                ingressPort.getValue());
                             // Link a neighbor switch's invalid match and
                             // outport to their Switch object
-                            neighborSwitches.put(floodlightProvider.getSwitch(link.getSrc()),
-                                                 invalidNeighborOutportAndMatch);
+                            neighborSwitches.put(switchService.getSwitch(link.getSrc()), invalidNeighborOutportAndMatch);
                         }
                     }
                 }
             }
-            log.debug("We have " + neighborSwitches.size()
-                      + " neighbors to deal with!");
+            log.debug("We have " + neighborSwitches.size() + " neighbors to deal with!");
 
             // Loop through all the neighbor switches we found to have
             // invalid matches
@@ -485,8 +455,7 @@ public class PortDownReconciliation implements IFloodlightModule,
                 log.debug("NeighborSwitch ID : " + neighborSwitch.getId());
                 // Recursively seek out and delete invalid flows on the
                 // neighbor switch
-                deleteInvalidFlows(neighborSwitch,
-                                   neighborSwitches.get(neighborSwitch));
+                deleteInvalidFlows(neighborSwitch, neighborSwitches.get(neighborSwitch));
             }
         }
     }
diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
index 588e8bc3123336bf3fa7bab8a421e5ce17ff456c..abf899c9ca8e8fa160e7cb9f0197ea2e6bef4ff5 100644
--- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
@@ -1,19 +1,19 @@
 /**
-*    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.
-**/
+ *    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.forwarding;
 
@@ -33,393 +33,422 @@ 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;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.util.AppCookie;
-import net.floodlightcontroller.counter.ICounterStoreService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
 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.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.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketOut;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.types.VlanVid;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @LogMessageCategory("Flow Programming")
 public class Forwarding extends ForwardingBase implements IFloodlightModule {
-    protected static Logger log = LoggerFactory.getLogger(Forwarding.class);
-
-    @Override
-    @LogMessageDoc(level="ERROR",
-                   message="Unexpected decision made for this packet-in={}",
-                   explanation="An unsupported PacketIn decision has been " +
-                   		"passed to the flow programming component",
-                   recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision,
-                                          FloodlightContext cntx) {
-        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
-                                   IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-
-        // If a decision has been made we obey it
-        // otherwise we just forward
-        if (decision != null) {
-            if (log.isTraceEnabled()) {
-                log.trace("Forwaring decision={} was made for PacketIn={}",
-                        decision.getRoutingAction().toString(),
-                        pi);
-            }
-
-            switch(decision.getRoutingAction()) {
-                case NONE:
-                    // don't do anything
-                    return Command.CONTINUE;
-                case FORWARD_OR_FLOOD:
-                case FORWARD:
-                    doForwardFlow(sw, pi, cntx, false);
-                    return Command.CONTINUE;
-                case MULTICAST:
-                    // treat as broadcast
-                    doFlood(sw, pi, cntx);
-                    return Command.CONTINUE;
-                case DROP:
-                    doDropFlow(sw, pi, decision, cntx);
-                    return Command.CONTINUE;
-                default:
-                    log.error("Unexpected decision made for this packet-in={}",
-                            pi, decision.getRoutingAction());
-                    return Command.CONTINUE;
-            }
-        } else {
-            if (log.isTraceEnabled()) {
-                log.trace("No decision was made for PacketIn={}, forwarding",
-                        pi);
-            }
-
-            if (eth.isBroadcast() || eth.isMulticast()) {
-                // For now we treat multicast as broadcast
-                doFlood(sw, pi, cntx);
-            } else {
-                doForwardFlow(sw, pi, cntx, false);
-            }
-        }
-
-        return Command.CONTINUE;
-    }
-
-    @LogMessageDoc(level="ERROR",
-            message="Failure writing drop flow mod",
-            explanation="An I/O error occured while trying to write a " +
-            		"drop flow mod to a switch",
-            recommendation=LogMessageDoc.CHECK_SWITCH)
-    protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
-        // initialize match structure and populate it using the packet
-        OFMatch match = new OFMatch();
-        match.loadFromPacket(pi.getPacketData(), pi.getInPort());
-        if (decision.getWildcards() != null) {
-            match.setWildcards(decision.getWildcards());
-        }
-
-        // Create flow-mod based on packet-in and src-switch
-        OFFlowMod fm =
-                (OFFlowMod) floodlightProvider.getOFMessageFactory()
-                                              .getMessage(OFType.FLOW_MOD);
-        List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to
-                                                            // drop
-        long cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
-
-        fm.setCookie(cookie)
-          .setHardTimeout((short) 0)
-          .setIdleTimeout((short) 5)
-          .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-          .setMatch(match)
-          .setActions(actions)
-          .setLengthU(OFFlowMod.MINIMUM_LENGTH); // +OFActionOutput.MINIMUM_LENGTH);
-
-        try {
-            if (log.isDebugEnabled()) {
-                log.debug("write drop flow-mod sw={} match={} flow-mod={}",
-                          new Object[] { sw, match, fm });
-            }
-            messageDamper.write(sw, fm, cntx);
-        } catch (IOException e) {
-            log.error("Failure writing drop flow mod", e);
-        }
-    }
-
-    protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi,
-                                 FloodlightContext cntx,
-                                 boolean requestFlowRemovedNotifn) {
-        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);
-
-        if (dstDevice != null) {
-            IDevice srcDevice =
-                    IDeviceService.fcStore.
-                        get(cntx, IDeviceService.CONTEXT_SRC_DEVICE);
-            Long srcIsland = topology.getL2DomainId(sw.getId());
-
-            if (srcDevice == null) {
-                log.debug("No device entry found for source device");
-                return;
-            }
-            if (srcIsland == null) {
-                log.debug("No openflow island found for source {}/{}",
-                          sw.getStringId(), pi.getInPort());
-                return;
-            }
-
-            // Validate that we have a destination known on the same island
-            // 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()) {
-                long dstSwDpid = dstDap.getSwitchDPID();
-                Long dstIsland = topology.getL2DomainId(dstSwDpid);
-                if ((dstIsland != null) && dstIsland.equals(srcIsland)) {
-                    on_same_island = true;
-                    if ((sw.getId() == dstSwDpid) &&
-                        (pi.getInPort() == dstDap.getPort())) {
-                        on_same_if = true;
-                    }
-                    break;
-                }
-            }
-
-            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);
-                }
-                doFlood(sw, pi, cntx);
-                return;
-            }
-
-            if (on_same_if) {
-                if (log.isTraceEnabled()) {
-                    log.trace("Both source and destination are on the same " +
-                              "switch/port {}/{}, Action = NOP",
-                              sw.toString(), pi.getInPort());
-                }
-                return;
-            }
-
-            // Install all the routes where both src and dst have attachment
-            // points.  Since the lists are stored in sorted order we can
-            // traverse the attachment points in O(m+n) time
-            SwitchPort[] srcDaps = srcDevice.getAttachmentPoints();
-            Arrays.sort(srcDaps, clusterIdComparator);
-            SwitchPort[] dstDaps = dstDevice.getAttachmentPoints();
-            Arrays.sort(dstDaps, clusterIdComparator);
-
-            int iSrcDaps = 0, iDstDaps = 0;
-
-            while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) {
-                SwitchPort srcDap = srcDaps[iSrcDaps];
-                SwitchPort dstDap = dstDaps[iDstDaps];
-
-                // srcCluster and dstCluster here cannot be null as
-                // every switch will be at least in its own L2 domain.
-                Long srcCluster =
-                        topology.getL2DomainId(srcDap.getSwitchDPID());
-                Long dstCluster =
-                        topology.getL2DomainId(dstDap.getSwitchDPID());
-
-                int srcVsDest = srcCluster.compareTo(dstCluster);
-                if (srcVsDest == 0) {
-                    if (!srcDap.equals(dstDap)) {
-                        Route route =
-                                routingEngine.getRoute(srcDap.getSwitchDPID(),
-                                                       (short)srcDap.getPort(),
-                                                       dstDap.getSwitchDPID(),
-                                                       (short)dstDap.getPort(), 0); //cookie = 0, i.e., default route
-                        if (route != null) {
-                            if (log.isTraceEnabled()) {
-                                log.trace("pushRoute match={} route={} " +
-                                          "destination={}:{}",
-                                          new Object[] {match, route,
-                                                        dstDap.getSwitchDPID(),
-                                                        dstDap.getPort()});
-                            }
-                            long cookie =
-                                    AppCookie.makeCookie(FORWARDING_APP_ID, 0);
-
-                            // if there is prior routing decision use wildcard
-                            Integer wildcard_hints = null;
-                            IRoutingDecision decision = null;
-                            if (cntx != null) {
-                                decision = IRoutingDecision.rtStore
-                                        .get(cntx,
-                                                IRoutingDecision.CONTEXT_DECISION);
-                            }
-                            if (decision != null) {
-                                wildcard_hints = decision.getWildcards();
-                            } else {
-                            	// L2 only wildcard if there is no prior route decision
-                                wildcard_hints = ((Integer) sw
-                                        .getAttribute(IOFSwitch.PROP_FASTWILDCARDS))
-                                        .intValue()
-                                        & ~OFMatch.OFPFW_IN_PORT
-                                        & ~OFMatch.OFPFW_DL_VLAN
-                                        & ~OFMatch.OFPFW_DL_SRC
-                                        & ~OFMatch.OFPFW_DL_DST
-                                        & ~OFMatch.OFPFW_NW_SRC_MASK
-                                        & ~OFMatch.OFPFW_NW_DST_MASK;
-                            }
-
-                            pushRoute(route, match, wildcard_hints, pi, sw.getId(), cookie,
-                                      cntx, requestFlowRemovedNotifn, false,
-                                      OFFlowMod.OFPFC_ADD);
-                        }
-                    }
-                    iSrcDaps++;
-                    iDstDaps++;
-                } else if (srcVsDest < 0) {
-                    iSrcDaps++;
-                } else {
-                    iDstDaps++;
-                }
-            }
-        } else {
-            // Flood since we don't know the dst device
-            doFlood(sw, pi, cntx);
-        }
-    }
-
-    /**
-     * Creates a OFPacketOut with the OFPacketIn data that is flooded on all ports unless
-     * the port is blocked, in which case the packet will be dropped.
-     * @param sw The switch that receives the OFPacketIn
-     * @param pi The OFPacketIn that came to the switch
-     * @param cntx The FloodlightContext associated with this OFPacketIn
-     */
-    @LogMessageDoc(level="ERROR",
-                   message="Failure writing PacketOut " +
-                   		"switch={switch} packet-in={packet-in} " +
-                   		"packet-out={packet-out}",
-                   explanation="An I/O error occured while writing a packet " +
-                   		"out message to the switch",
-                   recommendation=LogMessageDoc.CHECK_SWITCH)
-    protected void doFlood(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
-        if (topology.isIncomingBroadcastAllowed(sw.getId(),
-                                                pi.getInPort()) == false) {
-            if (log.isTraceEnabled()) {
-                log.trace("doFlood, drop broadcast packet, pi={}, " +
-                          "from a blocked port, srcSwitch=[{},{}], linkInfo={}",
-                          new Object[] {pi, sw.getId(),pi.getInPort()});
-            }
-            return;
-        }
-
-        // Set Action to flood
-        OFPacketOut po =
-            (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
-        List<OFAction> actions = new ArrayList<OFAction>();
-        if (sw.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) {
-            actions.add(new OFActionOutput(OFPort.OFPP_FLOOD.getValue(),
-                                           (short)0xFFFF));
-        } else {
-            actions.add(new OFActionOutput(OFPort.OFPP_ALL.getValue(),
-                                           (short)0xFFFF));
-        }
-        po.setActions(actions);
-        po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
-
-        // set buffer-id, in-port and packet-data based on packet-in
-        short poLength = (short)(po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
-        po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
-        po.setInPort(pi.getInPort());
-        byte[] packetData = pi.getPacketData();
-        poLength += packetData.length;
-        po.setPacketData(packetData);
-        po.setLength(poLength);
-
-        try {
-            if (log.isTraceEnabled()) {
-                log.trace("Writing flood PacketOut switch={} packet-in={} packet-out={}",
-                          new Object[] {sw, pi, po});
-            }
-            messageDamper.write(sw, po, cntx);
-        } catch (IOException e) {
-            log.error("Failure writing PacketOut switch={} packet-in={} packet-out={}",
-                    new Object[] {sw, pi, po}, e);
-        }
-
-        return;
-    }
-
-    // IFloodlightModule methods
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        // We don't export any services
-        return null;
-    }
-
-    @Override
-    public Map<Class<? extends IFloodlightService>, IFloodlightService>
-            getServiceImpls() {
-        // We don't have any services
-        return null;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
-        Collection<Class<? extends IFloodlightService>> l =
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IFloodlightProviderService.class);
-        l.add(IDeviceService.class);
-        l.add(IRoutingService.class);
-        l.add(ITopologyService.class);
-        l.add(ICounterStoreService.class);
-        return l;
-    }
-
-    @Override
-    @LogMessageDocs({
-        @LogMessageDoc(level="WARN",
-                message="Error parsing flow idle timeout, " +
-                        "using default of {number} seconds",
-                explanation="The properties file contains an invalid " +
-                        "flow idle timeout",
-                recommendation="Correct the idle timeout in the " +
-                        "properties file."),
-        @LogMessageDoc(level="WARN",
-                message="Error parsing flow hard timeout, " +
-                        "using default of {number} seconds",
-                explanation="The properties file contains an invalid " +
-                            "flow hard timeout",
-                recommendation="Correct the hard timeout in the " +
-                                "properties file.")
-    })
-    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
-        super.init();
-        this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-        this.deviceManager = context.getServiceImpl(IDeviceService.class);
-        this.routingEngine = context.getServiceImpl(IRoutingService.class);
-        this.topology = context.getServiceImpl(ITopologyService.class);
-        this.counterStore = context.getServiceImpl(ICounterStoreService.class);
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        super.startUp();
-    }
-}
+	protected static Logger log = LoggerFactory.getLogger(Forwarding.class);
+
+	protected static int DEFAULT_HARD_TIMEOUT = 0; // not final b/c could be configured from config file
+	protected static int DEFAULT_IDLE_TIMEOUT = 5;
+
+	@Override
+	@LogMessageDoc(level="ERROR",
+	message="Unexpected decision made for this packet-in={}",
+	explanation="An unsupported PacketIn decision has been " +
+			"passed to the flow programming component",
+			recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+	public Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
+		Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+
+		// We found a routing decision (i.e. Firewall is enabled... it's the only thing that makes RoutingDecisions)
+		if (decision != null) {
+			if (log.isTraceEnabled()) {
+				log.trace("Forwaring decision={} was made for PacketIn={}", decision.getRoutingAction().toString(), pi);
+			}
+
+			switch(decision.getRoutingAction()) {
+			case NONE:
+				// don't do anything
+				return Command.CONTINUE;
+			case FORWARD_OR_FLOOD:
+			case FORWARD:
+				doForwardFlow(sw, pi, cntx, false);
+				return Command.CONTINUE;
+			case MULTICAST:
+				// treat as broadcast
+				doFlood(sw, pi, cntx);
+				return Command.CONTINUE;
+			case DROP:
+				doDropFlow(sw, pi, decision, cntx);
+				return Command.CONTINUE;
+			default:
+				log.error("Unexpected decision made for this packet-in={}", pi, decision.getRoutingAction());
+				return Command.CONTINUE;
+			}
+		} else { // No routing decision was found. Forward to destination or flood if bcast or mcast.
+			if (log.isTraceEnabled()) {
+				log.trace("No decision was made for PacketIn={}, forwarding", pi);
+			}
+
+			if (eth.isBroadcast() || eth.isMulticast()) {
+				doFlood(sw, pi, cntx);
+			} else {
+				doForwardFlow(sw, pi, cntx, false);
+			}
+		}
+
+		return Command.CONTINUE;
+	}
+
+	@LogMessageDoc(level="ERROR",
+			message="Failure writing drop flow mod",
+			explanation="An I/O error occured while trying to write a " +
+					"drop flow mod to a switch",
+					recommendation=LogMessageDoc.CHECK_SWITCH)
+	protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
+		// initialize match structure and populate it based on the packet in's match
+		Match.Builder mb = null;
+		if (decision.getMatch() != null) {
+			/* TODO @Ryan This routing decision should be a match object with all appropriate fields set,
+			 * not just masked. If it's a decision that matches the packet we received, then simply setting
+			 * the masks to the new match will create the same match in the end. We can just use the routing
+			 * match object instead (right?).
+			 * 
+			 * The Firewall is currently the only module/service that sets routing decisions in the context 
+			 * store (or instantiates any for that matter). It's disabled by default, so as-is a decision's 
+			 * match should always be null, meaning this will never be true.
+			 */
+			mb = decision.getMatch().createBuilder();
+		} else {
+			mb = pi.getMatch().createBuilder(); // otherwise no route is known so go based on packet's match object
+		}
+
+		OFFlowMod.Builder fmb = sw.getOFFactory().buildFlowAdd(); // this will be a drop-flow; a flow that will not output to any ports
+		List<OFAction> actions = new ArrayList<OFAction>(); // set no action to drop
+		U64 cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
+
+		fmb.setCookie(cookie)
+		.setHardTimeout(DEFAULT_HARD_TIMEOUT)
+		.setIdleTimeout(DEFAULT_IDLE_TIMEOUT)
+		.setBufferId(OFBufferId.NO_BUFFER)
+		.setMatch(mb.build())
+		.setActions(actions); // empty list
+
+		try {
+			if (log.isDebugEnabled()) {
+				log.debug("write drop flow-mod sw={} match={} flow-mod={}",
+						new Object[] { sw, mb.build(), fmb.build() });
+			}
+			boolean dampened = messageDamper.write(sw, fmb.build(), cntx);
+			log.debug("OFMessage dampened: {}", dampened);
+		} catch (IOException e) {
+			log.error("Failure writing drop flow mod", e);
+		}
+	}
+
+	protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, boolean requestFlowRemovedNotifn) {
+		OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
+		// Check if we have the location of the destination
+		IDevice dstDevice = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE);
+
+		if (dstDevice != null) {
+			IDevice srcDevice = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_SRC_DEVICE);
+			DatapathId srcIsland = topologyService.getL2DomainId(sw.getId());
+
+			if (srcDevice == null) {
+				log.debug("No device entry found for source device");
+				return;
+			}
+			if (srcIsland == null) {
+				log.debug("No openflow island found for source {}/{}",
+						sw.getId().toString(), (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+				return;
+			}
+
+			// Validate that we have a destination known on the same island
+			// 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 = topologyService.getL2DomainId(dstSwDpid);
+				if ((dstIsland != null) && dstIsland.equals(srcIsland)) {
+					on_same_island = true;
+					if ((sw.getId().equals(dstSwDpid)) && ((pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)).equals(dstDap.getPort()))) {
+						on_same_if = true;
+					}
+					break;
+				}
+			}
+
+			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);
+				}
+				doFlood(sw, pi, cntx);
+				return;
+			}
+
+			if (on_same_if) {
+				if (log.isTraceEnabled()) {
+					log.trace("Both source and destination are on the same " +
+							"switch/port {}/{}, Action = NOP",
+							sw.toString(), (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+				}
+				return;
+			}
+
+			// Install all the routes where both src and dst have attachment
+			// points.  Since the lists are stored in sorted order we can
+			// traverse the attachment points in O(m+n) time
+			SwitchPort[] srcDaps = srcDevice.getAttachmentPoints();
+			Arrays.sort(srcDaps, clusterIdComparator);
+			SwitchPort[] dstDaps = dstDevice.getAttachmentPoints();
+			Arrays.sort(dstDaps, clusterIdComparator);
+
+			int iSrcDaps = 0, iDstDaps = 0;
+
+			while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) {
+				SwitchPort srcDap = srcDaps[iSrcDaps];
+				SwitchPort dstDap = dstDaps[iDstDaps];
+
+				// srcCluster and dstCluster here cannot be null as
+				// every switch will be at least in its own L2 domain.
+				DatapathId srcCluster = topologyService.getL2DomainId(srcDap.getSwitchDPID());
+				DatapathId dstCluster = topologyService.getL2DomainId(dstDap.getSwitchDPID());
+
+				int srcVsDest = srcCluster.compareTo(dstCluster);
+				if (srcVsDest == 0) {
+					if (!srcDap.equals(dstDap)) {
+						Route route =
+								routingEngineService.getRoute(srcDap.getSwitchDPID(), 
+										srcDap.getPort(),
+										dstDap.getSwitchDPID(),
+										dstDap.getPort(), U64.of(0)); //cookie = 0, i.e., default route
+										if (route != null) {
+											if (log.isTraceEnabled()) {
+												log.trace("pushRoute inPort={} route={} " +
+														"destination={}:{}",
+														new Object[] { inPort, route,
+														dstDap.getSwitchDPID(),
+														dstDap.getPort()});
+											}
+											U64 cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
+
+											// if there is prior routing decision use route's match
+											Match routeMatch = null;
+											IRoutingDecision decision = null;
+											if (cntx != null) {
+												decision = IRoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+											}
+											if (decision != null) {
+												routeMatch = decision.getMatch();
+											} else {
+												// The packet in match will only contain the port number.
+												// We need to add in specifics for the hosts we're routing between.
+												Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+												VlanVid vlan = VlanVid.ofVlan(eth.getVlanID());
+												MacAddress srcMac = eth.getSourceMACAddress();
+												MacAddress dstMac = eth.getDestinationMACAddress();
+												
+												// A retentive builder will remember all MatchFields of the parent the builder was generated from
+												// With a normal builder, all parent MatchFields will be lost if any MatchFields are added, mod, del
+												Match.Builder mb = sw.getOFFactory().buildMatch();
+												mb.setExact(MatchField.IN_PORT, inPort)
+												.setExact(MatchField.ETH_SRC, srcMac)
+												.setExact(MatchField.ETH_DST, dstMac);
+												
+												if (!vlan.equals(VlanVid.ZERO)) {
+													mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlanVid(vlan));
+												}
+												
+												if (eth.getEtherType() == Ethernet.TYPE_IPv4) {
+													IPv4 ip = (IPv4) eth.getPayload();
+													IPv4Address srcIp = ip.getSourceAddress();
+													IPv4Address dstIp = ip.getDestinationAddress();
+													mb.setExact(MatchField.IPV4_SRC, srcIp)
+													.setExact(MatchField.IPV4_DST, dstIp)
+													.setExact(MatchField.ETH_TYPE, EthType.IPv4);
+												} else if (eth.getEtherType() == Ethernet.TYPE_ARP) {
+													mb.setExact(MatchField.ETH_TYPE, EthType.ARP);
+												} //TODO @Ryan should probably include other ethertypes
+												
+												routeMatch = mb.build();
+											}
+
+											pushRoute(route, routeMatch, pi, sw.getId(), cookie,
+													cntx, requestFlowRemovedNotifn, false,
+													OFFlowModCommand.ADD);
+										}
+					}
+					iSrcDaps++;
+					iDstDaps++;
+				} else if (srcVsDest < 0) {
+					iSrcDaps++;
+				} else {
+					iDstDaps++;
+				}
+			}
+		} else {
+			// Flood since we don't know the dst device
+			doFlood(sw, pi, cntx);
+		}
+	}
+
+	/**
+	 * Creates a OFPacketOut with the OFPacketIn data that is flooded on all ports unless
+	 * the port is blocked, in which case the packet will be dropped.
+	 * @param sw The switch that receives the OFPacketIn
+	 * @param pi The OFPacketIn that came to the switch
+	 * @param cntx The FloodlightContext associated with this OFPacketIn
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="Failure writing PacketOut " +
+					"switch={switch} packet-in={packet-in} " +
+					"packet-out={packet-out}",
+					explanation="An I/O error occured while writing a packet " +
+							"out message to the switch",
+							recommendation=LogMessageDoc.CHECK_SWITCH)
+	protected void doFlood(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
+		if (topologyService.isIncomingBroadcastAllowed(sw.getId(), (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT))) == false) {
+			if (log.isTraceEnabled()) {
+				log.trace("doFlood, drop broadcast packet, pi={}, " +
+						"from a blocked port, srcSwitch=[{},{}], linkInfo={}",
+						new Object[] {pi, sw.getId(), (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT))});
+			}
+			return;
+		}
+
+		// Set Action to flood
+		OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
+		List<OFAction> actions = new ArrayList<OFAction>();
+		if (sw.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) {
+			actions.add(sw.getOFFactory().actions().output(OFPort.FLOOD, Integer.MAX_VALUE)); // FLOOD is a more selective/efficient version of ALL
+		} else {
+			actions.add(sw.getOFFactory().actions().output(OFPort.ALL, Integer.MAX_VALUE));
+		}
+		pob.setActions(actions);
+
+		// set buffer-id, in-port and packet-data based on packet-in
+		pob.setBufferId(OFBufferId.NO_BUFFER);
+		pob.setInPort((pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+		pob.setData(pi.getData());
+
+		try {
+			if (log.isTraceEnabled()) {
+				log.trace("Writing flood PacketOut switch={} packet-in={} packet-out={}",
+						new Object[] {sw, pi, pob.build()});
+			}
+			messageDamper.write(sw, pob.build(), cntx);
+		} catch (IOException e) {
+			log.error("Failure writing PacketOut switch={} packet-in={} packet-out={}",
+					new Object[] {sw, pi, pob.build()}, e);
+		}
+
+		return;
+	}
+
+	// IFloodlightModule methods
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		// We don't export any services
+		return null;
+	}
+
+	@Override
+	public Map<Class<? extends IFloodlightService>, IFloodlightService>
+	getServiceImpls() {
+		// We don't have any services
+		return null;
+	}
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+		Collection<Class<? extends IFloodlightService>> l =
+				new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(IFloodlightProviderService.class);
+		l.add(IDeviceService.class);
+		l.add(IRoutingService.class);
+		l.add(ITopologyService.class);
+		l.add(IDebugCounterService.class);
+		return l;
+	}
+
+	@Override
+	@LogMessageDocs({
+		@LogMessageDoc(level="WARN",
+				message="Error parsing flow idle timeout, " +
+						"using default of {number} seconds",
+						explanation="The properties file contains an invalid " +
+								"flow idle timeout",
+								recommendation="Correct the idle timeout in the " +
+				"properties file."),
+				@LogMessageDoc(level="WARN",
+				message="Error parsing flow hard timeout, " +
+						"using default of {number} seconds",
+						explanation="The properties file contains an invalid " +
+								"flow hard timeout",
+								recommendation="Correct the hard timeout in the " +
+						"properties file.")
+	})
+	public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+		super.init();
+		this.floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+		this.deviceManagerService = context.getServiceImpl(IDeviceService.class);
+		this.routingEngineService = context.getServiceImpl(IRoutingService.class);
+		this.topologyService = context.getServiceImpl(ITopologyService.class);
+		this.debugCounterService = context.getServiceImpl(IDebugCounterService.class);
+		this.switchService = context.getServiceImpl(IOFSwitchService.class);
+
+		Map<String, String> configParameters = context.getConfigParams(this);
+		String tmp = configParameters.get("hard-timeout");
+		if (tmp != null) {
+			DEFAULT_HARD_TIMEOUT = Integer.parseInt(tmp);
+			log.info("Default hard timeout set to {}.", DEFAULT_HARD_TIMEOUT);
+		} else {
+			log.info("Default hard timeout not configured. Using {}.", DEFAULT_HARD_TIMEOUT);
+		}
+		tmp = configParameters.get("idle-timeout");
+		if (tmp != null) {
+			DEFAULT_IDLE_TIMEOUT = Integer.parseInt(tmp);
+			log.info("Default idle timeout set to {}.", DEFAULT_IDLE_TIMEOUT);
+		} else {
+			log.info("Default idle timeout not configured. Using {}.", DEFAULT_IDLE_TIMEOUT);
+		}
+
+
+
+	}
+
+	@Override
+	public void startUp(FloodlightModuleContext context) {
+		super.startUp();
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/hub/Hub.java b/src/main/java/net/floodlightcontroller/hub/Hub.java
index 4a3549ba47224cc0b8a7821798f589d61fbabb52..ed5efe236d83ce6d617f63e6425d556458caa175 100644
--- a/src/main/java/net/floodlightcontroller/hub/Hub.java
+++ b/src/main/java/net/floodlightcontroller/hub/Hub.java
@@ -17,7 +17,6 @@
 
 package net.floodlightcontroller.hub;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -32,25 +31,26 @@ import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 
-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;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+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.OFVersion;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
 
 /**
  *
  * @author David Erickson (daviderickson@cs.stanford.edu) - 04/04/10
  */
 public class Hub implements IFloodlightModule, IOFMessageListener {
-    protected static Logger log = LoggerFactory.getLogger(Hub.class);
+	private enum HubType {USE_PACKET_OUT, USE_FLOW_MOD};
 
-    protected IFloodlightProviderService floodlightProvider;
+    private IFloodlightProviderService floodlightProvider;
 
     /**
      * @param floodlightProvider the floodlightProvider to set
@@ -65,35 +65,53 @@ public class Hub implements IFloodlightModule, IOFMessageListener {
     }
 
     public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
-        OFPacketIn pi = (OFPacketIn) msg;
-        OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory()
-                .getMessage(OFType.PACKET_OUT);
-        po.setBufferId(pi.getBufferId())
-            .setInPort(pi.getInPort());
+    	OFMessage outMessage;
+    	HubType ht = HubType.USE_FLOW_MOD;
+    	switch (ht) {
+    	case USE_FLOW_MOD:
+            outMessage = createHubFlowMod(sw, msg);
+            break;
+        default:
+    	case USE_PACKET_OUT:
+            outMessage = createHubPacketOut(sw, msg);
+            break;
+    	}
+        sw.write(outMessage);
+
+        return Command.CONTINUE;
+    }
+    
+    private OFMessage createHubFlowMod(IOFSwitch sw, OFMessage msg) {
+    	OFPacketIn pi = (OFPacketIn) msg;
+        OFFlowAdd.Builder fmb = sw.getOFFactory().buildFlowAdd();
+        
+        fmb.setBufferId(pi.getBufferId())
+        .setXid(pi.getXid());
 
         // set actions
-        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() == 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);
-        }
+        OFActionOutput.Builder actionBuilder = sw.getOFFactory().actions().buildOutput();
+        actionBuilder.setPort(OFPort.FLOOD);
+        fmb.setActions(Collections.singletonList((OFAction) actionBuilder.build()));
 
-        return Command.CONTINUE;
+        return fmb.build();
+    }
+    
+    private OFMessage createHubPacketOut(IOFSwitch sw, OFMessage msg) {
+    	OFPacketIn pi = (OFPacketIn) msg;
+        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
+        pob.setBufferId(pi.getBufferId()).setXid(pi.getXid()).setInPort((pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+
+        // set actions
+        OFActionOutput.Builder actionBuilder = sw.getOFFactory().actions().buildOutput();
+        actionBuilder.setPort(OFPort.FLOOD);
+        pob.setActions(Collections.singletonList((OFAction) actionBuilder.build()));
+
+        // set data if it is included in the packetin
+        if (pi.getBufferId() == OFBufferId.NO_BUFFER) {
+            byte[] packetData = pi.getData();
+            pob.setData(packetData);
+        }
+        return pob.build();  	
     }
 
     @Override
@@ -133,8 +151,7 @@ public class Hub implements IFloodlightModule, IOFMessageListener {
     @Override
     public void init(FloodlightModuleContext context)
             throws FloodlightModuleException {
-        floodlightProvider =
-                context.getServiceImpl(IFloodlightProviderService.class);
+        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
     }
 
     @Override
diff --git a/src/main/java/net/floodlightcontroller/learningswitch/ILearningSwitchService.java b/src/main/java/net/floodlightcontroller/learningswitch/ILearningSwitchService.java
index 92352e93d60a5cfbe063e09c98af66902a9e190d..88e0c4b63ce632858e9c63b954c5fb144995bfce 100644
--- a/src/main/java/net/floodlightcontroller/learningswitch/ILearningSwitchService.java
+++ b/src/main/java/net/floodlightcontroller/learningswitch/ILearningSwitchService.java
@@ -18,6 +18,8 @@ package net.floodlightcontroller.learningswitch;
 
 import java.util.Map;
 
+import org.projectfloodlight.openflow.types.OFPort;
+
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.types.MacVlanPair;
@@ -27,5 +29,5 @@ public interface ILearningSwitchService extends IFloodlightService {
      * Returns the LearningSwitch's learned host table
      * @return The learned host table
      */
-    public Map<IOFSwitch, Map<MacVlanPair,Short>> getTable();
+    public Map<IOFSwitch, Map<MacVlanPair, OFPort>> getTable();
 }
diff --git a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java b/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java
index 2e8ce6f1baf678771543273e80e0f3dad0277054..7e347294c30dd4822e83e3c3980ea35ac49489f0 100644
--- a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java
+++ b/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java
@@ -29,14 +29,14 @@
 
 package net.floodlightcontroller.learningswitch;
 
-import java.io.IOException;
 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.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import net.floodlightcontroller.core.FloodlightContext;
@@ -48,22 +48,28 @@ import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.types.MacVlanPair;
-import net.floodlightcontroller.counter.ICounterStoreService;
-import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.restserver.IRestApiService;
 
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFFlowRemoved;
-import org.openflow.protocol.OFMatch;
-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.HexString;
-import org.openflow.util.LRULinkedHashMap;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
+import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
+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.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.types.VlanVid;
+import org.projectfloodlight.openflow.util.LRULinkedHashMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -72,12 +78,12 @@ public class LearningSwitch
     protected static Logger log = LoggerFactory.getLogger(LearningSwitch.class);
 
     // Module dependencies
-    protected IFloodlightProviderService floodlightProvider;
-    protected ICounterStoreService counterStore;
-    protected IRestApiService restApi;
+    protected IFloodlightProviderService floodlightProviderService;
+    protected IDebugCounterService debugCounterService;
+    protected IRestApiService restApiService;
 
     // Stores the learned state for each switch
-    protected Map<IOFSwitch, Map<MacVlanPair,Short>> macVlanToSwitchPortMap;
+    protected Map<IOFSwitch, Map<MacVlanPair, OFPort>> macVlanToSwitchPortMap;
 
     // flow-mod - for use in the cookie
     public static final int LEARNING_SWITCH_APP_ID = 1;
@@ -101,8 +107,8 @@ public class LearningSwitch
     /**
      * @param floodlightProvider the floodlightProvider to set
      */
-    public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) {
-        this.floodlightProvider = floodlightProvider;
+    public void setFloodlightProvider(IFloodlightProviderService floodlightProviderService) {
+        this.floodlightProviderService = floodlightProviderService;
     }
 
     @Override
@@ -117,18 +123,18 @@ public class LearningSwitch
      * @param vlan The VLAN that the host is on
      * @param portVal The switchport that the host is on
      */
-    protected void addToPortMap(IOFSwitch sw, long mac, short vlan, short portVal) {
-        Map<MacVlanPair,Short> swMap = macVlanToSwitchPortMap.get(sw);
+    protected void addToPortMap(IOFSwitch sw, MacAddress mac, VlanVid vlan, OFPort portVal) {
+        Map<MacVlanPair, OFPort> swMap = macVlanToSwitchPortMap.get(sw);
 
-        if (vlan == (short) 0xffff) {
+        if (vlan == VlanVid.FULL_MASK) {
             // OFMatch.loadFromPacket sets VLAN ID to 0xffff if the packet contains no VLAN tag;
             // for our purposes that is equivalent to the default VLAN ID 0
-            vlan = 0;
+            vlan = VlanVid.ofVlan(0);
         }
 
         if (swMap == null) {
             // May be accessed by REST API so we need to make it thread safe
-            swMap = Collections.synchronizedMap(new LRULinkedHashMap<MacVlanPair,Short>(MAX_MACS_PER_SWITCH));
+            swMap = Collections.synchronizedMap(new LRULinkedHashMap<MacVlanPair, OFPort>(MAX_MACS_PER_SWITCH));
             macVlanToSwitchPortMap.put(sw, swMap);
         }
         swMap.put(new MacVlanPair(mac, vlan), portVal);
@@ -140,13 +146,15 @@ public class LearningSwitch
      * @param mac The MAC address of the host to remove
      * @param vlan The VLAN that the host is on
      */
-    protected void removeFromPortMap(IOFSwitch sw, long mac, short vlan) {
-        if (vlan == (short) 0xffff) {
-            vlan = 0;
+    protected void removeFromPortMap(IOFSwitch sw, MacAddress mac, VlanVid vlan) {
+        if (vlan == VlanVid.FULL_MASK) {
+            vlan = VlanVid.ofVlan(0);
         }
-        Map<MacVlanPair,Short> swMap = macVlanToSwitchPortMap.get(sw);
-        if (swMap != null)
+        
+        Map<MacVlanPair, OFPort> swMap = macVlanToSwitchPortMap.get(sw);
+        if (swMap != null) {
             swMap.remove(new MacVlanPair(mac, vlan));
+        }
     }
 
     /**
@@ -156,13 +164,14 @@ public class LearningSwitch
      * @param vlan The VLAN number to get
      * @return The port the host is on
      */
-    public Short getFromPortMap(IOFSwitch sw, long mac, short vlan) {
-        if (vlan == (short) 0xffff) {
-            vlan = 0;
+    public OFPort getFromPortMap(IOFSwitch sw, MacAddress mac, VlanVid vlan) {
+        if (vlan == VlanVid.FULL_MASK) {
+            vlan = VlanVid.FULL_MASK;
         }
-        Map<MacVlanPair,Short> swMap = macVlanToSwitchPortMap.get(sw);
-        if (swMap != null)
+        Map<MacVlanPair, OFPort> swMap = macVlanToSwitchPortMap.get(sw);
+        if (swMap != null) {
             return swMap.get(new MacVlanPair(mac, vlan));
+        }
 
         // if none found
         return null;
@@ -180,13 +189,14 @@ public class LearningSwitch
      * @param sw The switch to clear the mapping for
      */
     public void clearLearnedTable(IOFSwitch sw) {
-        Map<MacVlanPair, Short> swMap = macVlanToSwitchPortMap.get(sw);
-        if (swMap != null)
+        Map<MacVlanPair, OFPort> swMap = macVlanToSwitchPortMap.get(sw);
+        if (swMap != null) {
             swMap.clear();
+        }
     }
 
     @Override
-    public synchronized Map<IOFSwitch, Map<MacVlanPair,Short>> getTable() {
+    public synchronized Map<IOFSwitch, Map<MacVlanPair, OFPort>> getTable() {
         return macVlanToSwitchPortMap;
     }
 
@@ -198,8 +208,8 @@ public class LearningSwitch
      * @param match The OFMatch structure to write.
      * @param outPort The switch port to output it to.
      */
-    private void writeFlowMod(IOFSwitch sw, short command, int bufferId,
-            OFMatch match, short outPort) {
+    private void writeFlowMod(IOFSwitch sw, OFFlowModCommand command, OFBufferId bufferId,
+            Match match, OFPort outPort) {
         // from openflow 1.0 spec - need to set these on a struct ofp_flow_mod:
         // struct ofp_flow_mod {
         //    struct ofp_header header;
@@ -223,16 +233,25 @@ public class LearningSwitch
         //                                            header. */
         //    };
 
-        OFFlowMod flowMod = (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD);
-        flowMod.setMatch(match);
-        flowMod.setCookie(LearningSwitch.LEARNING_SWITCH_COOKIE);
-        flowMod.setCommand(command);
-        flowMod.setIdleTimeout(LearningSwitch.FLOWMOD_DEFAULT_IDLE_TIMEOUT);
-        flowMod.setHardTimeout(LearningSwitch.FLOWMOD_DEFAULT_HARD_TIMEOUT);
-        flowMod.setPriority(LearningSwitch.FLOWMOD_PRIORITY);
-        flowMod.setBufferId(bufferId);
-        flowMod.setOutPort((command == OFFlowMod.OFPFC_DELETE) ? outPort : OFPort.OFPP_NONE.getValue());
-        flowMod.setFlags((command == OFFlowMod.OFPFC_DELETE) ? 0 : (short) (1 << 0)); // OFPFF_SEND_FLOW_REM
+        OFFlowMod.Builder fmb;
+        if (command == OFFlowModCommand.DELETE) {
+        	fmb = sw.getOFFactory().buildFlowDelete();
+        } else {
+        	fmb = sw.getOFFactory().buildFlowModify();
+        }
+        fmb.setMatch(match);
+        fmb.setCookie((U64.of(LearningSwitch.LEARNING_SWITCH_COOKIE)));
+        fmb.setIdleTimeout(LearningSwitch.FLOWMOD_DEFAULT_IDLE_TIMEOUT);
+        fmb.setHardTimeout(LearningSwitch.FLOWMOD_DEFAULT_HARD_TIMEOUT);
+        fmb.setPriority(LearningSwitch.FLOWMOD_PRIORITY);
+        fmb.setBufferId(bufferId);
+        fmb.setOutPort((command == OFFlowModCommand.DELETE) ? outPort : OFPort.ANY);
+        Set<OFFlowModFlags> sfmf = new HashSet<OFFlowModFlags>();
+        if (command != OFFlowModCommand.DELETE) {
+        	sfmf.add(OFFlowModFlags.SEND_FLOW_REM);
+        }
+        fmb.setFlags(sfmf);
+        
 
         // set the ofp_action_header/out actions:
         // from the openflow 1.0 spec: need to set these on a struct ofp_action_output:
@@ -242,22 +261,19 @@ public class LearningSwitch
         // uint16_t max_len; /* Max length to send to controller. */
         // type/len are set because it is OFActionOutput,
         // and port, max_len are arguments to this constructor
-        flowMod.setActions(Arrays.asList((OFAction) new OFActionOutput(outPort, (short) 0xffff)));
-        flowMod.setLength((short) (OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH));
+        List<OFAction> al = new ArrayList<OFAction>();
+        al.add(sw.getOFFactory().actions().buildOutput().setPort(outPort).build());
+        fmb.setActions(al);
 
         if (log.isTraceEnabled()) {
             log.trace("{} {} flow mod {}",
-                      new Object[]{ sw, (command == OFFlowMod.OFPFC_DELETE) ? "deleting" : "adding", flowMod });
+                      new Object[]{ sw, (command == OFFlowModCommand.DELETE) ? "deleting" : "adding", fmb.build() });
         }
 
-        counterStore.updatePktOutFMCounterStoreLocal(sw, flowMod);
+        //TODO @Ryan counterStore.updatePktOutFMCounterStoreLocal(sw, fmb.build());
 
         // and write it out
-        try {
-            sw.write(flowMod, null);
-        } catch (IOException e) {
-            log.error("Failed to write {} to switch {}", new Object[]{ flowMod, sw }, e);
-        }
+        sw.write(fmb.build());
     }
 
     /**
@@ -270,7 +286,7 @@ public class LearningSwitch
      * @param pi        packet-in
      * @param outport   output port
      */
-    private void pushPacket(IOFSwitch sw, OFMatch match, OFPacketIn pi, short outport) {
+    private void pushPacket(IOFSwitch sw, Match match, OFPacketIn pi, OFPort outport) {
         if (pi == null) {
             return;
         }
@@ -278,7 +294,7 @@ public class LearningSwitch
         // The assumption here is (sw) is the switch that generated the
         // packet-in. If the input port is the same as output port, then
         // the packet-out should be ignored.
-        if (pi.getInPort() == outport) {
+        if (pi.getInPort().equals(outport)) {
             if (log.isDebugEnabled()) {
                 log.debug("Attempting to do packet-out to the same " +
                           "interface as packet-in. Dropping packet. " +
@@ -293,47 +309,35 @@ public class LearningSwitch
                       new Object[] {sw, match, pi});
         }
 
-        OFPacketOut po =
-                (OFPacketOut) floodlightProvider.getOFMessageFactory()
-                                                .getMessage(OFType.PACKET_OUT);
+        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
 
         // set actions
         List<OFAction> actions = new ArrayList<OFAction>();
-        actions.add(new OFActionOutput(outport, (short) 0xffff));
-
-        po.setActions(actions)
-          .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
-        short poLength =
-                (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
+        actions.add(sw.getOFFactory().actions().buildOutput().setPort(outport).build());
 
+        pob.setActions(actions);
+       
         // If the switch doens't support buffering set the buffer id to be none
         // otherwise it'll be the the buffer id of the PacketIn
         if (sw.getBuffers() == 0) {
             // We set the PI buffer id here so we don't have to check again below
-            pi.setBufferId(OFPacketOut.BUFFER_ID_NONE);
-            po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
+            pi = pi.createBuilder().setBufferId(OFBufferId.NO_BUFFER).build();
+            pob.setBufferId(OFBufferId.NO_BUFFER);
         } else {
-            po.setBufferId(pi.getBufferId());
+            pob.setBufferId(pi.getBufferId());
         }
 
-        po.setInPort(pi.getInPort());
+        pob.setInPort(pi.getInPort());
 
         // If the buffer id is none or the switch doesn's support buffering
         // we send the data with the packet out
-        if (pi.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
-            byte[] packetData = pi.getPacketData();
-            poLength += packetData.length;
-            po.setPacketData(packetData);
+        if (pi.getBufferId() == OFBufferId.NO_BUFFER) {
+            byte[] packetData = pi.getData();
+            pob.setData(packetData);
         }
 
-        po.setLength(poLength);
-
-        try {
-            counterStore.updatePktOutFMCounterStoreLocal(sw, po);
-            sw.write(po, null);
-        } catch (IOException e) {
-            log.error("Failure writing packet out", e);
-        }
+        //TODO @Ryan counterStore.updatePktOutFMCounterStoreLocal(sw, pob.build());
+        sw.write(pob.build());
     }
 
     /**
@@ -342,9 +346,7 @@ public class LearningSwitch
      * @param packetInMessage The corresponding PacketIn.
      * @param egressPort The switchport to output the PacketOut.
      */
-    private void writePacketOutForPacketIn(IOFSwitch sw,
-                                          OFPacketIn packetInMessage,
-                                          short egressPort) {
+    private void writePacketOutForPacketIn(IOFSwitch sw, OFPacketIn packetInMessage, OFPort egressPort) {
         // from openflow 1.0 spec - need to set these on a struct ofp_packet_out:
         // uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */
         // uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */
@@ -354,37 +356,27 @@ public class LearningSwitch
                                   from the length field in the header.
                                   (Only meaningful if buffer_id == -1.) */
 
-        OFPacketOut packetOutMessage = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
-        short packetOutLength = (short)OFPacketOut.MINIMUM_LENGTH; // starting length
+        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
 
         // Set buffer_id, in_port, actions_len
-        packetOutMessage.setBufferId(packetInMessage.getBufferId());
-        packetOutMessage.setInPort(packetInMessage.getInPort());
-        packetOutMessage.setActionsLength((short)OFActionOutput.MINIMUM_LENGTH);
-        packetOutLength += OFActionOutput.MINIMUM_LENGTH;
+        pob.setBufferId(packetInMessage.getBufferId());
+        pob.setInPort(packetInMessage.getInPort());
 
         // set actions
         List<OFAction> actions = new ArrayList<OFAction>(1);
-        actions.add(new OFActionOutput(egressPort, (short) 0));
-        packetOutMessage.setActions(actions);
+        actions.add(sw.getOFFactory().actions().buildOutput().setPort(egressPort).build());
+        pob.setActions(actions);
 
         // set data - only if buffer_id == -1
-        if (packetInMessage.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
-            byte[] packetData = packetInMessage.getPacketData();
-            packetOutMessage.setPacketData(packetData);
-            packetOutLength += (short)packetData.length;
+        if (packetInMessage.getBufferId() == OFBufferId.NO_BUFFER) {
+            byte[] packetData = packetInMessage.getData();
+            pob.setData(packetData);
         }
 
-        // finally, set the total length
-        packetOutMessage.setLength(packetOutLength);
-
         // and write it out
-        try {
-            counterStore.updatePktOutFMCounterStoreLocal(sw, packetOutMessage);
-            sw.write(packetOutMessage, null);
-        } catch (IOException e) {
-            log.error("Failed to write {} to switch {}: {}", new Object[]{ packetOutMessage, sw, e });
-        }
+        //TODO @Ryan counterStore.updatePktOutFMCounterStoreLocal(sw, pob.build());
+        sw.write(pob.build());
+
     }
 
     /**
@@ -398,36 +390,35 @@ public class LearningSwitch
      */
     private Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
         // Read in packet data headers by using OFMatch
-        OFMatch match = new OFMatch();
-        match.loadFromPacket(pi.getPacketData(), pi.getInPort());
-        Long sourceMac = Ethernet.toLong(match.getDataLayerSource());
-        Long destMac = Ethernet.toLong(match.getDataLayerDestination());
-        Short vlan = match.getDataLayerVirtualLan();
-        if ((destMac & 0xfffffffffff0L) == 0x0180c2000000L) {
+        Match.Builder mb = pi.getMatch().createBuilder();
+        MacAddress sourceMac = mb.get(MatchField.ETH_SRC);
+        MacAddress destMac = mb.get(MatchField.ETH_DST);
+        OFVlanVidMatch vlan = mb.get(MatchField.VLAN_VID);
+        if ((destMac.getLong() & 0xfffffffffff0L) == 0x0180c2000000L) {
             if (log.isTraceEnabled()) {
                 log.trace("ignoring packet addressed to 802.1D/Q reserved addr: switch {} vlan {} dest MAC {}",
-                          new Object[]{ sw, vlan, HexString.toHexString(destMac) });
+                          new Object[]{ sw, vlan, destMac.toString() });
             }
             return Command.STOP;
         }
-        if ((sourceMac & 0x010000000000L) == 0) {
+        if ((sourceMac.getLong() & 0x010000000000L) == 0) {
             // If source MAC is a unicast address, learn the port for this MAC/VLAN
-            this.addToPortMap(sw, sourceMac, vlan, pi.getInPort());
+            this.addToPortMap(sw, sourceMac, vlan.getVlanVid(), pi.getInPort());
         }
 
         // Now output flow-mod and/or packet
-        Short outPort = getFromPortMap(sw, destMac, vlan);
+        OFPort outPort = getFromPortMap(sw, destMac, vlan.getVlanVid());
         if (outPort == null) {
             // If we haven't learned the port for the dest MAC/VLAN, flood it
             // Don't flood broadcast packets if the broadcast is disabled.
             // XXX For LearningSwitch this doesn't do much. The sourceMac is removed
             //     from port map whenever a flow expires, so you would still see
             //     a lot of floods.
-            this.writePacketOutForPacketIn(sw, pi, OFPort.OFPP_FLOOD.getValue());
-        } else if (outPort == match.getInputPort()) {
+            this.writePacketOutForPacketIn(sw, pi, OFPort.FLOOD);
+        } else if (outPort.equals(mb.get(MatchField.IN_PORT))) {
             log.trace("ignoring packet that arrived on same port as learned destination:"
                     + " switch {} vlan {} dest MAC {} port {}",
-                    new Object[]{ sw, vlan, HexString.toHexString(destMac), outPort });
+                    new Object[]{ sw, vlan, destMac.toString(), outPort.getPortNumber() });
         } else {
             // Add flow table entry matching source MAC, dest MAC, VLAN and input port
             // that sends to the port we previously learned for the dest MAC/VLAN.  Also
@@ -438,23 +429,30 @@ public class LearningSwitch
             // its former location does not keep the stale entry alive forever.
             // FIXME: current HP switches ignore DL_SRC and DL_DST fields, so we have to match on
             // NW_SRC and NW_DST as well
-            match.setWildcards(((Integer)sw.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).intValue()
-                    & ~OFMatch.OFPFW_IN_PORT
-                    & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST
-                    & ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK);
             // We write FlowMods with Buffer ID none then explicitly PacketOut the buffered packet
-            this.pushPacket(sw, match, pi, outPort);
-            this.writeFlowMod(sw, OFFlowMod.OFPFC_ADD, OFPacketOut.BUFFER_ID_NONE, match, outPort);
+            this.pushPacket(sw, mb.build(), pi, outPort);
+            this.writeFlowMod(sw, OFFlowModCommand.ADD, OFBufferId.NO_BUFFER, mb.build(), outPort);
             if (LEARNING_SWITCH_REVERSE_FLOW) {
-                this.writeFlowMod(sw, OFFlowMod.OFPFC_ADD, -1, match.clone()
-                    .setDataLayerSource(match.getDataLayerDestination())
-                    .setDataLayerDestination(match.getDataLayerSource())
-                    .setNetworkSource(match.getNetworkDestination())
-                    .setNetworkDestination(match.getNetworkSource())
-                    .setTransportSource(match.getTransportDestination())
-                    .setTransportDestination(match.getTransportSource())
-                    .setInputPort(outPort),
-                    match.getInputPort());
+            	Match.Builder mb2 = mb.build().createBuilder();
+            	mb2.setExact(MatchField.ETH_SRC, mb.get(MatchField.ETH_DST))                         
+            	.setExact(MatchField.ETH_DST, mb.get(MatchField.ETH_SRC))                         
+            	.setExact(MatchField.IPV4_SRC, mb.get(MatchField.IPV4_DST))                         
+            	.setExact(MatchField.IPV4_DST, mb.get(MatchField.IPV4_SRC));
+            	if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.TCP)) {
+            		mb2.setExact(MatchField.TCP_SRC, mb.get(MatchField.TCP_DST))
+            		.setExact(MatchField.TCP_DST, mb.get(MatchField.TCP_SRC));
+            	} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.UDP)) {
+            		mb2.setExact(MatchField.UDP_SRC, mb.get(MatchField.UDP_DST))
+            		.setExact(MatchField.UDP_DST, mb.get(MatchField.UDP_SRC));
+            	} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.SCTP)) {
+            		mb2.setExact(MatchField.SCTP_SRC, mb.get(MatchField.SCTP_DST))
+            		.setExact(MatchField.SCTP_DST, mb.get(MatchField.SCTP_SRC));
+            	} else {
+            		log.debug("In writing reverse LS flow, could not determine L4 proto (was int " + mb.get(MatchField.IP_PROTO).getIpProtocolNumber() + ")");
+            	}
+            	mb2.setExact(MatchField.IN_PORT, outPort);
+
+            	this.writeFlowMod(sw, OFFlowModCommand.ADD, OFBufferId.NO_BUFFER, mb2.build(), mb.get(MatchField.IN_PORT));
             }
         }
         return Command.CONTINUE;
@@ -468,36 +466,42 @@ public class LearningSwitch
      * @return Whether to continue processing this message or stop.
      */
     private Command processFlowRemovedMessage(IOFSwitch sw, OFFlowRemoved flowRemovedMessage) {
-        if (flowRemovedMessage.getCookie() != LearningSwitch.LEARNING_SWITCH_COOKIE) {
+        if (!flowRemovedMessage.getCookie().equals(U64.of(LearningSwitch.LEARNING_SWITCH_COOKIE))) {
             return Command.CONTINUE;
         }
         if (log.isTraceEnabled()) {
             log.trace("{} flow entry removed {}", sw, flowRemovedMessage);
         }
-        OFMatch match = flowRemovedMessage.getMatch();
+        Match match = flowRemovedMessage.getMatch();
         // When a flow entry expires, it means the device with the matching source
         // MAC address and VLAN either stopped sending packets or moved to a different
         // port.  If the device moved, we can't know where it went until it sends
         // another packet, allowing us to re-learn its port.  Meanwhile we remove
         // it from the macVlanToPortMap to revert to flooding packets to this device.
-        this.removeFromPortMap(sw, Ethernet.toLong(match.getDataLayerSource()),
-            match.getDataLayerVirtualLan());
+        this.removeFromPortMap(sw, match.get(MatchField.ETH_SRC), match.get(MatchField.VLAN_VID).getVlanVid());
 
         // Also, if packets keep coming from another device (e.g. from ping), the
         // corresponding reverse flow entry will never expire on its own and will
         // send the packets to the wrong port (the matching input port of the
         // expired flow entry), so we must delete the reverse entry explicitly.
-        this.writeFlowMod(sw, OFFlowMod.OFPFC_DELETE, -1, match.clone()
-                .setWildcards(((Integer)sw.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).intValue()
-                        & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST
-                        & ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK)
-                .setDataLayerSource(match.getDataLayerDestination())
-                .setDataLayerDestination(match.getDataLayerSource())
-                .setNetworkSource(match.getNetworkDestination())
-                .setNetworkDestination(match.getNetworkSource())
-                .setTransportSource(match.getTransportDestination())
-                .setTransportDestination(match.getTransportSource()),
-                match.getInputPort());
+        Match.Builder mb = match.createBuilder();
+    	mb.setExact(MatchField.ETH_SRC, match.get(MatchField.ETH_DST))                         
+    	.setExact(MatchField.ETH_DST, match.get(MatchField.ETH_SRC))                         
+    	.setExact(MatchField.IPV4_SRC, match.get(MatchField.IPV4_DST))                         
+    	.setExact(MatchField.IPV4_DST, match.get(MatchField.IPV4_SRC));
+    	if (match.get(MatchField.IP_PROTO).equals(IpProtocol.TCP)) {
+    		mb.setExact(MatchField.TCP_SRC, match.get(MatchField.TCP_DST))
+    		.setExact(MatchField.TCP_DST, match.get(MatchField.TCP_SRC));
+    	} else if (match.get(MatchField.IP_PROTO).equals(IpProtocol.UDP)) {
+    		mb.setExact(MatchField.UDP_SRC, match.get(MatchField.UDP_DST))
+    		.setExact(MatchField.UDP_DST, match.get(MatchField.UDP_SRC));
+    	} else if (match.get(MatchField.IP_PROTO).equals(IpProtocol.SCTP)) {
+    		mb.setExact(MatchField.SCTP_SRC, match.get(MatchField.SCTP_DST))
+    		.setExact(MatchField.SCTP_DST, match.get(MatchField.SCTP_SRC));
+    	} else {
+    		log.debug("In writing reverse LS flow, could not determine L4 proto (was int " + mb.get(MatchField.IP_PROTO).getIpProtocolNumber() + ")");
+    	}
+        this.writeFlowMod(sw, OFFlowModCommand.DELETE, OFBufferId.NO_BUFFER, mb.build(), match.get(MatchField.IN_PORT));
         return Command.CONTINUE;
     }
 
@@ -541,46 +545,37 @@ public class LearningSwitch
     }
 
     @Override
-    public Map<Class<? extends IFloodlightService>, IFloodlightService>
-            getServiceImpls() {
-        Map<Class<? extends IFloodlightService>,
-            IFloodlightService> m =
-                new HashMap<Class<? extends IFloodlightService>,
-                    IFloodlightService>();
+    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+        Map<Class<? extends IFloodlightService>,  IFloodlightService> m = 
+        		new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
         m.put(ILearningSwitchService.class, this);
         return m;
     }
 
     @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleDependencies() {
+    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
         Collection<Class<? extends IFloodlightService>> l =
                 new ArrayList<Class<? extends IFloodlightService>>();
         l.add(IFloodlightProviderService.class);
-        l.add(ICounterStoreService.class);
+        l.add(IDebugCounterService.class);
         l.add(IRestApiService.class);
         return l;
     }
 
     @Override
-    public void init(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-        macVlanToSwitchPortMap =
-                new ConcurrentHashMap<IOFSwitch, Map<MacVlanPair,Short>>();
-        floodlightProvider =
-                context.getServiceImpl(IFloodlightProviderService.class);
-        counterStore =
-                context.getServiceImpl(ICounterStoreService.class);
-        restApi =
-                context.getServiceImpl(IRestApiService.class);
+    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+        macVlanToSwitchPortMap = new ConcurrentHashMap<IOFSwitch, Map<MacVlanPair, OFPort>>();
+        floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+        debugCounterService = context.getServiceImpl(IDebugCounterService.class);
+        restApiService = context.getServiceImpl(IRestApiService.class);
     }
 
     @Override
     public void startUp(FloodlightModuleContext context) {
-        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-        floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this);
-        floodlightProvider.addOFMessageListener(OFType.ERROR, this);
-        restApi.addRestletRoutable(new LearningSwitchWebRoutable());
+        floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
+        floodlightProviderService.addOFMessageListener(OFType.FLOW_REMOVED, this);
+        floodlightProviderService.addOFMessageListener(OFType.ERROR, this);
+        restApiService.addRestletRoutable(new LearningSwitchWebRoutable());
 
         // read our config options
         Map<String, String> configOptions = context.getConfigParams(this);
@@ -591,8 +586,7 @@ public class LearningSwitch
             }
         } catch (NumberFormatException e) {
             log.warn("Error parsing flow idle timeout, " +
-                     "using default of {} seconds",
-                     FLOWMOD_DEFAULT_IDLE_TIMEOUT);
+                     "using default of {} seconds", FLOWMOD_DEFAULT_IDLE_TIMEOUT);
         }
         try {
             String hardTimeout = configOptions.get("hardtimeout");
@@ -601,8 +595,7 @@ public class LearningSwitch
             }
         } catch (NumberFormatException e) {
             log.warn("Error parsing flow hard timeout, " +
-                     "using default of {} seconds",
-                     FLOWMOD_DEFAULT_HARD_TIMEOUT);
+                     "using default of {} seconds", FLOWMOD_DEFAULT_HARD_TIMEOUT);
         }
         try {
             String priority = configOptions.get("priority");
@@ -614,11 +607,8 @@ public class LearningSwitch
                      "using default of {}",
                      FLOWMOD_PRIORITY);
         }
-        log.debug("FlowMod idle timeout set to {} seconds",
-                  FLOWMOD_DEFAULT_IDLE_TIMEOUT);
-        log.debug("FlowMod hard timeout set to {} seconds",
-                  FLOWMOD_DEFAULT_HARD_TIMEOUT);
-        log.debug("FlowMod priority set to {}",
-                FLOWMOD_PRIORITY);
+        log.debug("FlowMod idle timeout set to {} seconds", FLOWMOD_DEFAULT_IDLE_TIMEOUT);
+        log.debug("FlowMod hard timeout set to {} seconds", FLOWMOD_DEFAULT_HARD_TIMEOUT);
+        log.debug("FlowMod priority set to {}", FLOWMOD_PRIORITY);
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchTable.java b/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchTable.java
index 2eb1b914f1bc501a449d954733317d229463114e..bb222a41632360e1f30c428e497d139ca23e8ff8 100644
--- a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchTable.java
+++ b/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitchTable.java
@@ -22,11 +22,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.core.types.MacVlanPair;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
 import org.restlet.data.Status;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
@@ -36,17 +37,17 @@ import org.slf4j.LoggerFactory;
 public class LearningSwitchTable extends ServerResource {
     protected static Logger log = LoggerFactory.getLogger(LearningSwitchTable.class);
 
-    protected Map<String, Object> formatTableEntry(MacVlanPair key, short port) {
+    protected Map<String, Object> formatTableEntry(MacVlanPair key, OFPort port) {
         Map<String, Object> entry = new HashMap<String, Object>();
-        entry.put("mac", HexString.toHexString(key.mac));
-        entry.put("vlan", key.vlan);
-        entry.put("port", port);
+        entry.put("mac", key.mac.toString());
+        entry.put("vlan", key.vlan.getVlan());
+        entry.put("port", port.getPortNumber());
         return entry;
     }
 
-    protected List<Map<String, Object>> getOneSwitchTable(Map<MacVlanPair, Short> switchMap) {
+    protected List<Map<String, Object>> getOneSwitchTable(Map<MacVlanPair, OFPort> switchMap) {
         List<Map<String, Object>> switchTable = new ArrayList<Map<String, Object>>();
-        for (Entry<MacVlanPair, Short> entry : switchMap.entrySet()) {
+        for (Entry<MacVlanPair, OFPort> entry : switchMap.entrySet()) {
             switchTable.add(formatTableEntry(entry.getKey(), entry.getValue()));
         }
         return switchTable;
@@ -58,22 +59,21 @@ public class LearningSwitchTable extends ServerResource {
                 (ILearningSwitchService)getContext().getAttributes().
                     get(ILearningSwitchService.class.getCanonicalName());
 
-        Map<IOFSwitch, Map<MacVlanPair,Short>> table = lsp.getTable();
+        Map<IOFSwitch, Map<MacVlanPair, OFPort>> table = lsp.getTable();
         Map<String, List<Map<String, Object>>> allSwitchTableJson = new HashMap<String, List<Map<String, Object>>>();
 
         String switchId = (String) getRequestAttributes().get("switch");
         if (switchId.toLowerCase().equals("all")) {
             for (IOFSwitch sw : table.keySet()) {
-                allSwitchTableJson.put(HexString.toHexString(sw.getId()), getOneSwitchTable(table.get(sw)));
+                allSwitchTableJson.put(sw.getId().toString(), getOneSwitchTable(table.get(sw)));
             }
         } else {
             try {
-                IFloodlightProviderService floodlightProvider =
-                        (IFloodlightProviderService)getContext().getAttributes().
-                            get(IFloodlightProviderService.class.getCanonicalName());
-                long dpid = HexString.toLong(switchId);
-                IOFSwitch sw = floodlightProvider.getSwitch(dpid);
-                allSwitchTableJson.put(HexString.toHexString(sw.getId()), getOneSwitchTable(table.get(sw)));
+                IOFSwitchService switchService =
+                        (IOFSwitchService) getContext().getAttributes().
+                            get(IOFSwitchService.class.getCanonicalName());
+                IOFSwitch sw = switchService.getSwitch(DatapathId.of(switchId));
+                allSwitchTableJson.put(sw.getId().toString(), getOneSwitchTable(table.get(sw)));
             } catch (NumberFormatException e) {
                 log.error("Could not decode switch ID = " + switchId);
                 setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java
index e4e109ca46fea5d8605109aea8f497c6300edcb6..d1dee02a9347d5d5fd185dd9bc17356a57240365 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java
@@ -18,7 +18,9 @@ package net.floodlightcontroller.linkdiscovery;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import org.openflow.util.HexString;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
 
 public interface ILinkDiscovery {
 
@@ -45,16 +47,16 @@ public interface ILinkDiscovery {
     }
 
     public class LDUpdate {
-        protected long src;
-        protected short srcPort;
-        protected long dst;
-        protected short dstPort;
+        protected DatapathId src;
+        protected OFPort srcPort;
+        protected DatapathId dst;
+        protected OFPort dstPort;
         protected SwitchType srcType;
         protected LinkType type;
         protected UpdateOperation operation;
 
-        public LDUpdate(long src, short srcPort,
-                      long dst, short dstPort,
+        public LDUpdate(DatapathId src, OFPort srcPort,
+        		DatapathId dst, OFPort dstPort,
                       ILinkDiscovery.LinkType type,
                       UpdateOperation operation) {
             this.src = src;
@@ -76,32 +78,32 @@ public interface ILinkDiscovery {
         }
 
         // For updtedSwitch(sw)
-        public LDUpdate(long switchId, SwitchType stype, UpdateOperation oper ){
+        public LDUpdate(DatapathId 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(long sw, short port, UpdateOperation operation) {
+        public LDUpdate(DatapathId sw, OFPort port, UpdateOperation operation) {
             this.src = sw;
             this.srcPort = port;
             this.operation = operation;
         }
 
-        public long getSrc() {
+        public DatapathId getSrc() {
             return src;
         }
 
-        public short getSrcPort() {
+        public OFPort getSrcPort() {
             return srcPort;
         }
 
-        public long getDst() {
+        public DatapathId getDst() {
             return dst;
         }
 
-        public short getDstPort() {
+        public OFPort getDstPort() {
             return dstPort;
         }
 
@@ -127,20 +129,20 @@ public interface ILinkDiscovery {
             case LINK_REMOVED:
             case LINK_UPDATED:
                 return "LDUpdate [operation=" + operation +
-                        ", src=" + HexString.toHexString(src)
-                        + ", srcPort=" + srcPort
-                        + ", dst=" + HexString.toHexString(dst) 
-                        + ", dstPort=" + dstPort
+                        ", src=" + src.toString()
+                        + ", srcPort=" + srcPort.toString()
+                        + ", dst=" + dst.toString()
+                        + ", dstPort=" + dstPort.toString()
                         + ", type=" + type + "]";
             case PORT_DOWN:
             case PORT_UP:
                 return "LDUpdate [operation=" + operation +
-                        ", src=" + HexString.toHexString(src)
-                        + ", srcPort=" + srcPort + "]";
+                        ", src=" + src.toString()
+                        + ", srcPort=" + srcPort.toString() + "]";
             case SWITCH_REMOVED:
             case SWITCH_UPDATED:
                 return "LDUpdate [operation=" + operation +
-                        ", src=" + HexString.toHexString(src) + "]";
+                        ", src=" + src.toString() + "]";
             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 3773efd713b992755e093bd50dfdaf85317114a0..2bb53727917ffba3b4138bf3d06a9e56b79db1f2 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
@@ -20,7 +20,10 @@ package net.floodlightcontroller.linkdiscovery;
 import java.util.Map;
 import java.util.Set;
 
-import org.openflow.protocol.OFPacketOut;
+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 net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.routing.Link;
@@ -32,7 +35,7 @@ public interface ILinkDiscoveryService extends IFloodlightService {
     /**
      * Returns if a given switchport is a tunnel endpoint or not
      */
-    public boolean isTunnelPort(long sw, short port);
+    public boolean isTunnelPort(DatapathId sw, OFPort port);
 
     /**
      * Retrieves a map of all known link connections between OpenFlow switches
@@ -59,7 +62,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(long sw, short port,
+    public OFPacketOut generateLLDPMessage(DatapathId sw, OFPort port,
                                            boolean isStandard,
                                            boolean isReverse);
 
@@ -67,7 +70,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<Long, Set<Link>> getSwitchLinks();
+    public Map<DatapathId, Set<Link>> getSwitchLinks();
 
     /**
      * Adds a listener to listen for ILinkDiscoveryService messages
@@ -84,17 +87,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(long sw, short port);
+    public void AddToSuppressLLDPs(DatapathId sw, OFPort port);
 
     /**
      * Removes a switch port from suppress lldp set
      */
-    public void RemoveFromSuppressLLDPs(long sw, short port);
+    public void RemoveFromSuppressLLDPs(DatapathId sw, OFPort port);
 
     /**
      * Get the set of quarantined ports on a switch
      */
-    public Set<Short> getQuarantinedPorts(long sw);
+    public Set<OFPort> getQuarantinedPorts(DatapathId sw);
 
     /**
      * Get the status of auto port fast feature.
@@ -126,5 +129,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(long mac, int ignoreBits);
+    public void addMACToIgnoreList(MacAddress mac, int ignoreBits);
 }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java b/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java
index 0230b3bbd31f8cb47581ff83f6b79f4632386560..6c2d7334e436cabe3f44eca1547d4f1425c3d440 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java
@@ -15,15 +15,17 @@
 
 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(Long firstSeenTime,
-                    Long lastLldpReceivedTime,
-                    Long lastBddpReceivedTime) {
+    public LinkInfo(Date firstSeenTime,
+                    Date lastLldpReceivedTime,
+                    Date lastBddpReceivedTime) {
         super();
         this.firstSeenTime = firstSeenTime;
         this.lastLldpReceivedTime = lastLldpReceivedTime;
@@ -46,9 +48,9 @@ public class LinkInfo {
         this.lastBddpReceivedTime = fromLinkInfo.getMulticastValidTime();
     }
 
-    protected Long firstSeenTime;
-    protected Long lastLldpReceivedTime; /* Standard LLLDP received time */
-    protected Long lastBddpReceivedTime; /* Modified LLDP received time  */
+    protected Date firstSeenTime;
+    protected Date lastLldpReceivedTime; /* Standard LLLDP received time */
+    protected Date 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
@@ -60,27 +62,27 @@ public class LinkInfo {
      * requires the new state to be written to storage.
      */
 
-    public Long getFirstSeenTime() {
+    public Date getFirstSeenTime() {
         return firstSeenTime;
     }
 
-    public void setFirstSeenTime(Long firstSeenTime) {
+    public void setFirstSeenTime(Date firstSeenTime) {
         this.firstSeenTime = firstSeenTime;
     }
 
-    public Long getUnicastValidTime() {
+    public Date getUnicastValidTime() {
         return lastLldpReceivedTime;
     }
 
-    public void setUnicastValidTime(Long unicastValidTime) {
+    public void setUnicastValidTime(Date unicastValidTime) {
         this.lastLldpReceivedTime = unicastValidTime;
     }
 
-    public Long getMulticastValidTime() {
+    public Date getMulticastValidTime() {
         return lastBddpReceivedTime;
     }
 
-    public void setMulticastValidTime(Long multicastValidTime) {
+    public void setMulticastValidTime(Date multicastValidTime) {
         this.lastBddpReceivedTime = multicastValidTime;
     }
 
@@ -147,8 +149,8 @@ public class LinkInfo {
      */
     @Override
     public String toString() {
-        return "LinkInfo [unicastValidTime=" + ((lastLldpReceivedTime == null) ? "null" : lastLldpReceivedTime)
-                + ", multicastValidTime=" + ((lastBddpReceivedTime == null) ? "null" : lastBddpReceivedTime)
+        return "LinkInfo [unicastValidTime=" + ((lastLldpReceivedTime == null) ? "null" : lastLldpReceivedTime.getTime())
+                + ", multicastValidTime=" + ((lastBddpReceivedTime == null) ? "null" : lastBddpReceivedTime.getTime())
                 + "]";
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index 2dbba0a30de9a7d558e26e79d6c216b388a4c455..e2b53a77707e34434536ee481c4831bc813d4103 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -17,7 +17,6 @@
 
 package net.floodlightcontroller.linkdiscovery.internal;
 
-import java.io.IOException;
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.nio.ByteBuffer;
@@ -25,6 +24,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -42,17 +42,19 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 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.IShutdownService;
+import net.floodlightcontroller.core.PortChangeType;
 import net.floodlightcontroller.core.IHAListener;
 import net.floodlightcontroller.core.IInfoProvider;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.IOFSwitchListener;
-import net.floodlightcontroller.core.ImmutablePort;
 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;
@@ -60,15 +62,10 @@ import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.util.SingletonTask;
 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.debugevent.IDebugEventService;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
-import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
-import net.floodlightcontroller.debugevent.IEventUpdater;
-import net.floodlightcontroller.debugevent.NullDebugEvent;
+import net.floodlightcontroller.debugevent.IEventCategory;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
@@ -95,16 +92,20 @@ import net.floodlightcontroller.storage.StorageException;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.topology.NodePortTuple;
 
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.protocol.OFPhysicalPort.OFPortState;
-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.HexString;
+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.OFPortState;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+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.util.HexString;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -125,1540 +126,1507 @@ import org.slf4j.LoggerFactory;
  */
 @LogMessageCategory("Network Topology")
 public class LinkDiscoveryManager implements IOFMessageListener,
-    IOFSwitchListener, IStorageSourceListener, ILinkDiscoveryService,
-    IFloodlightModule, IInfoProvider {
-    protected static final Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
-    protected static final INotificationManager notifier =
-        NotificationManagerFactory.getNotificationManager(LinkDiscoveryManager.class);
-
-    public static final String MODULE_NAME = "linkdiscovery";
-
-    // Names of table/fields for links in the storage API
-    private static final String TOPOLOGY_TABLE_NAME = "controller_topologyconfig";
-    private static final String TOPOLOGY_ID = "id";
-    private static final String TOPOLOGY_AUTOPORTFAST = "autoportfast";
-
-    private static final String LINK_TABLE_NAME = "controller_link";
-    private static final String LINK_ID = "id";
-    private static final String LINK_SRC_SWITCH = "src_switch_id";
-    private static final String LINK_SRC_PORT = "src_port";
-    private static final String LINK_DST_SWITCH = "dst_switch_id";
-    private static final String LINK_DST_PORT = "dst_port";
-    private static final String LINK_VALID_TIME = "valid_time";
-    private static final String LINK_TYPE = "link_type";
-    private static final String SWITCH_CONFIG_TABLE_NAME = "controller_switchconfig";
-    private static final String SWITCH_CONFIG_CORE_SWITCH = "core_switch";
-
-    // Event updaters for debug events
-    protected IEventUpdater<DirectLinkEvent> evDirectLink;
-
-    protected IFloodlightProviderService floodlightProvider;
-    protected IStorageSourceService storageSource;
-    protected IThreadPoolService threadPool;
-    protected IRestApiService restApi;
-    protected IDebugCounterService debugCounters;
-    protected IDebugEventService debugEvents;
-
-    // Role
-    protected Role role;
-
-    // LLDP and BDDP fields
-    private static final byte[] LLDP_STANDARD_DST_MAC_STRING =
-            HexString.fromHexString("01:80:c2:00:00:0e");
-    private static final long LINK_LOCAL_MASK = 0xfffffffffff0L;
-    private static final long LINK_LOCAL_VALUE = 0x0180c2000000L;
-    protected static int EVENT_HISTORY_SIZE = 1024; // in seconds
-
-    // BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version
-    // private static final String LLDP_BSN_DST_MAC_STRING =
-    // "5d:16:c7:00:00:01";
-    private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff";
-
-    // Direction TLVs are used to indicate if the LLDPs were sent
-    // periodically or in response to a recieved LLDP
-    private static final byte TLV_DIRECTION_TYPE = 0x73;
-    private static final short TLV_DIRECTION_LENGTH = 1; // 1 byte
-    private static final byte TLV_DIRECTION_VALUE_FORWARD[] = { 0x01 };
-    private static final byte TLV_DIRECTION_VALUE_REVERSE[] = { 0x02 };
-    private static final LLDPTLV forwardTLV = new LLDPTLV().setType(TLV_DIRECTION_TYPE)
-                                                           .setLength(TLV_DIRECTION_LENGTH)
-                                                           .setValue(TLV_DIRECTION_VALUE_FORWARD);
-
-    private static final LLDPTLV reverseTLV = new LLDPTLV().setType(TLV_DIRECTION_TYPE)
-                                                           .setLength(TLV_DIRECTION_LENGTH)
-                                                           .setValue(TLV_DIRECTION_VALUE_REVERSE);
-
-    // Link discovery task details.
-    protected SingletonTask discoveryTask;
-    protected final int DISCOVERY_TASK_INTERVAL = 1;
-    protected final int LINK_TIMEOUT = 35; // timeout as part of LLDP process.
-    protected final int LLDP_TO_ALL_INTERVAL = 15; // 15 seconds.
-    protected long lldpClock = 0;
-    // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL.
-    // If we want to identify link failures faster, we could decrease this
-    // value to a small number, say 1 or 2 sec.
-    protected final int LLDP_TO_KNOWN_INTERVAL = 20; // LLDP frequency for known
-                                                     // links
-
-    protected LLDPTLV controllerTLV;
-    protected ReentrantReadWriteLock lock;
-    int lldpTimeCount = 0;
-
-    /**
-     * Flag to indicate if automatic port fast is enabled or not. Default is set
-     * to false -- Initialized in the init method as well.
-     */
-    protected boolean AUTOPORTFAST_DEFAULT = false;
-    protected boolean autoPortFastFeature = AUTOPORTFAST_DEFAULT;
-
-    /**
-     * Map from link to the most recent time it was verified functioning
-     */
-    protected Map<Link, LinkInfo> links;
-
-    /**
-     * Map from switch id to a set of all links with it as an endpoint
-     */
-    protected Map<Long, Set<Link>> switchLinks;
-
-    /**
-     * Map from a id:port to the set of links containing it as an endpoint
-     */
-    protected Map<NodePortTuple, Set<Link>> portLinks;
-
-    protected volatile boolean shuttingDown = false;
-
-    /*
-     * topology aware components are called in the order they were added to the
-     * the array
-     */
-    protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware;
-    protected BlockingQueue<LDUpdate> updates;
-    protected Thread updatesThread;
-
-    /**
-     * List of ports through which LLDP/BDDPs are not sent.
-     */
-    protected Set<NodePortTuple> suppressLinkDiscovery;
-
-    /**
-     * A list of ports that are quarantined for discovering links through them.
-     * Data traffic from these ports are not allowed until the ports are
-     * released from quarantine.
-     */
-    protected LinkedBlockingQueue<NodePortTuple> quarantineQueue;
-    protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue;
-    /**
-     * Quarantine task
-     */
-    protected SingletonTask bddpTask;
-    protected final int BDDP_TASK_INTERVAL = 100; // 100 ms.
-    protected final int BDDP_TASK_SIZE = 10; // # of ports per iteration
-
-    private class MACRange {
-        long baseMAC;
-        int ignoreBits;
-    }
-    protected Set<MACRange> ignoreMACSet;
-
-    private IHAListener haListener;
-
-    /**
-     * Debug Counters
-     */
-    private IDebugCounter ctrQuarantineDrops;
-    private IDebugCounter ctrIgnoreSrcMacDrops;
-    private IDebugCounter ctrIncoming;
-    private IDebugCounter ctrLinkLocalDrops;
-    private IDebugCounter ctrLldpEol;
-
-    private final String PACKAGE = LinkDiscoveryManager.class.getPackage().getName();
-
-
-    //*********************
-    // ILinkDiscoveryService
-    //*********************
-
-    @Override
-    public OFPacketOut generateLLDPMessage(long sw, short port,
-                                       boolean isStandard, boolean isReverse) {
-
-        IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
-        ImmutablePort ofpPort = iofSwitch.getPort(port);
-
-        if (log.isTraceEnabled()) {
-            log.trace("Sending LLDP packet out of swich: {}, port: {}",
-                      HexString.toHexString(sw), port);
-        }
-
-        // using "nearest customer bridge" MAC address for broadest possible
-        // propagation
-        // through provider and TPMR bridges (see IEEE 802.1AB-2009 and
-        // 802.1Q-2011),
-        // in particular the Linux bridge which behaves mostly like a provider
-        // bridge
-        byte[] chassisId = new byte[] { 4, 0, 0, 0, 0, 0, 0 }; // filled in
-                                                               // later
-        byte[] portId = new byte[] { 2, 0, 0 }; // filled in later
-        byte[] ttlValue = new byte[] { 0, 0x78 };
-        // OpenFlow OUI - 00-26-E1
-        byte[] dpidTLVValue = new byte[] { 0x0, 0x26, (byte) 0xe1, 0, 0, 0,
-                                          0, 0, 0, 0, 0, 0 };
-        LLDPTLV dpidTLV = new LLDPTLV().setType((byte) 127)
-                                       .setLength((short) dpidTLVValue.length)
-                                       .setValue(dpidTLVValue);
-
-        byte[] dpidArray = new byte[8];
-        ByteBuffer dpidBB = ByteBuffer.wrap(dpidArray);
-        ByteBuffer portBB = ByteBuffer.wrap(portId, 1, 2);
-
-        Long dpid = sw;
-        dpidBB.putLong(dpid);
-        // set the chassis id's value to last 6 bytes of dpid
-        System.arraycopy(dpidArray, 2, chassisId, 1, 6);
-        // set the optional tlv to the full dpid
-        System.arraycopy(dpidArray, 0, dpidTLVValue, 4, 8);
-
-        // TODO: Consider remove this block of code.
-        // It's evil to overwrite port object. The the old code always
-        // overwrote mac address, we now only overwrite zero macs and
-        // log a warning, mostly for paranoia.
-        byte[] srcMac = ofpPort.getHardwareAddress();
-        byte[] zeroMac = { 0, 0, 0, 0, 0, 0 };
-        if (Arrays.equals(srcMac, zeroMac)) {
-            log.warn("Port {}/{} has zero hareware address"
-                             + "overwrite with lower 6 bytes of dpid",
-                     HexString.toHexString(dpid), ofpPort.getPortNumber());
-            System.arraycopy(dpidArray, 2, srcMac, 0, 6);
-        }
-
-        // set the portId to the outgoing port
-        portBB.putShort(port);
-        if (log.isTraceEnabled()) {
-            log.trace("Sending LLDP out of interface: {}/{}",
-                      HexString.toHexString(sw), port);
-        }
-
-        LLDP lldp = new LLDP();
-        lldp.setChassisId(new LLDPTLV().setType((byte) 1)
-                                       .setLength((short) chassisId.length)
-                                       .setValue(chassisId));
-        lldp.setPortId(new LLDPTLV().setType((byte) 2)
-                                    .setLength((short) portId.length)
-                                    .setValue(portId));
-        lldp.setTtl(new LLDPTLV().setType((byte) 3)
-                                 .setLength((short) ttlValue.length)
-                                 .setValue(ttlValue));
-        lldp.getOptionalTLVList().add(dpidTLV);
-
-        // Add the controller identifier to the TLV value.
-        lldp.getOptionalTLVList().add(controllerTLV);
-        if (isReverse) {
-            lldp.getOptionalTLVList().add(reverseTLV);
-        } else {
-            lldp.getOptionalTLVList().add(forwardTLV);
-        }
-
-        Ethernet ethernet;
-        if (isStandard) {
-            ethernet = new Ethernet().setSourceMACAddress(ofpPort.getHardwareAddress())
-                                     .setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING)
-                                     .setEtherType(Ethernet.TYPE_LLDP);
-            ethernet.setPayload(lldp);
-        } else {
-            BSN bsn = new BSN(BSN.BSN_TYPE_BDDP);
-            bsn.setPayload(lldp);
-
-            ethernet = new Ethernet().setSourceMACAddress(ofpPort.getHardwareAddress())
-                                     .setDestinationMACAddress(LLDP_BSN_DST_MAC_STRING)
-                                     .setEtherType(Ethernet.TYPE_BSN);
-            ethernet.setPayload(bsn);
-        }
-
-        // serialize and wrap in a packet out
-        byte[] data = ethernet.serialize();
-        OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory()
-                                                         .getMessage(OFType.PACKET_OUT);
-        po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
-        po.setInPort(OFPort.OFPP_NONE);
-
-        // set data and data length
-        po.setLengthU(OFPacketOut.MINIMUM_LENGTH + data.length);
-        po.setPacketData(data);
-
-        return po;
-    }
-
-    /**
-     * Get the LLDP sending period in seconds.
-     *
-     * @return LLDP sending period in seconds.
-     */
-    public int getLldpFrequency() {
-        return LLDP_TO_KNOWN_INTERVAL;
-    }
-
-    /**
-     * Get the LLDP timeout value in seconds
-     *
-     * @return LLDP timeout value in seconds
-     */
-    public int getLldpTimeout() {
-        return LINK_TIMEOUT;
-    }
-
-    @Override
-    public Map<NodePortTuple, Set<Link>> getPortLinks() {
-        return portLinks;
-    }
-
-    @Override
-    public Set<NodePortTuple> getSuppressLLDPsInfo() {
-        return suppressLinkDiscovery;
-    }
-
-    /**
-     * Add a switch port to the suppressed LLDP list. Remove any known links on
-     * the switch port.
-     */
-    @Override
-    public void AddToSuppressLLDPs(long sw, short port) {
-        NodePortTuple npt = new NodePortTuple(sw, port);
-        this.suppressLinkDiscovery.add(npt);
-        deleteLinksOnPort(npt, "LLDP suppressed.");
-    }
-
-    /**
-     * Remove a switch port from the suppressed LLDP list. Discover links on
-     * that switchport.
-     */
-    @Override
-    public void RemoveFromSuppressLLDPs(long sw, short port) {
-        NodePortTuple npt = new NodePortTuple(sw, port);
-        this.suppressLinkDiscovery.remove(npt);
-        discover(npt);
-    }
-
-    public boolean isShuttingDown() {
-        return shuttingDown;
-    }
-
-    @Override
-    public boolean isTunnelPort(long sw, short port) {
-        return false;
-    }
-
-    @Override
-    public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) {
-        if (info.getUnicastValidTime() != null) {
-            return ILinkDiscovery.LinkType.DIRECT_LINK;
-        } else if (info.getMulticastValidTime() != null) {
-            return ILinkDiscovery.LinkType.MULTIHOP_LINK;
-        }
-        return ILinkDiscovery.LinkType.INVALID_LINK;
-    }
-
-    @Override
-    public Set<Short> getQuarantinedPorts(long sw) {
-        Set<Short> qPorts = new HashSet<Short>();
-
-        Iterator<NodePortTuple> iter = quarantineQueue.iterator();
-        while (iter.hasNext()) {
-            NodePortTuple npt = iter.next();
-            if (npt.getNodeId() == sw) {
-                qPorts.add(npt.getPortId());
-            }
-        }
-        return qPorts;
-    }
-
-    @Override
-    public Map<Long, Set<Link>> getSwitchLinks() {
-        return this.switchLinks;
-    }
-
-    @Override
-    public void addMACToIgnoreList(long mac, int ignoreBits) {
-        MACRange range = new MACRange();
-        range.baseMAC = mac;
-        range.ignoreBits = ignoreBits;
-        ignoreMACSet.add(range);
-    }
-
-    @Override
-    public boolean isAutoPortFastFeature() {
-        return autoPortFastFeature;
-    }
-
-    @Override
-    public void setAutoPortFastFeature(boolean autoPortFastFeature) {
-        this.autoPortFastFeature = autoPortFastFeature;
-    }
-
-    @Override
-    public void addListener(ILinkDiscoveryListener listener) {
-        linkDiscoveryAware.add(listener);
-    }
-
-    @Override
-    public Map<Link, LinkInfo> getLinks() {
-        lock.readLock().lock();
-        Map<Link, LinkInfo> result;
-        try {
-            result = new HashMap<Link, LinkInfo>(links);
-        } finally {
-            lock.readLock().unlock();
-        }
-        return result;
-    }
-
-    @Override
-    public LinkInfo getLinkInfo(Link link) {
-        lock.readLock().lock();
-        LinkInfo linkInfo = links.get(link);
-        LinkInfo retLinkInfo = null;
-        if (linkInfo != null) {
-            retLinkInfo  = new LinkInfo(linkInfo);
-        }
-        lock.readLock().unlock();
-        return retLinkInfo;
-    }
-
-    @Override
-    public String getName() {
-        return MODULE_NAME;
-    }
-
-    //*********************
-    //   OFMessage Listener
-    //*********************
-
-    @Override
-    public Command receive(IOFSwitch sw, OFMessage msg,
-                           FloodlightContext cntx) {
-        switch (msg.getType()) {
-            case PACKET_IN:
-                ctrIncoming.updateCounterNoFlush();
-                return this.handlePacketIn(sw.getId(), (OFPacketIn) msg,
-                                           cntx);
-            default:
-                break;
-        }
-        return Command.CONTINUE;
-    }
-
-    @Override
-    public boolean isCallbackOrderingPrereq(OFType type, String name) {
-        return false;
-    }
-
-    @Override
-    public boolean isCallbackOrderingPostreq(OFType type, String name) {
-        return false;
-    }
-
-    //***********************************
-    //  Internal Methods - Packet-in Processing Related
-    //***********************************
-
-    protected Command handlePacketIn(long sw, OFPacketIn pi,
-                                     FloodlightContext cntx) {
-        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
-                           IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-
-        if (eth.getPayload() instanceof BSN) {
-            BSN bsn = (BSN) eth.getPayload();
-            if (bsn == null) return Command.STOP;
-            if (bsn.getPayload() == null) return Command.STOP;
-            // It could be a packet other than BSN LLDP, therefore
-            // continue with the regular processing.
-            if (bsn.getPayload() instanceof LLDP == false)
-                return Command.CONTINUE;
-            return handleLldp((LLDP) bsn.getPayload(), sw, pi.getInPort(), false, cntx);
-        } else if (eth.getPayload() instanceof LLDP) {
-            return handleLldp((LLDP) eth.getPayload(), sw, pi.getInPort(), true, cntx);
-        } else if (eth.getEtherType() < 1500) {
-            long destMac = eth.getDestinationMAC().toLong();
-            if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE) {
-                ctrLinkLocalDrops.updateCounterNoFlush();
-                if (log.isTraceEnabled()) {
-                    log.trace("Ignoring packet addressed to 802.1D/Q "
-                              + "reserved address.");
-                }
-                return Command.STOP;
-            }
-        }
-
-        if (ignorePacketInFromSource(eth.getSourceMAC().toLong())) {
-            ctrIgnoreSrcMacDrops.updateCounterNoFlush();
-            return Command.STOP;
-        }
-
-        // If packet-in is from a quarantine port, stop processing.
-        NodePortTuple npt = new NodePortTuple(sw, pi.getInPort());
-        if (quarantineQueue.contains(npt)) {
-            ctrQuarantineDrops.updateCounterNoFlush();
-            return Command.STOP;
-        }
-
-        return Command.CONTINUE;
-    }
-
-    private boolean ignorePacketInFromSource(long srcMAC) {
-        Iterator<MACRange> it = ignoreMACSet.iterator();
-        while (it.hasNext()) {
-            MACRange range = it.next();
-            long mask = ~0;
-            if (range.ignoreBits >= 0 && range.ignoreBits <= 48) {
-                mask = mask << range.ignoreBits;
-                if ((range.baseMAC & mask) == (srcMAC & mask)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private Command handleLldp(LLDP lldp, long sw, short inPort,
-                               boolean isStandard, FloodlightContext cntx) {
-        // If LLDP is suppressed on this port, ignore received packet as well
-        IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
-
-        if (!isIncomingDiscoveryAllowed(sw, inPort, isStandard))
-            return Command.STOP;
-
-        // If this is a malformed LLDP exit
-        if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3) {
-            return Command.STOP;
-        }
-
-        long myId = ByteBuffer.wrap(controllerTLV.getValue()).getLong();
-        long otherId = 0;
-        boolean myLLDP = false;
-        Boolean isReverse = null;
-
-        ByteBuffer portBB = ByteBuffer.wrap(lldp.getPortId().getValue());
-        portBB.position(1);
-
-        Short remotePort = portBB.getShort();
-        IOFSwitch remoteSwitch = null;
-
-        // Verify this LLDP packet matches what we're looking for
-        for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
-            if (lldptlv.getType() == 127 && lldptlv.getLength() == 12
-                && lldptlv.getValue()[0] == 0x0
-                && lldptlv.getValue()[1] == 0x26
-                && lldptlv.getValue()[2] == (byte) 0xe1
-                && lldptlv.getValue()[3] == 0x0) {
-                ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
-                remoteSwitch = floodlightProvider.getSwitch(dpidBB.getLong(4));
-            } else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8) {
-                otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong();
-                if (myId == otherId) myLLDP = true;
-            } else if (lldptlv.getType() == TLV_DIRECTION_TYPE
-                       && lldptlv.getLength() == TLV_DIRECTION_LENGTH) {
-                if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_FORWARD[0])
-                    isReverse = false;
-                else if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_REVERSE[0])
-                    isReverse = true;
-            }
-        }
-
-        if (myLLDP == false) {
-            // This is not the LLDP sent by this controller.
-            // If the LLDP message has multicast bit set, then we need to
-            // broadcast the packet as a regular packet (after checking IDs)
-            if (isStandard) {
-                if (log.isTraceEnabled()) {
-                    log.trace("Got a standard LLDP=[{}] that was not sent by" +
-                              " this controller. Not fowarding it.", lldp.toString());
-                }
-                return Command.STOP;
-            } else if (myId < otherId) {
-                if (log.isTraceEnabled()) {
-                    log.trace("Getting BDDP packets from a different controller"
-                              + "and letting it go through normal processing chain.");
-                }
-                return Command.CONTINUE;
-            }
-            return Command.STOP;
-        }
-
-        if (remoteSwitch == null) {
-            // Ignore LLDPs not generated by Floodlight, or from a switch that
-            // has recently
-            // disconnected, or from a switch connected to another Floodlight
-            // instance
-            if (log.isTraceEnabled()) {
-                log.trace("Received LLDP from remote switch not connected to the controller");
-            }
-            return Command.STOP;
-        }
-
-        if (!remoteSwitch.portEnabled(remotePort)) {
-            if (log.isTraceEnabled()) {
-                log.trace("Ignoring link with disabled source port: switch {} port {} {}",
-                          new Object[] { remoteSwitch.getStringId(),
-                                         remotePort,
-                                         remoteSwitch.getPort(remotePort)});
-            }
-            return Command.STOP;
-        }
-        if (suppressLinkDiscovery.contains(new NodePortTuple(
-                                                             remoteSwitch.getId(),
-                                                             remotePort))) {
-            if (log.isTraceEnabled()) {
-                log.trace("Ignoring link with suppressed src port: switch {} port {} {}",
-                          new Object[] { remoteSwitch.getStringId(),
-                                         remotePort,
-                                         remoteSwitch.getPort(remotePort)});
-            }
-            return Command.STOP;
-        }
-        if (!iofSwitch.portEnabled(inPort)) {
-            if (log.isTraceEnabled()) {
-                log.trace("Ignoring link with disabled dest port: switch {} port {} {}",
-                          new Object[] { HexString.toHexString(sw),
-                                         inPort,
-                                         iofSwitch.getPort(inPort)});
-            }
-            return Command.STOP;
-        }
-
-        // Store the time of update to this link, and push it out to
-        // routingEngine
-        Link lt = new Link(remoteSwitch.getId(), remotePort,
-                           iofSwitch.getId(), inPort);
-
-        if (!isLinkAllowed(lt.getSrc(), lt.getSrcPort(),
-                           lt.getDst(), lt.getDstPort()))
-            return Command.STOP;
-
-        // Continue only if link is allowed.
-        Long lastLldpTime = null;
-        Long lastBddpTime = null;
-
-        Long firstSeenTime = System.currentTimeMillis();
-
-        if (isStandard)
-            lastLldpTime = System.currentTimeMillis();
-        else
-            lastBddpTime = System.currentTimeMillis();
-
-        LinkInfo newLinkInfo = new LinkInfo(firstSeenTime, lastLldpTime,
-                                            lastBddpTime);
-
-        addOrUpdateLink(lt, newLinkInfo);
-
-        // Check if reverse link exists.
-        // If it doesn't exist and if the forward link was seen
-        // first seen within a small interval, send probe on the
-        // reverse link.
-        newLinkInfo = links.get(lt);
-        if (newLinkInfo != null && isStandard && isReverse == false) {
-            Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
-                                        lt.getSrc(), lt.getSrcPort());
-            LinkInfo reverseInfo = links.get(reverseLink);
-            if (reverseInfo == null) {
-                // the reverse link does not exist.
-                if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis()
-                                                     - LINK_TIMEOUT) {
-                    this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(),
-                                              isStandard, true);
-                }
-            }
-        }
-
-        // If the received packet is a BDDP packet, then create a reverse BDDP
-        // link as well.
-        if (!isStandard) {
-            Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
-                                        lt.getSrc(), lt.getSrcPort());
-
-            // srcPortState and dstPort state are reversed.
-            LinkInfo reverseInfo = new LinkInfo(firstSeenTime, lastLldpTime,
-                                                lastBddpTime);
-
-            addOrUpdateLink(reverseLink, reverseInfo);
-        }
-
-        // Remove the node ports from the quarantine and maintenance queues.
-        NodePortTuple nptSrc = new NodePortTuple(lt.getSrc(),
-                                                 lt.getSrcPort());
-        NodePortTuple nptDst = new NodePortTuple(lt.getDst(),
-                                                 lt.getDstPort());
-        removeFromQuarantineQueue(nptSrc);
-        removeFromMaintenanceQueue(nptSrc);
-        removeFromQuarantineQueue(nptDst);
-        removeFromMaintenanceQueue(nptDst);
-
-        // Consume this message
-        ctrLldpEol.updateCounterNoFlush();
-        return Command.STOP;
-    }
-
-    //***********************************
-    //  Internal Methods - Port Status/ New Port Processing Related
-    //***********************************
-    /**
-     * Process a new port. If link discovery is disabled on the port, then do
-     * nothing. If autoportfast feature is enabled and the port is a fast port,
-     * then do nothing. Otherwise, send LLDP message. Add the port to
-     * quarantine.
-     *
-     * @param sw
-     * @param p
-     */
-    private void processNewPort(long sw, short p) {
-        if (isLinkDiscoverySuppressed(sw, p)) {
-            // Do nothing as link discovery is suppressed.
-            return;
-        }
-
-        IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
-        if (iofSwitch == null) return;
-
-        if (autoPortFastFeature && iofSwitch.isFastPort(p)) {
-            // Do nothing as the port is a fast port.
-            return;
-        }
-        NodePortTuple npt = new NodePortTuple(sw, p);
-        discover(sw, p);
-        // if it is not a fast port, add it to quarantine.
-        if (!iofSwitch.isFastPort(p)) {
-            addToQuarantineQueue(npt);
-        } else {
-            // Add to maintenance queue to ensure that BDDP packets
-            // are sent out.
-            addToMaintenanceQueue(npt);
-        }
-    }
-
-    //***********************************
-    //  Internal Methods - Discovery Related
-    //***********************************
-
-    @LogMessageDoc(level = "ERROR",
-                   message = "Error in link discovery updates loop",
-                   explanation = "An unknown error occured while dispatching "
-                                 + "link update notifications",
-                   recommendation = LogMessageDoc.GENERIC_ACTION)
-    private void doUpdatesThread() throws InterruptedException {
-        do {
-            LDUpdate update = updates.take();
-            List<LDUpdate> updateList = new ArrayList<LDUpdate>();
-            updateList.add(update);
-
-            // Add all the pending updates to the list.
-            while (updates.peek() != null) {
-                updateList.add(updates.remove());
-            }
-
-            if (linkDiscoveryAware != null) {
-                if (log.isTraceEnabled()) {
-                    log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
-                              new Object[] {
-                                            update.getOperation(),
-                                            HexString.toHexString(update.getSrc()),
-                                            update.getSrcPort(),
-                                            HexString.toHexString(update.getDst()),
-                                            update.getDstPort(),
-                                            linkDiscoveryAware });
-                }
-                try {
-                    for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order
-                        // maintained
-                        lda.linkDiscoveryUpdate(updateList);
-                    }
-                } catch (Exception e) {
-                    log.error("Error in link discovery updates loop", e);
-                }
-            }
-        } while (updates.peek() != null);
-    }
-
-    protected boolean isLinkDiscoverySuppressed(long sw, short portNumber) {
-        return this.suppressLinkDiscovery.contains(new NodePortTuple(sw,
-                                                                     portNumber));
-    }
-
-    protected void discoverLinks() {
-
-        // timeout known links.
-        timeoutLinks();
-
-        // increment LLDP clock
-        lldpClock = (lldpClock + 1) % LLDP_TO_ALL_INTERVAL;
-
-        if (lldpClock == 0) {
-            if (log.isTraceEnabled())
-                log.trace("Sending LLDP out on all ports.");
-            discoverOnAllPorts();
-        }
-    }
-
-    /**
-     * Quarantine Ports.
-     */
-    protected class QuarantineWorker implements Runnable {
-        @Override
-        public void run() {
-            try {
-                processBDDPLists();
-            } catch (Exception e) {
-                log.error("Error in quarantine worker thread", e);
-            } finally {
-                bddpTask.reschedule(BDDP_TASK_INTERVAL,
-                                    TimeUnit.MILLISECONDS);
-            }
-        }
-    }
-
-    /**
-     * Add a switch port to the quarantine queue. Schedule the quarantine task
-     * if the quarantine queue was empty before adding this switch port.
-     *
-     * @param npt
-     */
-    protected void addToQuarantineQueue(NodePortTuple npt) {
-        if (quarantineQueue.contains(npt) == false)
-                                                   quarantineQueue.add(npt);
-    }
-
-    /**
-     * Remove a switch port from the quarantine queue.
-     */
-    protected void removeFromQuarantineQueue(NodePortTuple npt) {
-        // Remove all occurrences of the node port tuple from the list.
-        while (quarantineQueue.remove(npt))
-            ;
-    }
-
-    /**
-     * Add a switch port to maintenance queue.
-     *
-     * @param npt
-     */
-    protected void addToMaintenanceQueue(NodePortTuple npt) {
-        // TODO We are not checking if the switch port tuple is already
-        // in the maintenance list or not. This will be an issue for
-        // really large number of switch ports in the network.
-        if (maintenanceQueue.contains(npt) == false)
-                                                    maintenanceQueue.add(npt);
-    }
-
-    /**
-     * Remove a switch port from maintenance queue.
-     *
-     * @param npt
-     */
-    protected void removeFromMaintenanceQueue(NodePortTuple npt) {
-        // Remove all occurrences of the node port tuple from the queue.
-        while (maintenanceQueue.remove(npt))
-            ;
-    }
-
-    /**
-     * This method processes the quarantine list in bursts. The task is at most
-     * once per BDDP_TASK_INTERVAL. One each call, BDDP_TASK_SIZE number of
-     * switch ports are processed. Once the BDDP packets are sent out through
-     * the switch ports, the ports are removed from the quarantine list.
-     */
-    protected void processBDDPLists() {
-        int count = 0;
-        Set<NodePortTuple> nptList = new HashSet<NodePortTuple>();
-
-        while (count < BDDP_TASK_SIZE && quarantineQueue.peek() != null) {
-            NodePortTuple npt;
-            npt = quarantineQueue.remove();
-            sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false,
-                                 false);
-            nptList.add(npt);
-            count++;
-        }
-
-        count = 0;
-        while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) {
-            NodePortTuple npt;
-            npt = maintenanceQueue.remove();
-            sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false,
-                                 false);
-            count++;
-        }
-
-        for (NodePortTuple npt : nptList) {
-            generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId());
-        }
-    }
-
-    private void generateSwitchPortStatusUpdate(long sw, short port) {
-        UpdateOperation operation;
-
-        IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
-        if (iofSwitch == null) return;
-
-        OFPhysicalPort ofp = iofSwitch.getPort(port).toOFPhysicalPort();
-        if (ofp == null) return;
-
-        int srcPortState = ofp.getState();
-        boolean portUp = ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue())
-                               != OFPortState.OFPPS_STP_BLOCK.getValue());
-
-        if (portUp)
-            operation = UpdateOperation.PORT_UP;
-        else
-            operation = UpdateOperation.PORT_DOWN;
-
-        updates.add(new LDUpdate(sw, port, operation));
-    }
-
-    protected void discover(NodePortTuple npt) {
-        discover(npt.getNodeId(), npt.getPortId());
-    }
-
-    protected void discover(long sw, short port) {
-        sendDiscoveryMessage(sw, port, true, false);
-    }
-
-    /**
-     * Check if incoming discovery messages are enabled or not.
-     * @param sw
-     * @param port
-     * @param isStandard
-     * @return
-     */
-    protected boolean isIncomingDiscoveryAllowed(long sw, short port,
-                                                 boolean isStandard) {
-
-        if (isLinkDiscoverySuppressed(sw, port)) {
-            /* Do not process LLDPs from this port as suppressLLDP is set */
-            return false;
-        }
-
-        IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
-        if (iofSwitch == null) {
-            return false;
-        }
-
-        if (port == OFPort.OFPP_LOCAL.getValue()) return false;
-
-        ImmutablePort ofpPort = iofSwitch.getPort(port);
-        if (ofpPort == null) {
-            if (log.isTraceEnabled()) {
-                log.trace("Null physical port. sw={}, port={}",
-                          HexString.toHexString(sw), port);
-            }
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Check if outgoing discovery messages are enabled or not.
-     * @param sw
-     * @param port
-     * @param isStandard
-     * @param isReverse
-     * @return
-     */
-    protected boolean isOutgoingDiscoveryAllowed(long sw, short port,
-                                                 boolean isStandard,
-                                                 boolean isReverse) {
-
-        if (isLinkDiscoverySuppressed(sw, port)) {
-            /* Dont send LLDPs out of this port as suppressLLDP is set */
-            return false;
-        }
-
-        IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
-        if (iofSwitch == null) {
-            return false;
-        }
-
-        if (port == OFPort.OFPP_LOCAL.getValue()) return false;
-
-        ImmutablePort ofpPort = iofSwitch.getPort(port);
-        if (ofpPort == null) {
-            if (log.isTraceEnabled()) {
-                log.trace("Null physical port. sw={}, port={}",
-                          HexString.toHexString(sw), port);
-            }
-            return false;
-        }
-
-        // For fast ports, do not send forward LLDPs or BDDPs.
-        if (!isReverse && autoPortFastFeature && iofSwitch.isFastPort(port))
-            return false;
-        return true;
-    }
-
-    /**
-     * Get the actions for packet-out corresponding to a specific port.
-     * This is a placeholder for adding actions if any port-specific
-     * actions are desired.  The default action is simply to output to
-     * the given port.
-     * @param port
-     * @return
-     */
-    protected List<OFAction> getDiscoveryActions (IOFSwitch sw, OFPhysicalPort port){
-        // set actions
-        List<OFAction> actions = new ArrayList<OFAction>();
-        actions.add(new OFActionOutput(port.getPortNumber(), (short) 0));
-        return actions;
-    }
-
-    /**
-     * Send link discovery message out of a given switch port. The discovery
-     * message may be a standard LLDP or a modified LLDP, where the dst mac
-     * address is set to :ff. TODO: The modified LLDP will updated in the future
-     * and may use a different eth-type.
-     *
-     * @param sw
-     * @param port
-     * @param isStandard
-     *            indicates standard or modified LLDP
-     * @param isReverse
-     *            indicates whether the LLDP was sent as a response
-     */
-    @LogMessageDoc(level = "ERROR",
-                   message = "Failure sending LLDP out port {port} on switch {switch}",
-                   explanation = "An I/O error occured while sending LLDP message "
-                                 + "to the switch.",
-                   recommendation = LogMessageDoc.CHECK_SWITCH)
-    protected void sendDiscoveryMessage(long sw, short port,
-                                        boolean isStandard, boolean isReverse) {
-
-        // Takes care of all checks including null pointer checks.
-        if (!isOutgoingDiscoveryAllowed(sw, port, isStandard, isReverse))
-            return;
-
-        IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
-        OFPhysicalPort ofpPort = iofSwitch.getPort(port).toOFPhysicalPort();
-
-        if (log.isTraceEnabled()) {
-            log.trace("Sending LLDP packet out of swich: {}, port: {}",
-                      HexString.toHexString(sw), port);
-        }
-        OFPacketOut po = generateLLDPMessage(sw, port, isStandard, isReverse);
-
-        // Add actions
-        List<OFAction> actions = getDiscoveryActions(iofSwitch, ofpPort);
-        po.setActions(actions);
-        short  actionLength = 0;
-        Iterator <OFAction> actionIter = actions.iterator();
-        while (actionIter.hasNext()) {
-            actionLength += actionIter.next().getLength();
-        }
-        po.setActionsLength(actionLength);
-
-        // po already has the minimum length + data length set
-        // simply add the actions length to this.
-        po.setLengthU(po.getLengthU() + po.getActionsLength());
-
-        // send
-        try {
-            iofSwitch.write(po, null);
-            iofSwitch.flush();
-        } catch (IOException e) {
-            log.error("Failure sending LLDP out port {} on switch {}",
-                      new Object[] { port, iofSwitch.getStringId() }, e);
-        }
-    }
-
-    /**
-     * Send LLDPs to all switch-ports
-     */
-    protected void discoverOnAllPorts() {
-        if (log.isTraceEnabled()) {
-            log.trace("Sending LLDP packets out of all the enabled ports");
-        }
-        // Send standard LLDPs
-        for (long sw : floodlightProvider.getAllSwitchDpids()) {
-            IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
-            if (iofSwitch == null) continue;
-            if (iofSwitch.getEnabledPorts() != null) {
-                for (ImmutablePort ofp : iofSwitch.getEnabledPorts()) {
-                    if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber()))
-                                                                           continue;
-                    if (autoPortFastFeature
-                        && iofSwitch.isFastPort(ofp.getPortNumber()))
-                                                                     continue;
-
-                    // sends forward LLDP only non-fastports.
-                    sendDiscoveryMessage(sw, ofp.getPortNumber(), true,
-                                         false);
-
-                    // If the switch port is not already in the maintenance
-                    // queue, add it.
-                    NodePortTuple npt = new NodePortTuple(
-                                                          sw,
-                                                          ofp.getPortNumber());
-                    addToMaintenanceQueue(npt);
-                }
-            }
-        }
-    }
-
-    protected UpdateOperation getUpdateOperation(int srcPortState,
-                                                 int dstPortState) {
-        boolean added = (((srcPortState & OFPortState.OFPPS_STP_MASK.getValue())
-                                != OFPortState.OFPPS_STP_BLOCK.getValue()) &&
-                          ((dstPortState & OFPortState.OFPPS_STP_MASK.getValue())
-                                != OFPortState.OFPPS_STP_BLOCK.getValue()));
-
-        if (added) return UpdateOperation.LINK_UPDATED;
-        return UpdateOperation.LINK_REMOVED;
-    }
-
-    protected UpdateOperation getUpdateOperation(int srcPortState) {
-        boolean portUp = ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) != OFPortState.OFPPS_STP_BLOCK.getValue());
-
-        if (portUp)
-            return UpdateOperation.PORT_UP;
-        else
-            return UpdateOperation.PORT_DOWN;
-    }
-
-    //************************************
-    // Internal Methods - Link Operations Related
-    //************************************
-
-    /**
-     * This method is used to specifically ignore/consider specific links.
-     */
-    protected boolean isLinkAllowed(long src, short srcPort,
-                                    long dst, short dstPort) {
-        return true;
-    }
-
-    private boolean addLink(Link lt, LinkInfo newInfo) {
-        NodePortTuple srcNpt, dstNpt;
-
-        srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
-        dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
-
-        // index it by switch source
-        if (!switchLinks.containsKey(lt.getSrc()))
-            switchLinks.put(lt.getSrc(),
-                            new HashSet<Link>());
-        switchLinks.get(lt.getSrc()).add(lt);
-
-        // index it by switch dest
-        if (!switchLinks.containsKey(lt.getDst()))
-            switchLinks.put(lt.getDst(),
-                            new HashSet<Link>());
-        switchLinks.get(lt.getDst()).add(lt);
-
-        // index both ends by switch:port
-        if (!portLinks.containsKey(srcNpt))
-            portLinks.put(srcNpt,
-                          new HashSet<Link>());
-        portLinks.get(srcNpt).add(lt);
-
-        if (!portLinks.containsKey(dstNpt))
-            portLinks.put(dstNpt,
-                          new HashSet<Link>());
-        portLinks.get(dstNpt).add(lt);
-
-        return true;
-    }
-
-    protected boolean updateLink(Link lt, LinkInfo oldInfo, LinkInfo newInfo) {
-        boolean linkChanged = false;
-        // Since the link info is already there, we need to
-        // update the right fields.
-        if (newInfo.getUnicastValidTime() == null) {
-            // This is due to a multicast LLDP, so copy the old unicast
-            // value.
-            if (oldInfo.getUnicastValidTime() != null) {
-                newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime());
-            }
-        } else if (newInfo.getMulticastValidTime() == null) {
-            // This is due to a unicast LLDP, so copy the old multicast
-            // value.
-            if (oldInfo.getMulticastValidTime() != null) {
-                newInfo.setMulticastValidTime(oldInfo.getMulticastValidTime());
-            }
-        }
-
-        Long oldTime = oldInfo.getUnicastValidTime();
-        Long newTime = newInfo.getUnicastValidTime();
-        // the link has changed its state between openflow and
-        // non-openflow
-        // if the unicastValidTimes are null or not null
-        if (oldTime != null & newTime == null) {
-            linkChanged = true;
-        } else if (oldTime == null & newTime != null) {
-            linkChanged = true;
-        }
-
-        return linkChanged;
-    }
-
-    @LogMessageDocs({
-        @LogMessageDoc(message="Inter-switch link detected:",
-                explanation="Detected a new link between two openflow switches," +
-                            "use show link to find current status"),
-        @LogMessageDoc(message="Inter-switch link updated:",
-                explanation="Detected a link change between two openflow switches, " +
-                            "use show link to find current status")
-    })
-    protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {
-
-        boolean linkChanged = false;
-
-        lock.writeLock().lock();
-        try {
-            // put the new info. if an old info exists, it will be returned.
-            LinkInfo oldInfo = links.put(lt, newInfo);
-            if (oldInfo != null
-                    && oldInfo.getFirstSeenTime() < newInfo.getFirstSeenTime())
-                newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime());
-
-            if (log.isTraceEnabled()) {
-                log.trace("addOrUpdateLink: {} {}",
-                          lt,
-                          (newInfo.getMulticastValidTime() != null) ? "multicast"
-                                                                      : "unicast");
-            }
-
-            UpdateOperation updateOperation = null;
-            linkChanged = false;
-
-            if (oldInfo == null) {
-                addLink(lt, newInfo);
-                updateOperation = UpdateOperation.LINK_UPDATED;
-                linkChanged = true;
-
-                // Log direct links only. Multi-hop links may be numerous
-                // Add all to event history
-                LinkType linkType = getLinkType(lt, newInfo);
-                if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) {
-                    log.info("Inter-switch link detected: {}", lt);
-                    evDirectLink.updateEventNoFlush(new DirectLinkEvent(lt.getSrc(),
-                         lt.getSrcPort(), lt.getDst(), lt.getDstPort(), "direct-link-added::rcvd LLDP"));
-                }
-                notifier.postNotification("Link added: " + lt.toString());
-            } else {
-                linkChanged = updateLink(lt, oldInfo, newInfo);
-                if (linkChanged) {
-                    updateOperation = UpdateOperation.LINK_UPDATED;
-                    LinkType linkType = getLinkType(lt, newInfo);
-                    if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) {
-                        log.info("Inter-switch link updated: {}", lt);
-                        evDirectLink.updateEventNoFlush(new DirectLinkEvent(lt.getSrc(),
-                            lt.getSrcPort(), lt.getDst(), lt.getDstPort(),
-                            "link-port-state-updated::rcvd LLDP"));
-                    }
-                    notifier.postNotification("Link updated: " + lt.toString());
-                }
-            }
-
-            // Write changes to storage. This will always write the updated
-            // valid time, plus the port states if they've changed (i.e. if
-            // they weren't set to null in the previous block of code.
-            writeLinkToStorage(lt, newInfo);
-
-            if (linkChanged) {
-                // find out if the link was added or removed here.
-                updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
-                                         lt.getDst(), lt.getDstPort(),
-                                         getLinkType(lt, newInfo),
-                                         updateOperation));
-            }
-        } finally {
-            lock.writeLock().unlock();
-        }
-
-        return linkChanged;
-    }
-
-    /**
-     * Delete a link
-     *
-     * @param link
-     *            - link to be deleted.
-     * @param reason
-     *            - reason why the link is deleted.
-     */
-    protected void deleteLink(Link link, String reason) {
-        if (link == null)
-            return;
-        List<Link> linkList = new ArrayList<Link>();
-        linkList.add(link);
-        deleteLinks(linkList, reason);
-    }
-    /**
-     * Removes links from memory and storage.
-     *
-     * @param links
-     *            The List of @LinkTuple to delete.
-     */
-    protected void deleteLinks(List<Link> links, String reason) {
-        deleteLinks(links, reason, null);
-    }
-
-    /**
-     * Removes links from memory and storage.
-     *
-     * @param links
-     *            The List of @LinkTuple to delete.
-     */
-    @LogMessageDoc(message="Inter-switch link removed:",
-            explanation="A previously detected link between two openflow switches no longer exists, " +
-                        "use show link to find current status")
-    protected void deleteLinks(List<Link> links, String reason,
-                               List<LDUpdate> updateList) {
-
-        NodePortTuple srcNpt, dstNpt;
-        List<LDUpdate> linkUpdateList = new ArrayList<LDUpdate>();
-        lock.writeLock().lock();
-        try {
-            for (Link lt : links) {
-                srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
-                dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
-
-                if (switchLinks.containsKey(lt.getSrc())) {
-                    switchLinks.get(lt.getSrc()).remove(lt);
-                    if (switchLinks.get(lt.getSrc()).isEmpty())
-                        this.switchLinks.remove(lt.getSrc());
-                }
-                if (this.switchLinks.containsKey(lt.getDst())) {
-                    switchLinks.get(lt.getDst()).remove(lt);
-                    if (this.switchLinks.get(lt.getDst()).isEmpty())
-                        this.switchLinks.remove(lt.getDst());
-                }
-
-                if (this.portLinks.get(srcNpt) != null) {
-                    this.portLinks.get(srcNpt).remove(lt);
-                    if (this.portLinks.get(srcNpt).isEmpty())
-                                                             this.portLinks.remove(srcNpt);
-                }
-                if (this.portLinks.get(dstNpt) != null) {
-                    this.portLinks.get(dstNpt).remove(lt);
-                    if (this.portLinks.get(dstNpt).isEmpty())
-                                                             this.portLinks.remove(dstNpt);
-                }
-
-                LinkInfo info = this.links.remove(lt);
-                LinkType linkType = getLinkType(lt, info);
-                linkUpdateList.add(new LDUpdate(lt.getSrc(),
-                                                lt.getSrcPort(),
-                                                lt.getDst(),
-                                                lt.getDstPort(),
-                                                linkType,
-                                                UpdateOperation.LINK_REMOVED));
-
-                // FIXME: link type shows up as invalid now -- thus not checking if
-                // link type is a direct link
-                evDirectLink.updateEventWithFlush(new DirectLinkEvent(lt.getSrc(),
-                      lt.getSrcPort(), lt.getDst(), lt.getDstPort(),
-                      "link-deleted::" + reason));
-                // remove link from storage.
-                removeLinkFromStorage(lt);
-
-                // TODO Whenever link is removed, it has to checked if
-                // the switchports must be added to quarantine.
-
-                if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) {
-                    log.info("Inter-switch link removed: {}", lt);
-                    notifier.postNotification("Inter-switch link removed: " +
-                                              lt.toString());
-                } else if (log.isTraceEnabled()) {
-                    log.trace("Deleted link {}", lt);
-                }
-            }
-        } finally {
-            if (updateList != null) linkUpdateList.addAll(updateList);
-            updates.addAll(linkUpdateList);
-            lock.writeLock().unlock();
-        }
-    }
-
-    /**
-     * Delete links incident on a given switch port.
-     *
-     * @param npt
-     * @param reason
-     */
-    protected void deleteLinksOnPort(NodePortTuple npt, String reason) {
-        List<Link> eraseList = new ArrayList<Link>();
-        if (this.portLinks.containsKey(npt)) {
-            if (log.isTraceEnabled()) {
-                log.trace("handlePortStatus: Switch {} port #{} "
-                                  + "removing links {}",
-                          new Object[] {
-                                        HexString.toHexString(npt.getNodeId()),
-                                        npt.getPortId(),
-                                        this.portLinks.get(npt) });
-            }
-            eraseList.addAll(this.portLinks.get(npt));
-            deleteLinks(eraseList, reason);
-        }
-    }
-
-    /**
-     * Iterates through the list of links and deletes if the last discovery
-     * message reception time exceeds timeout values.
-     */
-    protected void timeoutLinks() {
-        List<Link> eraseList = new ArrayList<Link>();
-        Long curTime = System.currentTimeMillis();
-        boolean linkChanged = false;
-
-        // reentrant required here because deleteLink also write locks
-        lock.writeLock().lock();
-        try {
-            Iterator<Entry<Link, LinkInfo>> it = this.links.entrySet()
-                                                           .iterator();
-            while (it.hasNext()) {
-                Entry<Link, LinkInfo> entry = it.next();
-                Link lt = entry.getKey();
-                LinkInfo info = entry.getValue();
-
-                // Timeout the unicast and multicast LLDP valid times
-                // independently.
-                if ((info.getUnicastValidTime() != null)
-                    && (info.getUnicastValidTime()
-                        + (this.LINK_TIMEOUT * 1000) < curTime)) {
-                    info.setUnicastValidTime(null);
-                    linkChanged = true;
-                }
-                if ((info.getMulticastValidTime() != null)
-                    && (info.getMulticastValidTime()
-                        + (this.LINK_TIMEOUT * 1000) < curTime)) {
-                    info.setMulticastValidTime(null);
-                    linkChanged = true;
-                }
-                // Add to the erase list only if the unicast
-                // time is null.
-                if (info.getUnicastValidTime() == null
-                    && info.getMulticastValidTime() == null) {
-                    eraseList.add(entry.getKey());
-                } else if (linkChanged) {
-                    updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
-                                             lt.getDst(), lt.getDstPort(),
-                                             getLinkType(lt, info),
-                                             UpdateOperation.LINK_UPDATED));
-                }
-            }
-
-            // if any link was deleted or any link was changed.
-            if ((eraseList.size() > 0) || linkChanged) {
-                deleteLinks(eraseList, "LLDP timeout");
-            }
-        } finally {
-            lock.writeLock().unlock();
-        }
-    }
-
-    //******************
-    // Internal Helper Methods
-    //******************
-    @LogMessageDoc(level="WARN",
-            message="Could not get list of interfaces of local machine to " +
-                     "encode in TLV: {detail-msg}",
-            explanation="Outgoing LLDP packets encode a unique hash to " +
-                     "identify the local machine. The list of network " +
-                     "interfaces is used as input and the controller failed " +
-                     "to query this list",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    protected void setControllerTLV() {
-        // Setting the controllerTLVValue based on current nano time,
-        // controller's IP address, and the network interface object hash
-        // the corresponding IP address.
-
-        final int prime = 7867;
-
-        byte[] controllerTLVValue = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; // 8
-                                                                           // byte
-                                                                           // value.
-        ByteBuffer bb = ByteBuffer.allocate(10);
-
-        long result = System.nanoTime();
-        try{
-            // Use some data specific to the machine this controller is
-            // running on. In this case: the list of network interfaces
-            Enumeration<NetworkInterface> ifaces =
-                    NetworkInterface.getNetworkInterfaces();
-            if (ifaces != null) {
-                result = result * prime + ifaces.hashCode();
-            }
-        } catch (SocketException e) {
-            log.warn("Could not get list of interfaces of local machine to " +
-                     "encode in TLV: {}", e.toString());
-        }
-        // set the first 4 bits to 0.
-        result = result & (0x0fffffffffffffffL);
-
-        bb.putLong(result);
-
-        bb.rewind();
-        bb.get(controllerTLVValue, 0, 8);
-
-        this.controllerTLV = new LLDPTLV().setType((byte) 0x0c)
-                                          .setLength((short) controllerTLVValue.length)
-                                          .setValue(controllerTLVValue);
-    }
-
-    //******************
-    // IOFSwitchListener
-    //******************
-    private void handlePortDown(long switchId, short portNumber) {
-            NodePortTuple npt = new NodePortTuple(switchId, portNumber);
-            deleteLinksOnPort(npt, "Port Status Changed");
-            LDUpdate update = new LDUpdate(switchId, portNumber,
-                    UpdateOperation.PORT_DOWN);
-            updates.add(update);
-    }
-    /**
-     * We don't react the port changed notifications here. we listen for
-     * OFPortStatus messages directly. Might consider using this notifier
-     * instead
-     */
-    @Override
-    public void switchPortChanged(long switchId,
-            ImmutablePort port,
-            IOFSwitch.PortChangeType type) {
-
-        switch (type) {
-        case UP:
-            processNewPort(switchId, port.getPortNumber());
-            break;
-        case DELETE: case DOWN:
-            handlePortDown(switchId, port.getPortNumber());
-            break;
-        case OTHER_UPDATE: case ADD:
-            // This is something other than port add or delete.
-            // Topology does not worry about this.
-            // If for some reason the port features change, which
-            // we may have to react.
-            break;
-        }
-    }
-
-    @Override
-    public void switchAdded(long switchId) {
-        // no-op
-        // We don't do anything at switch added, but we do only when the
-        // switch is activated.
-    }
-
-    @Override
-    public void switchRemoved(long sw) {
+IOFSwitchListener, IStorageSourceListener, ILinkDiscoveryService,
+IFloodlightModule, IInfoProvider {
+	protected static final Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
+	protected static final INotificationManager notifier =
+			NotificationManagerFactory.getNotificationManager(LinkDiscoveryManager.class);
+
+	public static final String MODULE_NAME = "linkdiscovery";
+
+	// Names of table/fields for links in the storage API
+	private static final String TOPOLOGY_TABLE_NAME = "controller_topologyconfig";
+	private static final String TOPOLOGY_ID = "id";
+	private static final String TOPOLOGY_AUTOPORTFAST = "autoportfast";
+
+	private static final String LINK_TABLE_NAME = "controller_link";
+	private static final String LINK_ID = "id";
+	private static final String LINK_SRC_SWITCH = "src_switch_id";
+	private static final String LINK_SRC_PORT = "src_port";
+	private static final String LINK_DST_SWITCH = "dst_switch_id";
+	private static final String LINK_DST_PORT = "dst_port";
+	private static final String LINK_VALID_TIME = "valid_time";
+	private static final String LINK_TYPE = "link_type";
+	private static final String SWITCH_CONFIG_TABLE_NAME = "controller_switchconfig";
+
+	// Event updaters for debug events
+	protected IEventCategory<DirectLinkEvent> eventCategory;
+
+	protected IFloodlightProviderService floodlightProviderService;
+	protected IOFSwitchService switchService;
+	protected IStorageSourceService storageSourceService;
+	protected IThreadPoolService threadPoolService;
+	protected IRestApiService restApiService;
+	protected IDebugCounterService debugCounterService;
+	protected IDebugEventService debugEventService;
+	protected IShutdownService shutdownService;
+
+	// Role
+	protected HARole role;
+
+	// LLDP and BDDP fields
+	private static final byte[] LLDP_STANDARD_DST_MAC_STRING =
+			HexString.fromHexString("01:80:c2:00:00:0e");
+	private static final long LINK_LOCAL_MASK = 0xfffffffffff0L;
+	private static final long LINK_LOCAL_VALUE = 0x0180c2000000L;
+	protected static int EVENT_HISTORY_SIZE = 1024; // in seconds
+
+	// BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version
+	// private static final String LLDP_BSN_DST_MAC_STRING =
+	// "5d:16:c7:00:00:01";
+	private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff";
+
+	// Direction TLVs are used to indicate if the LLDPs were sent
+	// periodically or in response to a recieved LLDP
+	private static final byte TLV_DIRECTION_TYPE = 0x73;
+	private static final short TLV_DIRECTION_LENGTH = 1; // 1 byte
+	private static final byte TLV_DIRECTION_VALUE_FORWARD[] = { 0x01 };
+	private static final byte TLV_DIRECTION_VALUE_REVERSE[] = { 0x02 };
+	private static final LLDPTLV forwardTLV = new LLDPTLV().setType(TLV_DIRECTION_TYPE)
+			.setLength(TLV_DIRECTION_LENGTH)
+			.setValue(TLV_DIRECTION_VALUE_FORWARD);
+
+	private static final LLDPTLV reverseTLV = new LLDPTLV().setType(TLV_DIRECTION_TYPE)
+			.setLength(TLV_DIRECTION_LENGTH)
+			.setValue(TLV_DIRECTION_VALUE_REVERSE);
+
+	// Link discovery task details.
+	protected SingletonTask discoveryTask;
+	protected final int DISCOVERY_TASK_INTERVAL = 1;
+	protected final int LINK_TIMEOUT = 35; // timeout as part of LLDP process.
+	protected final int LLDP_TO_ALL_INTERVAL = 15; // 15 seconds.
+	protected long lldpClock = 0;
+	// This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL.
+	// If we want to identify link failures faster, we could decrease this
+	// value to a small number, say 1 or 2 sec.
+	protected final int LLDP_TO_KNOWN_INTERVAL = 20; // LLDP frequency for known
+	// links
+
+	protected LLDPTLV controllerTLV;
+	protected ReentrantReadWriteLock lock;
+	int lldpTimeCount = 0;
+
+	/**
+	 * Flag to indicate if automatic port fast is enabled or not. Default is set
+	 * to false -- Initialized in the init method as well.
+	 */
+	protected boolean AUTOPORTFAST_DEFAULT = false;
+	protected boolean autoPortFastFeature = AUTOPORTFAST_DEFAULT;
+
+	/**
+	 * Map from link to the most recent time it was verified functioning
+	 */
+	protected Map<Link, LinkInfo> links;
+
+	/**
+	 * Map from switch id to a set of all links with it as an endpoint
+	 */
+	protected Map<DatapathId, Set<Link>> switchLinks;
+
+	/**
+	 * Map from a id:port to the set of links containing it as an endpoint
+	 */
+	protected Map<NodePortTuple, Set<Link>> portLinks;
+
+	protected volatile boolean shuttingDown = false;
+
+	/*
+	 * topology aware components are called in the order they were added to the
+	 * the array
+	 */
+	protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware;
+	protected BlockingQueue<LDUpdate> updates;
+	protected Thread updatesThread;
+
+	/**
+	 * List of ports through which LLDP/BDDPs are not sent.
+	 */
+	protected Set<NodePortTuple> suppressLinkDiscovery;
+
+	/**
+	 * A list of ports that are quarantined for discovering links through them.
+	 * Data traffic from these ports are not allowed until the ports are
+	 * released from quarantine.
+	 */
+	protected LinkedBlockingQueue<NodePortTuple> quarantineQueue;
+	protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue;
+	/**
+	 * Quarantine task
+	 */
+	protected SingletonTask bddpTask;
+	protected final int BDDP_TASK_INTERVAL = 100; // 100 ms.
+	protected final int BDDP_TASK_SIZE = 10; // # of ports per iteration
+
+	private class MACRange {
+		MacAddress baseMAC;
+		int ignoreBits;
+	}
+	protected Set<MACRange> ignoreMACSet;
+
+	private IHAListener haListener;
+
+	/**
+	 * Debug Counters
+	 */
+	private IDebugCounter ctrQuarantineDrops;
+	private IDebugCounter ctrIgnoreSrcMacDrops;
+	private IDebugCounter ctrIncoming;
+	private IDebugCounter ctrLinkLocalDrops;
+	private IDebugCounter ctrLldpEol;
+
+	private final String PACKAGE = LinkDiscoveryManager.class.getPackage().getName();
+
+
+	//*********************
+	// ILinkDiscoveryService
+	//*********************
+
+	@Override
+	public OFPacketOut generateLLDPMessage(DatapathId sw, OFPort port,
+			boolean isStandard, boolean isReverse) {
+
+		IOFSwitch iofSwitch = switchService.getSwitch(sw);
+		OFPortDesc ofpPort = iofSwitch.getPort(port);
+
+		if (log.isTraceEnabled()) {
+			log.trace("Sending LLDP packet out of swich: {}, port: {}",
+					sw.toString(), port);
+		}
+
+		// using "nearest customer bridge" MAC address for broadest possible
+		// propagation
+		// through provider and TPMR bridges (see IEEE 802.1AB-2009 and
+		// 802.1Q-2011),
+		// in particular the Linux bridge which behaves mostly like a provider
+		// bridge
+		byte[] chassisId = new byte[] { 4, 0, 0, 0, 0, 0, 0 }; // filled in
+		// later
+		byte[] portId = new byte[] { 2, 0, 0 }; // filled in later
+		byte[] ttlValue = new byte[] { 0, 0x78 };
+		// OpenFlow OUI - 00-26-E1
+		byte[] dpidTLVValue = new byte[] { 0x0, 0x26, (byte) 0xe1, 0, 0, 0,
+				0, 0, 0, 0, 0, 0 };
+		LLDPTLV dpidTLV = new LLDPTLV().setType((byte) 127)
+				.setLength((short) dpidTLVValue.length)
+				.setValue(dpidTLVValue);
+
+		byte[] dpidArray = new byte[8];
+		ByteBuffer dpidBB = ByteBuffer.wrap(dpidArray);
+		ByteBuffer portBB = ByteBuffer.wrap(portId, 1, 2);
+
+		DatapathId dpid = sw;
+		dpidBB.putLong(dpid.getLong());
+		// set the chassis id's value to last 6 bytes of dpid
+		System.arraycopy(dpidArray, 2, chassisId, 1, 6);
+		// set the optional tlv to the full dpid
+		System.arraycopy(dpidArray, 0, dpidTLVValue, 4, 8);
+
+		// TODO: Consider remove this block of code.
+		// It's evil to overwrite port object. The the old code always
+		// overwrote mac address, we now only overwrite zero macs and
+		// log a warning, mostly for paranoia.
+		byte[] srcMac = ofpPort.getHwAddr().getBytes();
+		byte[] zeroMac = { 0, 0, 0, 0, 0, 0 };
+		if (Arrays.equals(srcMac, zeroMac)) {
+			log.warn("Port {}/{} has zero hareware address"
+					+ "overwrite with lower 6 bytes of dpid",
+					dpid.toString(), ofpPort.getPortNo().getPortNumber());
+			System.arraycopy(dpidArray, 2, srcMac, 0, 6);
+		}
+
+		// set the portId to the outgoing port
+		portBB.putShort(port.getShortPortNumber());
+		if (log.isTraceEnabled()) {
+			log.trace("Sending LLDP out of interface: {}/{}",
+					sw.toString(), port);
+		}
+
+		LLDP lldp = new LLDP();
+		lldp.setChassisId(new LLDPTLV().setType((byte) 1)
+				.setLength((short) chassisId.length)
+				.setValue(chassisId));
+		lldp.setPortId(new LLDPTLV().setType((byte) 2)
+				.setLength((short) portId.length)
+				.setValue(portId));
+		lldp.setTtl(new LLDPTLV().setType((byte) 3)
+				.setLength((short) ttlValue.length)
+				.setValue(ttlValue));
+		lldp.getOptionalTLVList().add(dpidTLV);
+
+		// Add the controller identifier to the TLV value.
+		lldp.getOptionalTLVList().add(controllerTLV);
+		if (isReverse) {
+			lldp.getOptionalTLVList().add(reverseTLV);
+		} else {
+			lldp.getOptionalTLVList().add(forwardTLV);
+		}
+
+		Ethernet ethernet;
+		if (isStandard) {
+			ethernet = new Ethernet().setSourceMACAddress(ofpPort.getHwAddr())
+					.setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING)
+					.setEtherType(Ethernet.TYPE_LLDP);
+			ethernet.setPayload(lldp);
+		} else {
+			BSN bsn = new BSN(BSN.BSN_TYPE_BDDP);
+			bsn.setPayload(lldp);
+
+			ethernet = new Ethernet().setSourceMACAddress(ofpPort.getHwAddr())
+					.setDestinationMACAddress(LLDP_BSN_DST_MAC_STRING)
+					.setEtherType(Ethernet.TYPE_BSN);
+			ethernet.setPayload(bsn);
+		}
+
+		// serialize and wrap in a packet out
+		byte[] data = ethernet.serialize();
+		OFPacketOut.Builder pob = switchService.getSwitch(sw).getOFFactory().buildPacketOut();
+		pob.setBufferId(OFBufferId.NO_BUFFER);
+		pob.setInPort(OFPort.ANY);
+
+		// set data and data length
+		pob.setData(data);
+
+		return pob.build();
+	}
+
+	/**
+	 * Get the LLDP sending period in seconds.
+	 *
+	 * @return LLDP sending period in seconds.
+	 */
+	public int getLldpFrequency() {
+		return LLDP_TO_KNOWN_INTERVAL;
+	}
+
+	/**
+	 * Get the LLDP timeout value in seconds
+	 *
+	 * @return LLDP timeout value in seconds
+	 */
+	public int getLldpTimeout() {
+		return LINK_TIMEOUT;
+	}
+
+	@Override
+	public Map<NodePortTuple, Set<Link>> getPortLinks() {
+		return portLinks;
+	}
+
+	@Override
+	public Set<NodePortTuple> getSuppressLLDPsInfo() {
+		return suppressLinkDiscovery;
+	}
+
+	/**
+	 * Add a switch port to the suppressed LLDP list. Remove any known links on
+	 * the switch port.
+	 */
+	@Override
+	public void AddToSuppressLLDPs(DatapathId sw, OFPort port) {
+		NodePortTuple npt = new NodePortTuple(sw, port);
+		this.suppressLinkDiscovery.add(npt);
+		deleteLinksOnPort(npt, "LLDP suppressed.");
+	}
+
+	/**
+	 * Remove a switch port from the suppressed LLDP list. Discover links on
+	 * that switchport.
+	 */
+	@Override
+	public void RemoveFromSuppressLLDPs(DatapathId sw, OFPort port) {
+		NodePortTuple npt = new NodePortTuple(sw, port);
+		this.suppressLinkDiscovery.remove(npt);
+		discover(npt);
+	}
+
+	public boolean isShuttingDown() {
+		return shuttingDown;
+	}
+
+	@Override
+	public boolean isTunnelPort(DatapathId sw, OFPort port) {
+		return false;
+	}
+
+	@Override
+	public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) {
+		if (info.getUnicastValidTime() != null) {
+			return ILinkDiscovery.LinkType.DIRECT_LINK;
+		} else if (info.getMulticastValidTime() != null) {
+			return ILinkDiscovery.LinkType.MULTIHOP_LINK;
+		}
+		return ILinkDiscovery.LinkType.INVALID_LINK;
+	}
+
+	@Override
+	public Set<OFPort> getQuarantinedPorts(DatapathId sw) {
+		Set<OFPort> qPorts = new HashSet<OFPort>();
+
+		Iterator<NodePortTuple> iter = quarantineQueue.iterator();
+		while (iter.hasNext()) {
+			NodePortTuple npt = iter.next();
+			if (npt.getNodeId().equals(sw)) {
+				qPorts.add(npt.getPortId());
+			}
+		}
+		return qPorts;
+	}
+
+	@Override
+	public Map<DatapathId, Set<Link>> getSwitchLinks() {
+		return this.switchLinks;
+	}
+
+	@Override
+	public void addMACToIgnoreList(MacAddress mac, int ignoreBits) {
+		MACRange range = new MACRange();
+		range.baseMAC = mac;
+		range.ignoreBits = ignoreBits;
+		ignoreMACSet.add(range);
+	}
+
+	@Override
+	public boolean isAutoPortFastFeature() {
+		return autoPortFastFeature;
+	}
+
+	@Override
+	public void setAutoPortFastFeature(boolean autoPortFastFeature) {
+		this.autoPortFastFeature = autoPortFastFeature;
+	}
+
+	@Override
+	public void addListener(ILinkDiscoveryListener listener) {
+		linkDiscoveryAware.add(listener);
+	}
+
+	@Override
+	public Map<Link, LinkInfo> getLinks() {
+		lock.readLock().lock();
+		Map<Link, LinkInfo> result;
+		try {
+			result = new HashMap<Link, LinkInfo>(links);
+		} finally {
+			lock.readLock().unlock();
+		}
+		return result;
+	}
+
+	@Override
+	public LinkInfo getLinkInfo(Link link) {
+		lock.readLock().lock();
+		LinkInfo linkInfo = links.get(link);
+		LinkInfo retLinkInfo = null;
+		if (linkInfo != null) {
+			retLinkInfo  = new LinkInfo(linkInfo);
+		}
+		lock.readLock().unlock();
+		return retLinkInfo;
+	}
+
+	@Override
+	public String getName() {
+		return MODULE_NAME;
+	}
+
+	//*********************
+	//   OFMessage Listener
+	//*********************
+
+	@Override
+	public Command receive(IOFSwitch sw, OFMessage msg,
+			FloodlightContext cntx) {
+		switch (msg.getType()) {
+		case PACKET_IN:
+			ctrIncoming.increment();
+			return this.handlePacketIn(sw.getId(), (OFPacketIn) msg,
+					cntx);
+		default:
+			break;
+		}
+		return Command.CONTINUE;
+	}
+
+	@Override
+	public boolean isCallbackOrderingPrereq(OFType type, String name) {
+		return false;
+	}
+
+	@Override
+	public boolean isCallbackOrderingPostreq(OFType type, String name) {
+		return false;
+	}
+
+	//***********************************
+	//  Internal Methods - Packet-in Processing Related
+	//***********************************
+
+	protected Command handlePacketIn(DatapathId sw, OFPacketIn pi,
+			FloodlightContext cntx) {
+		Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
+				IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+
+		if (eth.getPayload() instanceof BSN) {
+			BSN bsn = (BSN) eth.getPayload();
+			if (bsn == null) return Command.STOP;
+			if (bsn.getPayload() == null) return Command.STOP;
+			// It could be a packet other than BSN LLDP, therefore
+			// continue with the regular processing.
+			if (bsn.getPayload() instanceof LLDP == false)
+				return Command.CONTINUE;
+			return handleLldp((LLDP) bsn.getPayload(), sw, pi.getInPort(), false, cntx);
+		} else if (eth.getPayload() instanceof LLDP) {
+			return handleLldp((LLDP) eth.getPayload(), sw, pi.getInPort(), true, cntx);
+		} else if (eth.getEtherType() < 1500) {
+			long destMac = eth.getDestinationMACAddress().getLong();
+			if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE) {
+				ctrLinkLocalDrops.increment();
+				if (log.isTraceEnabled()) {
+					log.trace("Ignoring packet addressed to 802.1D/Q "
+							+ "reserved address.");
+				}
+				return Command.STOP;
+			}
+		}
+
+		if (ignorePacketInFromSource(eth.getSourceMACAddress())) {
+			ctrIgnoreSrcMacDrops.increment();
+			return Command.STOP;
+		}
+
+		// If packet-in is from a quarantine port, stop processing.
+		NodePortTuple npt = new NodePortTuple(sw, (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+		if (quarantineQueue.contains(npt)) {
+			ctrQuarantineDrops.increment();
+			return Command.STOP;
+		}
+
+		return Command.CONTINUE;
+	}
+
+	private boolean ignorePacketInFromSource(MacAddress srcMAC) {
+		Iterator<MACRange> it = ignoreMACSet.iterator();
+		while (it.hasNext()) {
+			MACRange range = it.next();
+			long mask = ~0;
+			if (range.ignoreBits >= 0 && range.ignoreBits <= 48) {
+				mask = mask << range.ignoreBits;
+				if ((range.baseMAC.getLong() & mask) == (srcMAC.getLong() & mask)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	private Command handleLldp(LLDP lldp, DatapathId sw, OFPort inPort,
+			boolean isStandard, FloodlightContext cntx) {
+		// If LLDP is suppressed on this port, ignore received packet as well
+		IOFSwitch iofSwitch = switchService.getSwitch(sw);
+
+		if (!isIncomingDiscoveryAllowed(sw, inPort, isStandard))
+			return Command.STOP;
+
+		// If this is a malformed LLDP exit
+		if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3) {
+			return Command.STOP;
+		}
+
+		long myId = ByteBuffer.wrap(controllerTLV.getValue()).getLong();
+		long otherId = 0;
+		boolean myLLDP = false;
+		Boolean isReverse = null;
+
+		ByteBuffer portBB = ByteBuffer.wrap(lldp.getPortId().getValue());
+		portBB.position(1);
+
+		OFPort remotePort = OFPort.of(portBB.getShort());
+		IOFSwitch remoteSwitch = null;
+
+		// Verify this LLDP packet matches what we're looking for
+		for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
+			if (lldptlv.getType() == 127 && lldptlv.getLength() == 12
+					&& lldptlv.getValue()[0] == 0x0
+					&& lldptlv.getValue()[1] == 0x26
+					&& lldptlv.getValue()[2] == (byte) 0xe1
+					&& lldptlv.getValue()[3] == 0x0) {
+				ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
+				remoteSwitch = switchService.getSwitch(DatapathId.of(dpidBB.getLong(4)));
+			} else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8) {
+				otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong();
+				if (myId == otherId) myLLDP = true;
+			} else if (lldptlv.getType() == TLV_DIRECTION_TYPE
+					&& lldptlv.getLength() == TLV_DIRECTION_LENGTH) {
+				if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_FORWARD[0])
+					isReverse = false;
+				else if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_REVERSE[0])
+					isReverse = true;
+			}
+		}
+
+		if (myLLDP == false) {
+			// This is not the LLDP sent by this controller.
+			// If the LLDP message has multicast bit set, then we need to
+			// broadcast the packet as a regular packet (after checking IDs)
+			if (isStandard) {
+				if (log.isTraceEnabled()) {
+					log.trace("Got a standard LLDP=[{}] that was not sent by" +
+							" this controller. Not fowarding it.", lldp.toString());
+				}
+				return Command.STOP;
+			} else if (myId < otherId) {
+				if (log.isTraceEnabled()) {
+					log.trace("Getting BDDP packets from a different controller"
+							+ "and letting it go through normal processing chain.");
+				}
+				return Command.CONTINUE;
+			}
+			return Command.STOP;
+		}
+
+		if (remoteSwitch == null) {
+			// Ignore LLDPs not generated by Floodlight, or from a switch that
+			// has recently
+			// disconnected, or from a switch connected to another Floodlight
+			// instance
+			if (log.isTraceEnabled()) {
+				log.trace("Received LLDP from remote switch not connected to the controller");
+			}
+			return Command.STOP;
+		}
+
+		if (!remoteSwitch.portEnabled(remotePort)) {
+			if (log.isTraceEnabled()) {
+				log.trace("Ignoring link with disabled source port: switch {} port {} {}",
+						new Object[] { remoteSwitch.getId().toString(),
+						remotePort,
+						remoteSwitch.getPort(remotePort)});
+			}
+			return Command.STOP;
+		}
+		if (suppressLinkDiscovery.contains(new NodePortTuple(
+				remoteSwitch.getId(),
+				remotePort))) {
+			if (log.isTraceEnabled()) {
+				log.trace("Ignoring link with suppressed src port: switch {} port {} {}",
+						new Object[] { remoteSwitch.getId().toString(),
+						remotePort,
+						remoteSwitch.getPort(remotePort)});
+			}
+			return Command.STOP;
+		}
+		if (!iofSwitch.portEnabled(inPort)) {
+			if (log.isTraceEnabled()) {
+				log.trace("Ignoring link with disabled dest port: switch {} port {} {}",
+						new Object[] { sw.toString(),
+						inPort.getPortNumber(),
+						iofSwitch.getPort(inPort).getPortNo().getPortNumber()});
+			}
+			return Command.STOP;
+		}
+
+		// Store the time of update to this link, and push it out to
+		// routingEngine
+		Link lt = new Link(remoteSwitch.getId(), remotePort,
+				iofSwitch.getId(), inPort);
+
+		if (!isLinkAllowed(lt.getSrc(), lt.getSrcPort(),
+				lt.getDst(), lt.getDstPort()))
+			return Command.STOP;
+
+		// Continue only if link is allowed.
+		Date lastLldpTime = null;
+		Date lastBddpTime = null;
+
+		Date firstSeenTime = new Date(System.currentTimeMillis());
+
+		if (isStandard)
+			lastLldpTime = new Date(System.currentTimeMillis());
+		else
+			lastBddpTime = new Date(System.currentTimeMillis());
+
+		LinkInfo newLinkInfo = new LinkInfo(firstSeenTime, lastLldpTime,
+				lastBddpTime);
+
+		addOrUpdateLink(lt, newLinkInfo);
+
+		// Check if reverse link exists.
+		// If it doesn't exist and if the forward link was seen
+		// first seen within a small interval, send probe on the
+		// reverse link.
+		newLinkInfo = links.get(lt);
+		if (newLinkInfo != null && isStandard && isReverse == false) {
+			Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
+					lt.getSrc(), lt.getSrcPort());
+			LinkInfo reverseInfo = links.get(reverseLink);
+			if (reverseInfo == null) {
+				// the reverse link does not exist.
+				if (newLinkInfo.getFirstSeenTime().getTime() > System.currentTimeMillis()
+						- LINK_TIMEOUT) {
+					this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(),
+							isStandard, true);
+				}
+			}
+		}
+
+		// If the received packet is a BDDP packet, then create a reverse BDDP
+		// link as well.
+		if (!isStandard) {
+			Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
+					lt.getSrc(), lt.getSrcPort());
+
+			// srcPortState and dstPort state are reversed.
+			LinkInfo reverseInfo = new LinkInfo(firstSeenTime, lastLldpTime,
+					lastBddpTime);
+
+			addOrUpdateLink(reverseLink, reverseInfo);
+		}
+
+		// Remove the node ports from the quarantine and maintenance queues.
+		NodePortTuple nptSrc = new NodePortTuple(lt.getSrc(),
+				lt.getSrcPort());
+		NodePortTuple nptDst = new NodePortTuple(lt.getDst(),
+				lt.getDstPort());
+		removeFromQuarantineQueue(nptSrc);
+		removeFromMaintenanceQueue(nptSrc);
+		removeFromQuarantineQueue(nptDst);
+		removeFromMaintenanceQueue(nptDst);
+
+		// Consume this message
+		ctrLldpEol.increment();
+		return Command.STOP;
+	}
+
+	//***********************************
+	//  Internal Methods - Port Status/ New Port Processing Related
+	//***********************************
+	/**
+	 * Process a new port. If link discovery is disabled on the port, then do
+	 * nothing. If autoportfast feature is enabled and the port is a fast port,
+	 * then do nothing. Otherwise, send LLDP message. Add the port to
+	 * quarantine.
+	 *
+	 * @param sw
+	 * @param p
+	 */
+	private void processNewPort(DatapathId sw, OFPort p) {
+		if (isLinkDiscoverySuppressed(sw, p)) {
+			// Do nothing as link discovery is suppressed.
+			return;
+		}
+
+		IOFSwitch iofSwitch = switchService.getSwitch(sw);
+		if (iofSwitch == null) {
+			return;
+		}
+
+		NodePortTuple npt = new NodePortTuple(sw, p);
+		discover(sw, p);
+		addToQuarantineQueue(npt);
+	}
+
+	//***********************************
+	//  Internal Methods - Discovery Related
+	//***********************************
+
+	@LogMessageDoc(level = "ERROR",
+			message = "Error in link discovery updates loop",
+			explanation = "An unknown error occured while dispatching "
+					+ "link update notifications",
+					recommendation = LogMessageDoc.GENERIC_ACTION)
+	private void doUpdatesThread() throws InterruptedException {
+		do {
+			LDUpdate update = updates.take();
+			List<LDUpdate> updateList = new ArrayList<LDUpdate>();
+			updateList.add(update);
+
+			// Add all the pending updates to the list.
+			while (updates.peek() != null) {
+				updateList.add(updates.remove());
+			}
+
+			if (linkDiscoveryAware != null) {
+				if (log.isTraceEnabled()) {
+					log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
+							new Object[] {
+							update.getOperation(),
+							update.getSrc().toString(),
+							update.getSrcPort(),
+							update.getDst().toString(),
+							update.getDstPort(),
+							linkDiscoveryAware });
+				}
+				try {
+					for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order
+						// maintained
+						lda.linkDiscoveryUpdate(updateList);
+					}
+				} catch (Exception e) {
+					log.error("Error in link discovery updates loop", e);
+				}
+			}
+		} while (updates.peek() != null);
+	}
+
+	protected boolean isLinkDiscoverySuppressed(DatapathId sw, OFPort portNumber) {
+		return this.suppressLinkDiscovery.contains(new NodePortTuple(sw,
+				portNumber));
+	}
+
+	protected void discoverLinks() {
+
+		// timeout known links.
+		timeoutLinks();
+
+		// increment LLDP clock
+		lldpClock = (lldpClock + 1) % LLDP_TO_ALL_INTERVAL;
+
+		if (lldpClock == 0) {
+			if (log.isTraceEnabled())
+				log.trace("Sending LLDP out on all ports.");
+			discoverOnAllPorts();
+		}
+	}
+
+	/**
+	 * Quarantine Ports.
+	 */
+	protected class QuarantineWorker implements Runnable {
+		@Override
+		public void run() {
+			try {
+				processBDDPLists();
+			} catch (Exception e) {
+				log.error("Error in quarantine worker thread", e);
+			} finally {
+				bddpTask.reschedule(BDDP_TASK_INTERVAL,
+						TimeUnit.MILLISECONDS);
+			}
+		}
+	}
+
+	/**
+	 * Add a switch port to the quarantine queue. Schedule the quarantine task
+	 * if the quarantine queue was empty before adding this switch port.
+	 *
+	 * @param npt
+	 */
+	protected void addToQuarantineQueue(NodePortTuple npt) {
+		if (quarantineQueue.contains(npt) == false)
+			quarantineQueue.add(npt);
+	}
+
+	/**
+	 * Remove a switch port from the quarantine queue.
+	 */
+	protected void removeFromQuarantineQueue(NodePortTuple npt) {
+		// Remove all occurrences of the node port tuple from the list.
+		while (quarantineQueue.remove(npt));
+	}
+
+	/**
+	 * Add a switch port to maintenance queue.
+	 *
+	 * @param npt
+	 */
+	protected void addToMaintenanceQueue(NodePortTuple npt) {
+		if (maintenanceQueue.contains(npt) == false) {
+			maintenanceQueue.add(npt);
+		}
+	}
+
+	/**
+	 * Remove a switch port from maintenance queue.
+	 *
+	 * @param npt
+	 */
+	protected void removeFromMaintenanceQueue(NodePortTuple npt) {
+		// Remove all occurrences of the node port tuple from the queue.
+		while (maintenanceQueue.remove(npt));
+	}
+
+	/**
+	 * This method processes the quarantine list in bursts. The task is at most
+	 * once per BDDP_TASK_INTERVAL. One each call, BDDP_TASK_SIZE number of
+	 * switch ports are processed. Once the BDDP packets are sent out through
+	 * the switch ports, the ports are removed from the quarantine list.
+	 */
+	protected void processBDDPLists() {
+		int count = 0;
+		Set<NodePortTuple> nptList = new HashSet<NodePortTuple>();
+
+		while (count < BDDP_TASK_SIZE && quarantineQueue.peek() != null) {
+			NodePortTuple npt;
+			npt = quarantineQueue.remove();
+			sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
+			nptList.add(npt);
+			count++;
+		}
+
+		count = 0;
+		while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) {
+			NodePortTuple npt;
+			npt = maintenanceQueue.remove();
+			sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
+			count++;
+		}
+
+		for (NodePortTuple npt : nptList) {
+			generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId());
+		}
+	}
+
+	private void generateSwitchPortStatusUpdate(DatapathId sw, OFPort port) {
+		UpdateOperation operation;
+
+		IOFSwitch iofSwitch = switchService.getSwitch(sw);
+		if (iofSwitch == null) return;
+
+		OFPortDesc ofp = iofSwitch.getPort(port);
+		if (ofp == null) return;
+
+		Set<OFPortState> srcPortState = ofp.getState();
+		//TODO @Ryan verify this is equivalent boolean portUp = ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) != OFPortState.OFPPS_STP_BLOCK.getValue());
+		boolean portUp = !srcPortState.contains(OFPortState.STP_BLOCK);
+
+		if (portUp) {
+			operation = UpdateOperation.PORT_UP;
+		} else {
+			operation = UpdateOperation.PORT_DOWN;
+		}
+		
+		updates.add(new LDUpdate(sw, port, operation));
+	}
+
+	protected void discover(NodePortTuple npt) {
+		discover(npt.getNodeId(), npt.getPortId());
+	}
+
+	protected void discover(DatapathId sw, OFPort port) {
+		sendDiscoveryMessage(sw, port, true, false);
+	}
+
+	/**
+	 * Check if incoming discovery messages are enabled or not.
+	 * @param sw
+	 * @param port
+	 * @param isStandard
+	 * @return
+	 */
+	protected boolean isIncomingDiscoveryAllowed(DatapathId sw, OFPort port,
+			boolean isStandard) {
+
+		if (isLinkDiscoverySuppressed(sw, port)) {
+			/* Do not process LLDPs from this port as suppressLLDP is set */
+			return false;
+		}
+
+		IOFSwitch iofSwitch = switchService.getSwitch(sw);
+		if (iofSwitch == null) {
+			return false;
+		}
+
+		if (port == OFPort.LOCAL) return false;
+
+		OFPortDesc ofpPort = iofSwitch.getPort(port);
+		if (ofpPort == null) {
+			if (log.isTraceEnabled()) {
+				log.trace("Null physical port. sw={}, port={}",
+						sw.toString(), port.getPortNumber());
+			}
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Check if outgoing discovery messages are enabled or not.
+	 * @param sw
+	 * @param port
+	 * @param isStandard
+	 * @param isReverse
+	 * @return
+	 */
+	protected boolean isOutgoingDiscoveryAllowed(DatapathId sw, OFPort port,
+			boolean isStandard,
+			boolean isReverse) {
+
+		if (isLinkDiscoverySuppressed(sw, port)) {
+			/* Dont send LLDPs out of this port as suppressLLDP is set */
+			return false;
+		}
+
+		IOFSwitch iofSwitch = switchService.getSwitch(sw);
+		if (iofSwitch == null) {
+			return false;
+		}
+
+		if (port == OFPort.LOCAL) return false;
+
+		OFPortDesc ofpPort = iofSwitch.getPort(port);
+		if (ofpPort == null) {
+			if (log.isTraceEnabled()) {
+				log.trace("Null physical port. sw={}, port={}",
+						sw.toString(), port.getPortNumber());
+			}
+			return false;
+		} else {
+			return true;
+		}
+	}
+
+	/**
+	 * Get the actions for packet-out corresponding to a specific port.
+	 * This is a placeholder for adding actions if any port-specific
+	 * actions are desired.  The default action is simply to output to
+	 * the given port.
+	 * @param port
+	 * @return
+	 */
+	protected List<OFAction> getDiscoveryActions (IOFSwitch sw, OFPort port){
+		// set actions
+		List<OFAction> actions = new ArrayList<OFAction>();
+		actions.add(sw.getOFFactory().actions().buildOutput().setPort(port).build());
+		return actions;
+	}
+
+	/**
+	 * Send link discovery message out of a given switch port. The discovery
+	 * message may be a standard LLDP or a modified LLDP, where the dst mac
+	 * address is set to :ff. TODO: The modified LLDP will updated in the future
+	 * and may use a different eth-type.
+	 *
+	 * @param sw
+	 * @param port
+	 * @param isStandard
+	 *            indicates standard or modified LLDP
+	 * @param isReverse
+	 *            indicates whether the LLDP was sent as a response
+	 */
+	@LogMessageDoc(level = "ERROR",
+			message = "Failure sending LLDP out port {port} on switch {switch}",
+			explanation = "An I/O error occured while sending LLDP message "
+					+ "to the switch.",
+					recommendation = LogMessageDoc.CHECK_SWITCH)
+	protected void sendDiscoveryMessage(DatapathId sw, OFPort port,
+			boolean isStandard, boolean isReverse) {
+
+		// Takes care of all checks including null pointer checks.
+		if (!isOutgoingDiscoveryAllowed(sw, port, isStandard, isReverse))
+			return;
+
+		IOFSwitch iofSwitch = switchService.getSwitch(sw);
+		OFPortDesc ofpPort = iofSwitch.getPort(port);
+
+		if (log.isTraceEnabled()) {
+			log.trace("Sending LLDP packet out of swich: {}, port: {}",
+					sw.toString(), port.getPortNumber());
+		}
+		OFPacketOut po = generateLLDPMessage(sw, port, isStandard, isReverse);
+		OFPacketOut.Builder pob = po.createBuilder();
+
+		// Add actions
+		List<OFAction> actions = getDiscoveryActions(iofSwitch, ofpPort.getPortNo());
+		pob.setActions(actions);
+		
+		// no need to set length anymore
+
+		// send
+		// no more try-catch. switch will silently fail
+		iofSwitch.write(po);
+		iofSwitch.flush();
+	}
+
+	/**
+	 * Send LLDPs to all switch-ports
+	 */
+	protected void discoverOnAllPorts() {
+		if (log.isTraceEnabled()) {
+			log.trace("Sending LLDP packets out of all the enabled ports");
+		}
+		// Send standard LLDPs
+		for (DatapathId sw : switchService.getAllSwitchDpids()) {
+			IOFSwitch iofSwitch = switchService.getSwitch(sw);
+			if (iofSwitch == null) continue;
+			if (iofSwitch.getEnabledPorts() != null) {
+				for (OFPortDesc ofp : iofSwitch.getEnabledPorts()) {
+					if (isLinkDiscoverySuppressed(sw, ofp.getPortNo())) {
+						continue;
+					}
+
+					sendDiscoveryMessage(sw, ofp.getPortNo(), true, false);
+
+					// If the switch port is not already in the maintenance
+					// queue, add it.
+					NodePortTuple npt = new NodePortTuple(sw, ofp.getPortNo());
+					addToMaintenanceQueue(npt);
+				}
+			}
+		}
+	}
+
+	protected UpdateOperation getUpdateOperation(OFPortState srcPortState, OFPortState dstPortState) {
+		//TODO @Ryan verify this is equivalent
+		//boolean added = (((srcPortState & OFPortState.STP_MASK) != OFPortState.STP_BLOCK) && ((dstPortState & OFPortState.STP_MASK) != OFPortState.STP_BLOCK));
+		boolean added = ((srcPortState != OFPortState.STP_BLOCK) && (dstPortState != OFPortState.STP_BLOCK));
+
+		if (added) {
+			return UpdateOperation.LINK_UPDATED;
+		} else {
+			return UpdateOperation.LINK_REMOVED;
+		}
+	}
+
+	protected UpdateOperation getUpdateOperation(OFPortState srcPortState) {
+		//TODO @Ryan verify this too
+		//boolean portUp = ((srcPortState & OFPortState.STP_MASK) != OFPortState.STP_BLOCK);
+		boolean portUp = (srcPortState != OFPortState.STP_BLOCK);
+
+		if (portUp) {
+			return UpdateOperation.PORT_UP;
+		} else {
+			return UpdateOperation.PORT_DOWN;
+		}
+	}
+
+	//************************************
+	// Internal Methods - Link Operations Related
+	//************************************
+
+	/**
+	 * This method is used to specifically ignore/consider specific links.
+	 */
+	protected boolean isLinkAllowed(DatapathId src, OFPort srcPort,
+			DatapathId dst, OFPort dstPort) {
+		return true;
+	}
+
+	private boolean addLink(Link lt, LinkInfo newInfo) {
+		NodePortTuple srcNpt, dstNpt;
+
+		srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
+		dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
+
+		// index it by switch source
+		if (!switchLinks.containsKey(lt.getSrc()))
+			switchLinks.put(lt.getSrc(),
+					new HashSet<Link>());
+		switchLinks.get(lt.getSrc()).add(lt);
+
+		// index it by switch dest
+		if (!switchLinks.containsKey(lt.getDst()))
+			switchLinks.put(lt.getDst(),
+					new HashSet<Link>());
+		switchLinks.get(lt.getDst()).add(lt);
+
+		// index both ends by switch:port
+		if (!portLinks.containsKey(srcNpt))
+			portLinks.put(srcNpt,
+					new HashSet<Link>());
+		portLinks.get(srcNpt).add(lt);
+
+		if (!portLinks.containsKey(dstNpt))
+			portLinks.put(dstNpt,
+					new HashSet<Link>());
+		portLinks.get(dstNpt).add(lt);
+
+		return true;
+	}
+
+	protected boolean updateLink(Link lt, LinkInfo oldInfo, LinkInfo newInfo) {
+		boolean linkChanged = false;
+		// Since the link info is already there, we need to
+		// update the right fields.
+		if (newInfo.getUnicastValidTime() == null) {
+			// This is due to a multicast LLDP, so copy the old unicast
+			// value.
+			if (oldInfo.getUnicastValidTime() != null) {
+				newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime());
+			}
+		} else if (newInfo.getMulticastValidTime() == null) {
+			// This is due to a unicast LLDP, so copy the old multicast
+			// value.
+			if (oldInfo.getMulticastValidTime() != null) {
+				newInfo.setMulticastValidTime(oldInfo.getMulticastValidTime());
+			}
+		}
+
+		Date oldTime = oldInfo.getUnicastValidTime();
+		Date newTime = newInfo.getUnicastValidTime();
+		// the link has changed its state between openflow and
+		// non-openflow
+		// if the unicastValidTimes are null or not null
+		if (oldTime != null & newTime == null) {
+			linkChanged = true;
+		} else if (oldTime == null & newTime != null) {
+			linkChanged = true;
+		}
+
+		return linkChanged;
+	}
+
+	@LogMessageDocs({
+		@LogMessageDoc(message="Inter-switch link detected:",
+				explanation="Detected a new link between two openflow switches," +
+				"use show link to find current status"),
+				@LogMessageDoc(message="Inter-switch link updated:",
+				explanation="Detected a link change between two openflow switches, " +
+						"use show link to find current status")
+	})
+	protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {
+
+		boolean linkChanged = false;
+
+		lock.writeLock().lock();
+		try {
+			// put the new info. if an old info exists, it will be returned.
+			LinkInfo oldInfo = links.put(lt, newInfo);
+			if (oldInfo != null
+					&& oldInfo.getFirstSeenTime().getTime() < newInfo.getFirstSeenTime().getTime())
+				newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime());
+
+			if (log.isTraceEnabled()) {
+				log.trace("addOrUpdateLink: {} {}",
+						lt,
+						(newInfo.getMulticastValidTime() != null) ? "multicast"
+								: "unicast");
+			}
+
+			UpdateOperation updateOperation = null;
+			linkChanged = false;
+
+			if (oldInfo == null) {
+				addLink(lt, newInfo);
+				updateOperation = UpdateOperation.LINK_UPDATED;
+				linkChanged = true;
+
+				// Log direct links only. Multi-hop links may be numerous
+				// Add all to event history
+				LinkType linkType = getLinkType(lt, newInfo);
+				if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) {
+					log.info("Inter-switch link detected: {}", lt);
+					eventCategory.newEventNoFlush(new DirectLinkEvent(lt.getSrc(),
+							lt.getSrcPort(), lt.getDst(), lt.getDstPort(), "direct-link-added::rcvd LLDP"));
+				}
+				notifier.postNotification("Link added: " + lt.toString());
+			} else {
+				linkChanged = updateLink(lt, oldInfo, newInfo);
+				if (linkChanged) {
+					updateOperation = UpdateOperation.LINK_UPDATED;
+					LinkType linkType = getLinkType(lt, newInfo);
+					if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) {
+						log.info("Inter-switch link updated: {}", lt);
+						eventCategory.newEventNoFlush(new DirectLinkEvent(lt.getSrc(),
+								lt.getSrcPort(), lt.getDst(), lt.getDstPort(),
+								"link-port-state-updated::rcvd LLDP"));
+					}
+					notifier.postNotification("Link updated: " + lt.toString());
+				}
+			}
+
+			// Write changes to storage. This will always write the updated
+			// valid time, plus the port states if they've changed (i.e. if
+			// they weren't set to null in the previous block of code.
+			writeLinkToStorage(lt, newInfo);
+
+			if (linkChanged) {
+				// find out if the link was added or removed here.
+				updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+						lt.getDst(), lt.getDstPort(),
+						getLinkType(lt, newInfo),
+						updateOperation));
+			}
+		} finally {
+			lock.writeLock().unlock();
+		}
+
+		return linkChanged;
+	}
+
+	/**
+	 * Delete a link
+	 *
+	 * @param link
+	 *            - link to be deleted.
+	 * @param reason
+	 *            - reason why the link is deleted.
+	 */
+	protected void deleteLink(Link link, String reason) {
+		if (link == null)
+			return;
+		List<Link> linkList = new ArrayList<Link>();
+		linkList.add(link);
+		deleteLinks(linkList, reason);
+	}
+	/**
+	 * Removes links from memory and storage.
+	 *
+	 * @param links
+	 *            The List of @LinkTuple to delete.
+	 */
+	protected void deleteLinks(List<Link> links, String reason) {
+		deleteLinks(links, reason, null);
+	}
+
+	/**
+	 * Removes links from memory and storage.
+	 *
+	 * @param links
+	 *            The List of @LinkTuple to delete.
+	 */
+	@LogMessageDoc(message="Inter-switch link removed:",
+			explanation="A previously detected link between two openflow switches no longer exists, " +
+			"use show link to find current status")
+	protected void deleteLinks(List<Link> links, String reason,
+			List<LDUpdate> updateList) {
+
+		NodePortTuple srcNpt, dstNpt;
+		List<LDUpdate> linkUpdateList = new ArrayList<LDUpdate>();
+		lock.writeLock().lock();
+		try {
+			for (Link lt : links) {
+				srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
+				dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
+
+				if (switchLinks.containsKey(lt.getSrc())) {
+					switchLinks.get(lt.getSrc()).remove(lt);
+					if (switchLinks.get(lt.getSrc()).isEmpty())
+						this.switchLinks.remove(lt.getSrc());
+				}
+				if (this.switchLinks.containsKey(lt.getDst())) {
+					switchLinks.get(lt.getDst()).remove(lt);
+					if (this.switchLinks.get(lt.getDst()).isEmpty())
+						this.switchLinks.remove(lt.getDst());
+				}
+
+				if (this.portLinks.get(srcNpt) != null) {
+					this.portLinks.get(srcNpt).remove(lt);
+					if (this.portLinks.get(srcNpt).isEmpty())
+						this.portLinks.remove(srcNpt);
+				}
+				if (this.portLinks.get(dstNpt) != null) {
+					this.portLinks.get(dstNpt).remove(lt);
+					if (this.portLinks.get(dstNpt).isEmpty())
+						this.portLinks.remove(dstNpt);
+				}
+
+				LinkInfo info = this.links.remove(lt);
+				LinkType linkType = getLinkType(lt, info);
+				linkUpdateList.add(new LDUpdate(lt.getSrc(),
+						lt.getSrcPort(),
+						lt.getDst(),
+						lt.getDstPort(),
+						linkType,
+						UpdateOperation.LINK_REMOVED));
+
+				// FIXME: link type shows up as invalid now -- thus not checking if
+				// link type is a direct link
+				eventCategory.newEventWithFlush(new DirectLinkEvent(lt.getSrc(),
+						lt.getSrcPort(), lt.getDst(), lt.getDstPort(),
+						"link-deleted::" + reason));
+				// remove link from storage.
+				removeLinkFromStorage(lt);
+
+				// TODO Whenever link is removed, it has to checked if
+				// the switchports must be added to quarantine.
+
+				if (linkType == ILinkDiscovery.LinkType.DIRECT_LINK) {
+					log.info("Inter-switch link removed: {}", lt);
+					notifier.postNotification("Inter-switch link removed: " +
+							lt.toString());
+				} else if (log.isTraceEnabled()) {
+					log.trace("Deleted link {}", lt);
+				}
+			}
+		} finally {
+			if (updateList != null) linkUpdateList.addAll(updateList);
+			updates.addAll(linkUpdateList);
+			lock.writeLock().unlock();
+		}
+	}
+
+	/**
+	 * Delete links incident on a given switch port.
+	 *
+	 * @param npt
+	 * @param reason
+	 */
+	protected void deleteLinksOnPort(NodePortTuple npt, String reason) {
+		List<Link> eraseList = new ArrayList<Link>();
+		if (this.portLinks.containsKey(npt)) {
+			if (log.isTraceEnabled()) {
+				log.trace("handlePortStatus: Switch {} port #{} "
+						+ "removing links {}",
+						new Object[] {
+								npt.getNodeId().toString(),
+								npt.getPortId(),
+								this.portLinks.get(npt) });
+			}
+			eraseList.addAll(this.portLinks.get(npt));
+			deleteLinks(eraseList, reason);
+		}
+	}
+
+	/**
+	 * Iterates through the list of links and deletes if the last discovery
+	 * message reception time exceeds timeout values.
+	 */
+	protected void timeoutLinks() {
+		List<Link> eraseList = new ArrayList<Link>();
+		Long curTime = System.currentTimeMillis();
+		boolean linkChanged = false;
+
+		// reentrant required here because deleteLink also write locks
+		lock.writeLock().lock();
+		try {
+			Iterator<Entry<Link, LinkInfo>> it = this.links.entrySet()
+					.iterator();
+			while (it.hasNext()) {
+				Entry<Link, LinkInfo> entry = it.next();
+				Link lt = entry.getKey();
+				LinkInfo info = entry.getValue();
+
+				// Timeout the unicast and multicast LLDP valid times
+				// independently.
+				if ((info.getUnicastValidTime() != null)
+						&& (info.getUnicastValidTime().getTime()
+								+ (this.LINK_TIMEOUT * 1000) < curTime)) {
+					info.setUnicastValidTime(null);
+					linkChanged = true;
+				}
+				if ((info.getMulticastValidTime() != null)
+						&& (info.getMulticastValidTime().getTime()
+								+ (this.LINK_TIMEOUT * 1000) < curTime)) {
+					info.setMulticastValidTime(null);
+					linkChanged = true;
+				}
+				// Add to the erase list only if the unicast
+				// time is null.
+				if (info.getUnicastValidTime() == null
+						&& info.getMulticastValidTime() == null) {
+					eraseList.add(entry.getKey());
+				} else if (linkChanged) {
+					updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
+							lt.getDst(), lt.getDstPort(),
+							getLinkType(lt, info),
+							UpdateOperation.LINK_UPDATED));
+				}
+			}
+
+			// if any link was deleted or any link was changed.
+			if ((eraseList.size() > 0) || linkChanged) {
+				deleteLinks(eraseList, "LLDP timeout");
+			}
+		} finally {
+			lock.writeLock().unlock();
+		}
+	}
+
+	//******************
+	// Internal Helper Methods
+	//******************
+	@LogMessageDoc(level="WARN",
+			message="Could not get list of interfaces of local machine to " +
+					"encode in TLV: {detail-msg}",
+					explanation="Outgoing LLDP packets encode a unique hash to " +
+							"identify the local machine. The list of network " +
+							"interfaces is used as input and the controller failed " +
+							"to query this list",
+							recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+	protected void setControllerTLV() {
+		// Setting the controllerTLVValue based on current nano time,
+		// controller's IP address, and the network interface object hash
+		// the corresponding IP address.
+
+		final int prime = 7867;
+
+		byte[] controllerTLVValue = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; // 8
+		// byte
+		// value.
+		ByteBuffer bb = ByteBuffer.allocate(10);
+
+		long result = System.nanoTime();
+		try{
+			// Use some data specific to the machine this controller is
+			// running on. In this case: the list of network interfaces
+			Enumeration<NetworkInterface> ifaces =
+					NetworkInterface.getNetworkInterfaces();
+			if (ifaces != null) {
+				result = result * prime + ifaces.hashCode();
+			}
+		} catch (SocketException e) {
+			log.warn("Could not get list of interfaces of local machine to " +
+					"encode in TLV: {}", e.toString());
+		}
+		// set the first 4 bits to 0.
+		result = result & (0x0fffffffffffffffL);
+
+		bb.putLong(result);
+
+		bb.rewind();
+		bb.get(controllerTLVValue, 0, 8);
+
+		this.controllerTLV = new LLDPTLV().setType((byte) 0x0c)
+				.setLength((short) controllerTLVValue.length)
+				.setValue(controllerTLVValue);
+	}
+
+	//******************
+	// IOFSwitchListener
+	//******************
+	private void handlePortDown(DatapathId switchId, OFPort portNumber) {
+		NodePortTuple npt = new NodePortTuple(switchId, portNumber);
+		deleteLinksOnPort(npt, "Port Status Changed");
+		LDUpdate update = new LDUpdate(switchId, portNumber,
+				UpdateOperation.PORT_DOWN);
+		updates.add(update);
+	}
+	/**
+	 * We don't react the port changed notifications here. we listen for
+	 * OFPortStatus messages directly. Might consider using this notifier
+	 * instead
+	 */
+	@Override
+	public void switchPortChanged(DatapathId switchId,
+			OFPortDesc port,
+			PortChangeType type) {
+
+		switch (type) {
+		case UP:
+			processNewPort(switchId, port.getPortNo());
+			break;
+		case DELETE: case DOWN:
+			handlePortDown(switchId, port.getPortNo());
+			break;
+		case OTHER_UPDATE: case ADD:
+			// This is something other than port add or delete.
+			// Topology does not worry about this.
+			// If for some reason the port features change, which
+			// we may have to react.
+			break;
+		}
+	}
+
+	@Override
+	public void switchAdded(DatapathId switchId) {
+		// no-op
+		// We don't do anything at switch added, but we do only when the
+		// switch is activated.
+	}
+
+	@Override
+	public void switchRemoved(DatapathId sw) {
         List<Link> eraseList = new ArrayList<Link>();
         lock.writeLock().lock();
         try {
             if (switchLinks.containsKey(sw)) {
                 if (log.isTraceEnabled()) {
-                    log.trace("Handle switchRemoved. Switch {}; removing links {}",
-                              HexString.toHexString(sw), switchLinks.get(sw));
+                    log.trace("Handle switchRemoved. Switch {}; removing links {}", sw.toString(), switchLinks.get(sw));
                 }
 
                 List<LDUpdate> updateList = new ArrayList<LDUpdate>();
-                updateList.add(new LDUpdate(sw, null,
-                                            UpdateOperation.SWITCH_REMOVED));
+                updateList.add(new LDUpdate(sw, SwitchType.BASIC_SWITCH, UpdateOperation.SWITCH_REMOVED));
                 // add all tuples with an endpoint on this switch to erase list
                 eraseList.addAll(switchLinks.get(sw));
 
@@ -1669,8 +1637,7 @@ public class LinkDiscoveryManager implements IOFMessageListener,
                 deleteLinks(eraseList, "Switch Removed", updateList);
             } else {
                 // Switch does not have any links.
-                updates.add(new LDUpdate(sw, null,
-                                         UpdateOperation.SWITCH_REMOVED));
+                updates.add(new LDUpdate(sw, SwitchType.BASIC_SWITCH, UpdateOperation.SWITCH_REMOVED));
             }
         } finally {
             lock.writeLock().unlock();
@@ -1678,66 +1645,67 @@ public class LinkDiscoveryManager implements IOFMessageListener,
 
     }
 
-    @Override
-    public void switchActivated(long switchId) {
-        IOFSwitch sw = floodlightProvider.getSwitch(switchId);
-        if (sw.getEnabledPortNumbers() != null) {
-            for (Short p : sw.getEnabledPortNumbers()) {
-                processNewPort(sw.getId(), p);
-            }
-        }
-        LDUpdate update = new LDUpdate(sw.getId(), null,
-                                       UpdateOperation.SWITCH_UPDATED);
-        updates.add(update);
-    }
-
-    @Override
-    public void switchChanged(long switchId) {
-        // no-op
-    }
-
 
-    //*********************
-    //   Storage Listener
-    //*********************
-    /**
-     * Sets the IStorageSource to use for Topology
-     *
-     * @param storageSource
-     *            the storage source to use
-     */
-    public void setStorageSource(IStorageSourceService storageSource) {
-        this.storageSource = storageSource;
-    }
-
-    /**
-     * Gets the storage source for this ITopology
-     *
-     * @return The IStorageSource ITopology is writing to
-     */
-    public IStorageSourceService getStorageSource() {
-        return storageSource;
-    }
-
-    @Override
-    public void rowsModified(String tableName, Set<Object> rowKeys) {
+	@Override
+	public void switchActivated(DatapathId switchId) {
+		IOFSwitch sw = switchService.getSwitch(switchId);
+		if (sw.getEnabledPortNumbers() != null) {
+			for (OFPort p : sw.getEnabledPortNumbers()) {
+				processNewPort(sw.getId(), p);
+			}
+		}
+		LDUpdate update = new LDUpdate(sw.getId(), SwitchType.BASIC_SWITCH, UpdateOperation.SWITCH_UPDATED);
+		updates.add(update);
+	}
+
+	@Override
+	public void switchChanged(DatapathId switchId) {
+		// no-op
+	}
+
+
+	//*********************
+	//   Storage Listener
+	//*********************
+	/**
+	 * Sets the IStorageSource to use for Topology
+	 *
+	 * @param storageSource
+	 *            the storage source to use
+	 */
+	public void setStorageSource(IStorageSourceService storageSourceService) {
+		this.storageSourceService = storageSourceService;
+	}
+
+	/**
+	 * Gets the storage source for this ITopology
+	 *
+	 * @return The IStorageSource ITopology is writing to
+	 */
+	public IStorageSourceService getStorageSource() {
+		return storageSourceService;
+	}
+
+	@Override
+	public void rowsModified(String tableName, Set<Object> rowKeys) {
 
         if (tableName.equals(TOPOLOGY_TABLE_NAME)) {
             readTopologyConfigFromStorage();
             return;
         }
+        /* TODO @Ryan can we nuke all this? core switch isn't used all that often (I don't think) and not at all anymore
 
         ArrayList<IOFSwitch> updated_switches = new ArrayList<IOFSwitch>();
         for (Object key : rowKeys) {
-            Long swId = new Long(HexString.toLong((String) key));
-            IOFSwitch sw = floodlightProvider.getSwitch(swId);
+            DatapathId swId = DatapathId.of((String) key);
+            IOFSwitch sw = switchService.getSwitch(swId);
             if (sw != null) {
-                boolean curr_status = sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH);
+               boolean curr_status = sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH);
                 boolean new_status = false;
                 IResultSet resultSet = null;
 
                 try {
-                    resultSet = storageSource.getRow(tableName, key);
+                    resultSet = storageSourceService.getRow(tableName, key);
                     for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
                         // In case of multiple rows, use the status in last row?
                         Map<String, Object> row = it.next().getRow();
@@ -1746,7 +1714,9 @@ public class LinkDiscoveryManager implements IOFMessageListener,
                         }
                     }
                 } finally {
-                    if (resultSet != null) resultSet.close();
+                    if (resultSet != null) {
+                    	resultSet.close();
+                    }
                 }
 
                 if (curr_status != new_status) {
@@ -1754,9 +1724,7 @@ public class LinkDiscoveryManager implements IOFMessageListener,
                 }
             } else {
                 if (log.isTraceEnabled()) {
-                    log.trace("Update for switch which has no entry in switch "
-                                      + "list (dpid={}), a delete action.",
-                              key);
+                    log.trace("Update for switch which has no entry in switch " + "list (dpid={}), a delete action.", key);
                 }
             }
         }
@@ -1766,489 +1734,482 @@ public class LinkDiscoveryManager implements IOFMessageListener,
             if (sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH)) {
                 sw.removeAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH);
                 if (log.isTraceEnabled()) {
-                    log.trace("SWITCH_IS_CORE_SWITCH set to False for {}",
-                              sw);
-                }
+                    log.trace("SWITCH_IS_CORE_SWITCH set to False for {}", sw);
+                } 
                 updates.add(new LDUpdate(sw.getId(),
                                          SwitchType.BASIC_SWITCH,
                                          UpdateOperation.SWITCH_UPDATED));
             } else {
-                sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH,
-                                new Boolean(true));
+                sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, new Boolean(true));
                 if (log.isTraceEnabled()) {
                     log.trace("SWITCH_IS_CORE_SWITCH set to True for {}", sw);
                 }
-                updates.add(new LDUpdate(sw.getId(), SwitchType.CORE_SWITCH,
-                                         UpdateOperation.SWITCH_UPDATED));
-            }
-        }
-    }
-
-    @Override
-    public void rowsDeleted(String tableName, Set<Object> rowKeys) {
-        // Ignore delete events, the switch delete will do the
-        // right thing on it's own.
-        readTopologyConfigFromStorage();
-    }
-
-
-    //******************************
-    // Internal methods - Config Related
-    //******************************
-
-    protected void readTopologyConfigFromStorage() {
-        IResultSet topologyResult = storageSource.executeQuery(TOPOLOGY_TABLE_NAME,
-                                                               null, null,
-                                                               null);
-
-        if (topologyResult.next()) {
-            boolean apf = topologyResult.getBoolean(TOPOLOGY_AUTOPORTFAST);
-            autoPortFastFeature = apf;
-        } else {
-            this.autoPortFastFeature = AUTOPORTFAST_DEFAULT;
-        }
-
-        if (autoPortFastFeature)
-            log.info("Setting autoportfast feature to ON");
-        else
-            log.info("Setting autoportfast feature to OFF");
-    }
-
-    /**
-     * Deletes all links from storage
-     */
-    void clearAllLinks() {
-        storageSource.deleteRowsAsync(LINK_TABLE_NAME, null);
-    }
-
-    /**
-     * Writes a LinkTuple and corresponding LinkInfo to storage
-     *
-     * @param lt
-     *            The LinkTuple to write
-     * @param linkInfo
-     *            The LinkInfo to write
-     */
-    protected void writeLinkToStorage(Link lt, LinkInfo linkInfo) {
-        LinkType type = getLinkType(lt, linkInfo);
-
-        // Write only direct links. Do not write links to external
-        // L2 network.
-        // if (type != LinkType.DIRECT_LINK && type != LinkType.TUNNEL) {
-        // return;
-        // }
-
-        Map<String, Object> rowValues = new HashMap<String, Object>();
-        String id = getLinkId(lt);
-        rowValues.put(LINK_ID, id);
-        rowValues.put(LINK_VALID_TIME, linkInfo.getUnicastValidTime());
-        String srcDpid = HexString.toHexString(lt.getSrc());
-        rowValues.put(LINK_SRC_SWITCH, srcDpid);
-        rowValues.put(LINK_SRC_PORT, lt.getSrcPort());
-
-        if (type == LinkType.DIRECT_LINK)
-            rowValues.put(LINK_TYPE, "internal");
-        else if (type == LinkType.MULTIHOP_LINK)
-            rowValues.put(LINK_TYPE, "external");
-        else if (type == LinkType.TUNNEL)
-            rowValues.put(LINK_TYPE, "tunnel");
-        else
-            rowValues.put(LINK_TYPE, "invalid");
-
-        String dstDpid = HexString.toHexString(lt.getDst());
-        rowValues.put(LINK_DST_SWITCH, dstDpid);
-        rowValues.put(LINK_DST_PORT, lt.getDstPort());
-
-        storageSource.updateRowAsync(LINK_TABLE_NAME, rowValues);
-    }
-
-    /**
-     * Removes a link from storage using an asynchronous call.
-     *
-     * @param lt
-     *            The LinkTuple to delete.
-     */
-    protected void removeLinkFromStorage(Link lt) {
-        String id = getLinkId(lt);
-        storageSource.deleteRowAsync(LINK_TABLE_NAME, id);
-    }
-
-    public Long readLinkValidTime(Link lt) {
-        // FIXME: We're not currently using this right now, but if we start
-        // to use this again, we probably shouldn't use it in its current
-        // form, because it's doing synchronous storage calls. Depending
-        // on the context this may still be OK, but if it's being called
-        // on the packet in processing thread it should be reworked to
-        // use asynchronous storage calls.
-        Long validTime = null;
-        IResultSet resultSet = null;
-        try {
-            String[] columns = { LINK_VALID_TIME };
-            String id = getLinkId(lt);
-            resultSet = storageSource.executeQuery(LINK_TABLE_NAME,
-                                                   columns,
-                                                   new OperatorPredicate(
-                                                        LINK_ID,
-                                                        OperatorPredicate.Operator.EQ,
-                                                        id),
-                                                   null);
-            if (resultSet.next())
-                                 validTime = resultSet.getLong(LINK_VALID_TIME);
-        } finally {
-            if (resultSet != null) resultSet.close();
-        }
-        return validTime;
-    }
-
-    /**
-     * Gets the storage key for a LinkTuple
-     *
-     * @param lt
-     *            The LinkTuple to get
-     * @return The storage key as a String
-     */
-    private String getLinkId(Link lt) {
-        return HexString.toHexString(lt.getSrc()) + "-" + lt.getSrcPort()
-               + "-" + HexString.toHexString(lt.getDst()) + "-"
-               + lt.getDstPort();
-    }
-
-    //***************
-    // IFloodlightModule
-    //***************
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l =
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(ILinkDiscoveryService.class);
-        // l.add(ITopologyService.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(ILinkDiscoveryService.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(IStorageSourceService.class);
-        l.add(IThreadPoolService.class);
-        l.add(IRestApiService.class);
-        return l;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-        storageSource = context.getServiceImpl(IStorageSourceService.class);
-        threadPool = context.getServiceImpl(IThreadPoolService.class);
-        restApi = context.getServiceImpl(IRestApiService.class);
-        debugCounters = context.getServiceImpl(IDebugCounterService.class);
-        debugEvents = context.getServiceImpl(IDebugEventService.class);
-
-        // read our config options
-        Map<String, String> configOptions = context.getConfigParams(this);
-        try {
-            String histSize = configOptions.get("eventhistorysize");
-            if (histSize != null) {
-                EVENT_HISTORY_SIZE = Short.parseShort(histSize);
-            }
-        } catch (NumberFormatException e) {
-            log.warn("Error event history size, using default of {} seconds", EVENT_HISTORY_SIZE);
-        }
-        log.debug("Event history size set to {}", EVENT_HISTORY_SIZE);
-
-        // Set the autoportfast feature to false.
-        this.autoPortFastFeature = AUTOPORTFAST_DEFAULT;
-
-        // We create this here because there is no ordering guarantee
-        this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
-        this.lock = new ReentrantReadWriteLock();
-        this.updates = new LinkedBlockingQueue<LDUpdate>();
-        this.links = new HashMap<Link, LinkInfo>();
-        this.portLinks = new HashMap<NodePortTuple, Set<Link>>();
-        this.suppressLinkDiscovery = Collections.synchronizedSet(new HashSet<NodePortTuple>());
-        this.switchLinks = new HashMap<Long, Set<Link>>();
-        this.quarantineQueue = new LinkedBlockingQueue<NodePortTuple>();
-        this.maintenanceQueue = new LinkedBlockingQueue<NodePortTuple>();
-
-        this.ignoreMACSet = Collections.newSetFromMap(
-                                new ConcurrentHashMap<MACRange,Boolean>());
-        this.haListener = new HAListenerDelegate();
-        registerLinkDiscoveryDebugCounters();
-        registerLinkDiscoveryDebugEvents();
-    }
-
-    @Override
-    @LogMessageDocs({
-                     @LogMessageDoc(level = "ERROR",
-                                    message = "No storage source found.",
-                                    explanation = "Storage source was not initialized; cannot initialize "
-                                                  + "link discovery.",
-                                    recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
-                     @LogMessageDoc(level = "ERROR",
-                                    message = "Error in installing listener for "
-                                              + "switch config table {table}",
-                                    explanation = "Failed to install storage notification for the "
-                                                  + "switch config table",
-                                    recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
-                     @LogMessageDoc(level = "ERROR",
-                                    message = "No storage source found.",
-                                    explanation = "Storage source was not initialized; cannot initialize "
-                                                  + "link discovery.",
-                                    recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
-                     @LogMessageDoc(level = "ERROR",
-                                    message = "Exception in LLDP send timer.",
-                                    explanation = "An unknown error occured while sending LLDP "
-                                                  + "messages to switches.",
-                                    recommendation = LogMessageDoc.CHECK_SWITCH) })
-    public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
-
-        // Initialize role to floodlight provider role.
-        this.role = floodlightProvider.getRole();
-
-        // Create our storage tables
-        if (storageSource == null) {
-            log.error("No storage source found.");
-            return;
-        }
-
-        storageSource.createTable(TOPOLOGY_TABLE_NAME, null);
-        storageSource.setTablePrimaryKeyName(TOPOLOGY_TABLE_NAME,
-                                             TOPOLOGY_ID);
-        readTopologyConfigFromStorage();
-
-        storageSource.createTable(LINK_TABLE_NAME, null);
-        storageSource.setTablePrimaryKeyName(LINK_TABLE_NAME, LINK_ID);
-        storageSource.deleteMatchingRows(LINK_TABLE_NAME, null);
-        // Register for storage updates for the switch table
-        try {
-            storageSource.addListener(SWITCH_CONFIG_TABLE_NAME, this);
-            storageSource.addListener(TOPOLOGY_TABLE_NAME, this);
-        } catch (StorageException ex) {
-            log.error("Error in installing listener for "
-                      + "switch table {}", SWITCH_CONFIG_TABLE_NAME);
-        }
-
-        ScheduledExecutorService ses = threadPool.getScheduledExecutor();
-
-        // To be started by the first switch connection
-        discoveryTask = new SingletonTask(ses, new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    discoverLinks();
-                } catch (StorageException e) {
-                    log.error("Storage exception in LLDP send timer; "
-                              + "terminating process", e);
-                    floodlightProvider.terminate();
-                } catch (Exception e) {
-                    log.error("Exception in LLDP send timer.", e);
-                } finally {
-                    if (!shuttingDown) {
-                        // null role implies HA mode is not enabled.
-                        if (role == null || role == Role.MASTER) {
-                            log.trace("Rescheduling discovery task as role = {}",
-                                      role);
-                            discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
-                                                     TimeUnit.SECONDS);
-                        } else {
-                            log.trace("Stopped LLDP rescheduling due to role = {}.",
-                                      role);
-                        }
-                    }
-                }
-            }
-        });
-
-        // null role implies HA mode is not enabled.
-        if (role == null || role == Role.MASTER) {
-            log.trace("Setup: Rescheduling discovery task. role = {}", role);
-            discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
-                                     TimeUnit.SECONDS);
-        } else {
-            log.trace("Setup: Not scheduling LLDP as role = {}.", role);
-        }
-
-        // Setup the BDDP task. It is invoked whenever switch port tuples
-        // are added to the quarantine list.
-        bddpTask = new SingletonTask(ses, new QuarantineWorker());
-        bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS);
-
-        updatesThread = new Thread(new Runnable() {
-            @Override
-            public void run() {
-                while (true) {
-                    try {
-                        doUpdatesThread();
-                    } catch (InterruptedException e) {
-                        return;
-                    }
-                }
-            }
-        }, "Topology Updates");
-        updatesThread.start();
-
-        // Register for the OpenFlow messages we want to receive
-        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-        floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
-        // Register for switch updates
-        floodlightProvider.addOFSwitchListener(this);
-        floodlightProvider.addHAListener(this.haListener);
-        floodlightProvider.addInfoProvider("summary", this);
-        if (restApi != null)
-                            restApi.addRestletRoutable(new LinkDiscoveryWebRoutable());
-        setControllerTLV();
-    }
-
-    // ****************************************************
-    // Link Discovery DebugCounters and DebugEvents
-    // ****************************************************
-
-    private void registerLinkDiscoveryDebugCounters() throws FloodlightModuleException {
-        if (debugCounters == null) {
-            log.error("Debug Counter Service not found.");
-            debugCounters = new NullDebugCounter();
-        }
-        try {
-            ctrIncoming = debugCounters.registerCounter(PACKAGE, "incoming",
-                "All incoming packets seen by this module", CounterType.ALWAYS_COUNT);
-            ctrLldpEol  = debugCounters.registerCounter(PACKAGE, "lldp-eol",
-                "End of Life for LLDP packets", CounterType.COUNT_ON_DEMAND);
-            ctrLinkLocalDrops = debugCounters.registerCounter(PACKAGE, "linklocal-drops",
-                "All link local packets dropped by this module",
-                CounterType.ALWAYS_COUNT);
-            ctrIgnoreSrcMacDrops = debugCounters.registerCounter(PACKAGE, "ignore-srcmac-drops",
-                "All packets whose srcmac is configured to be dropped by this module",
-                CounterType.ALWAYS_COUNT);
-            ctrQuarantineDrops = debugCounters.registerCounter(PACKAGE, "quarantine-drops",
-                "All packets arriving on quarantined ports dropped by this module",
-                CounterType.ALWAYS_COUNT, IDebugCounterService.CTR_MDATA_WARN);
-        } catch (CounterException e) {
-            throw new FloodlightModuleException(e.getMessage());
-        }
-    }
-
-    private void registerLinkDiscoveryDebugEvents() throws FloodlightModuleException {
-        if (debugEvents == null) {
-            log.error("Debug Event Service not found.");
-            debugEvents = new NullDebugEvent();
-        }
-
-        try {
-            evDirectLink = debugEvents.registerEvent(
-                               PACKAGE, "linkevent",
-                               "Direct OpenFlow links discovered or timed-out",
-                               EventType.ALWAYS_LOG, DirectLinkEvent.class, 100);
-        } catch (MaxEventsRegistered e) {
-            throw new FloodlightModuleException("max events registered", e);
-        }
-
-    }
-
-    public class DirectLinkEvent {
-        @EventColumn(name = "srcSw", description = EventFieldType.DPID)
-        long srcDpid;
-
-        @EventColumn(name = "srcPort", description = EventFieldType.PRIMITIVE)
-        short srcPort;
-
-        @EventColumn(name = "dstSw", description = EventFieldType.DPID)
-        long dstDpid;
-
-        @EventColumn(name = "dstPort", description = EventFieldType.PRIMITIVE)
-        short dstPort;
-
-        @EventColumn(name = "reason", description = EventFieldType.STRING)
-        String reason;
-
-        public DirectLinkEvent(long srcDpid, short srcPort, long dstDpid,
-                               short dstPort, String reason) {
-            this.srcDpid = srcDpid;
-            this.srcPort = srcPort;
-            this.dstDpid = dstDpid;
-            this.dstPort = dstPort;
-            this.reason = reason;
-        }
-    }
-
-
-    //*********************
-    //  IInfoProvider
-    //*********************
-
-    @Override
-    public Map<String, Object> getInfo(String type) {
-        if (!"summary".equals(type)) return null;
-
-        Map<String, Object> info = new HashMap<String, Object>();
-
-        int numDirectLinks = 0;
-        for (Set<Link> links : switchLinks.values()) {
-            for (Link link : links) {
-                LinkInfo linkInfo = this.getLinkInfo(link);
-                if (linkInfo != null &&
-                    linkInfo.getLinkType() == LinkType.DIRECT_LINK) {
-                    numDirectLinks++;
-                }
-            }
-        }
-        info.put("# inter-switch links", numDirectLinks / 2);
-        info.put("# quarantine ports", quarantineQueue.size());
-        return info;
-    }
-
-    //***************
-    // IHAListener
-    //***************
-
-    private class HAListenerDelegate implements IHAListener {
-        @Override
-        public void  transitionToMaster() {
-            if (log.isTraceEnabled()) {
-                log.trace("Sending LLDPs "
-                        + "to HA change from SLAVE->MASTER");
-            }
-            LinkDiscoveryManager.this.role = Role.MASTER;
-            clearAllLinks();
-            readTopologyConfigFromStorage();
-            log.debug("Role Change to Master: Rescheduling discovery task.");
-            discoveryTask.reschedule(1, TimeUnit.MICROSECONDS);
-        }
-
-        @Override
-        public void controllerNodeIPsChanged(Map<String, String> curControllerNodeIPs,
-                                             Map<String, String> addedControllerNodeIPs,
-                                             Map<String, String> removedControllerNodeIPs) {
-            // ignore
-        }
-
-        @Override
-        public String getName() {
-            return LinkDiscoveryManager.this.getName();
-        }
-
-        @Override
-        public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
-                                                String name) {
-            return ("topology".equals(name));
-        }
-
-        @Override
-        public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
-                                                 String name) {
-            return "tunnelmanager".equals(name);
-        }
-    }
+                updates.add(new LDUpdate(sw.getId(), SwitchType.CORE_SWITCH, UpdateOperation.SWITCH_UPDATED));
+            } 
+        }*/
+    }
+
+	@Override
+	public void rowsDeleted(String tableName, Set<Object> rowKeys) {
+		// Ignore delete events, the switch delete will do the
+		// right thing on it's own.
+		readTopologyConfigFromStorage();
+	}
+
+
+	//******************************
+	// Internal methods - Config Related
+	//******************************
+
+	protected void readTopologyConfigFromStorage() {
+		IResultSet topologyResult = storageSourceService.executeQuery(TOPOLOGY_TABLE_NAME,
+				null, null,
+				null);
+
+		if (topologyResult.next()) {
+			boolean apf = topologyResult.getBoolean(TOPOLOGY_AUTOPORTFAST);
+			autoPortFastFeature = apf;
+		} else {
+			this.autoPortFastFeature = AUTOPORTFAST_DEFAULT;
+		}
+
+		if (autoPortFastFeature)
+			log.info("Setting autoportfast feature to ON");
+		else
+			log.info("Setting autoportfast feature to OFF");
+	}
+
+	/**
+	 * Deletes all links from storage
+	 */
+	void clearAllLinks() {
+		storageSourceService.deleteRowsAsync(LINK_TABLE_NAME, null);
+	}
+
+	/**
+	 * Writes a LinkTuple and corresponding LinkInfo to storage
+	 *
+	 * @param lt
+	 *            The LinkTuple to write
+	 * @param linkInfo
+	 *            The LinkInfo to write
+	 */
+	protected void writeLinkToStorage(Link lt, LinkInfo linkInfo) {
+		LinkType type = getLinkType(lt, linkInfo);
+
+		// Write only direct links. Do not write links to external
+		// L2 network.
+		// if (type != LinkType.DIRECT_LINK && type != LinkType.TUNNEL) {
+		// return;
+		// }
+
+		Map<String, Object> rowValues = new HashMap<String, Object>();
+		String id = getLinkId(lt);
+		rowValues.put(LINK_ID, id);
+		rowValues.put(LINK_VALID_TIME, linkInfo.getUnicastValidTime());
+		String srcDpid = lt.getSrc().toString();
+		rowValues.put(LINK_SRC_SWITCH, srcDpid);
+		rowValues.put(LINK_SRC_PORT, lt.getSrcPort());
+
+		if (type == LinkType.DIRECT_LINK)
+			rowValues.put(LINK_TYPE, "internal");
+		else if (type == LinkType.MULTIHOP_LINK)
+			rowValues.put(LINK_TYPE, "external");
+		else if (type == LinkType.TUNNEL)
+			rowValues.put(LINK_TYPE, "tunnel");
+		else
+			rowValues.put(LINK_TYPE, "invalid");
+
+		String dstDpid = lt.getDst().toString();
+		rowValues.put(LINK_DST_SWITCH, dstDpid);
+		rowValues.put(LINK_DST_PORT, lt.getDstPort());
+
+		storageSourceService.updateRowAsync(LINK_TABLE_NAME, rowValues);
+	}
+
+	/**
+	 * Removes a link from storage using an asynchronous call.
+	 *
+	 * @param lt
+	 *            The LinkTuple to delete.
+	 */
+	protected void removeLinkFromStorage(Link lt) {
+		String id = getLinkId(lt);
+		storageSourceService.deleteRowAsync(LINK_TABLE_NAME, id);
+	}
+
+	public Long readLinkValidTime(Link lt) {
+		// FIXME: We're not currently using this right now, but if we start
+		// to use this again, we probably shouldn't use it in its current
+		// form, because it's doing synchronous storage calls. Depending
+		// on the context this may still be OK, but if it's being called
+		// on the packet in processing thread it should be reworked to
+		// use asynchronous storage calls.
+		Long validTime = null;
+		IResultSet resultSet = null;
+		try {
+			String[] columns = { LINK_VALID_TIME };
+			String id = getLinkId(lt);
+			resultSet = storageSourceService.executeQuery(LINK_TABLE_NAME,
+					columns,
+					new OperatorPredicate(
+							LINK_ID,
+							OperatorPredicate.Operator.EQ,
+							id),
+							null);
+			if (resultSet.next())
+				validTime = resultSet.getLong(LINK_VALID_TIME);
+		} finally {
+			if (resultSet != null) resultSet.close();
+		}
+		return validTime;
+	}
+
+	/**
+	 * Gets the storage key for a LinkTuple
+	 *
+	 * @param lt
+	 *            The LinkTuple to get
+	 * @return The storage key as a String
+	 */
+	private String getLinkId(Link lt) {
+		return lt.getSrc().toString() + "-" + lt.getSrcPort()
+				+ "-" + lt.getDst().toString() + "-"
+				+ lt.getDstPort();
+	}
+
+	//***************
+	// IFloodlightModule
+	//***************
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		Collection<Class<? extends IFloodlightService>> l =
+				new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(ILinkDiscoveryService.class);
+		// l.add(ITopologyService.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(ILinkDiscoveryService.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(IStorageSourceService.class);
+		l.add(IThreadPoolService.class);
+		l.add(IRestApiService.class);
+		l.add(IShutdownService.class);
+		return l;
+	}
+
+	@Override
+	public void init(FloodlightModuleContext context)
+			throws FloodlightModuleException {
+		floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+		switchService = context.getServiceImpl(IOFSwitchService.class);
+		storageSourceService = context.getServiceImpl(IStorageSourceService.class);
+		threadPoolService = context.getServiceImpl(IThreadPoolService.class);
+		restApiService = context.getServiceImpl(IRestApiService.class);
+		debugCounterService = context.getServiceImpl(IDebugCounterService.class);
+		debugEventService = context.getServiceImpl(IDebugEventService.class);
+		shutdownService = context.getServiceImpl(IShutdownService.class);
+
+		// read our config options
+		Map<String, String> configOptions = context.getConfigParams(this);
+		try {
+			String histSize = configOptions.get("eventhistorysize");
+			if (histSize != null) {
+				EVENT_HISTORY_SIZE = Short.parseShort(histSize);
+			}
+		} catch (NumberFormatException e) {
+			log.warn("Error event history size, using default of {} seconds", EVENT_HISTORY_SIZE);
+		}
+		log.debug("Event history size set to {}", EVENT_HISTORY_SIZE);
+
+		// Set the autoportfast feature to false.
+		this.autoPortFastFeature = AUTOPORTFAST_DEFAULT;
+
+		// We create this here because there is no ordering guarantee
+		this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
+		this.lock = new ReentrantReadWriteLock();
+		this.updates = new LinkedBlockingQueue<LDUpdate>();
+		this.links = new HashMap<Link, LinkInfo>();
+		this.portLinks = new HashMap<NodePortTuple, Set<Link>>();
+		this.suppressLinkDiscovery = Collections.synchronizedSet(new HashSet<NodePortTuple>());
+		this.switchLinks = new HashMap<DatapathId, Set<Link>>();
+		this.quarantineQueue = new LinkedBlockingQueue<NodePortTuple>();
+		this.maintenanceQueue = new LinkedBlockingQueue<NodePortTuple>();
+
+		this.ignoreMACSet = Collections.newSetFromMap(
+				new ConcurrentHashMap<MACRange,Boolean>());
+		this.haListener = new HAListenerDelegate();
+		registerLinkDiscoveryDebugCounters();
+		registerLinkDiscoveryDebugEvents();
+	}
+
+	@Override
+	@LogMessageDocs({
+		@LogMessageDoc(level = "ERROR",
+				message = "No storage source found.",
+				explanation = "Storage source was not initialized; cannot initialize "
+						+ "link discovery.",
+						recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
+						@LogMessageDoc(level = "ERROR",
+						message = "Error in installing listener for "
+								+ "switch config table {table}",
+								explanation = "Failed to install storage notification for the "
+										+ "switch config table",
+										recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
+										@LogMessageDoc(level = "ERROR",
+										message = "No storage source found.",
+										explanation = "Storage source was not initialized; cannot initialize "
+												+ "link discovery.",
+												recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
+												@LogMessageDoc(level = "ERROR",
+												message = "Exception in LLDP send timer.",
+												explanation = "An unknown error occured while sending LLDP "
+														+ "messages to switches.",
+														recommendation = LogMessageDoc.CHECK_SWITCH) })
+	public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
+
+		// Initialize role to floodlight provider role.
+		this.role = floodlightProviderService.getRole();
+
+		// Create our storage tables
+		if (storageSourceService == null) {
+			log.error("No storage source found.");
+			return;
+		}
+
+		storageSourceService.createTable(TOPOLOGY_TABLE_NAME, null);
+		storageSourceService.setTablePrimaryKeyName(TOPOLOGY_TABLE_NAME,
+				TOPOLOGY_ID);
+		readTopologyConfigFromStorage();
+
+		storageSourceService.createTable(LINK_TABLE_NAME, null);
+		storageSourceService.setTablePrimaryKeyName(LINK_TABLE_NAME, LINK_ID);
+		storageSourceService.deleteMatchingRows(LINK_TABLE_NAME, null);
+		// Register for storage updates for the switch table
+		try {
+			storageSourceService.addListener(SWITCH_CONFIG_TABLE_NAME, this);
+			storageSourceService.addListener(TOPOLOGY_TABLE_NAME, this);
+		} catch (StorageException ex) {
+			log.error("Error in installing listener for "
+					+ "switch table {}", SWITCH_CONFIG_TABLE_NAME);
+		}
+
+		ScheduledExecutorService ses = threadPoolService.getScheduledExecutor();
+
+		// To be started by the first switch connection
+		discoveryTask = new SingletonTask(ses, new Runnable() {
+			@Override
+			public void run() {
+				try {
+					discoverLinks();
+				} catch (StorageException e) {
+					shutdownService.terminate("Storage exception in LLDP send timer. Terminating process " + e, 0); // TODO @Ryan as there "standard" shutdown codes Floodlight uses?
+				} catch (Exception e) {
+					log.error("Exception in LLDP send timer.", e);
+				} finally {
+					if (!shuttingDown) {
+						// null role implies HA mode is not enabled.
+						if (role == null || role == HARole.ACTIVE) {
+							log.trace("Rescheduling discovery task as role = {}",
+									role);
+							discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
+									TimeUnit.SECONDS);
+						} else {
+							log.trace("Stopped LLDP rescheduling due to role = {}.",
+									role);
+						}
+					}
+				}
+			}
+		});
+
+		// null role implies HA mode is not enabled.
+		if (role == null || role == HARole.ACTIVE) {
+			log.trace("Setup: Rescheduling discovery task. role = {}", role);
+			discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
+					TimeUnit.SECONDS);
+		} else {
+			log.trace("Setup: Not scheduling LLDP as role = {}.", role);
+		}
+
+		// Setup the BDDP task. It is invoked whenever switch port tuples
+		// are added to the quarantine list.
+		bddpTask = new SingletonTask(ses, new QuarantineWorker());
+		bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS);
+
+		updatesThread = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				while (true) {
+					try {
+						doUpdatesThread();
+					} catch (InterruptedException e) {
+						return;
+					}
+				}
+			}
+		}, "Topology Updates");
+		updatesThread.start();
+
+		// Register for the OpenFlow messages we want to receive
+		floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
+		floodlightProviderService.addOFMessageListener(OFType.PORT_STATUS, this);
+		// Register for switch updates
+		switchService.addOFSwitchListener(this);
+		floodlightProviderService.addHAListener(this.haListener);
+		floodlightProviderService.addInfoProvider("summary", this);
+		if (restApiService != null)
+			restApiService.addRestletRoutable(new LinkDiscoveryWebRoutable());
+		setControllerTLV();
+	}
+
+	// ****************************************************
+	// Link Discovery DebugCounters and DebugEvents
+	// ****************************************************
+
+	private void registerLinkDiscoveryDebugCounters() throws FloodlightModuleException {
+		if (debugCounterService == null) {
+			log.error("Debug Counter Service not found.");
+		}
+		debugCounterService.registerModule(PACKAGE);
+		ctrIncoming = debugCounterService.registerCounter(PACKAGE, "incoming",
+				"All incoming packets seen by this module");
+		ctrLldpEol  = debugCounterService.registerCounter(PACKAGE, "lldp-eol",
+				"End of Life for LLDP packets");
+		ctrLinkLocalDrops = debugCounterService.registerCounter(PACKAGE, "linklocal-drops",
+				"All link local packets dropped by this module");
+		ctrIgnoreSrcMacDrops = debugCounterService.registerCounter(PACKAGE, "ignore-srcmac-drops",
+				"All packets whose srcmac is configured to be dropped by this module");
+		ctrQuarantineDrops = debugCounterService.registerCounter(PACKAGE, "quarantine-drops",
+				"All packets arriving on quarantined ports dropped by this module", IDebugCounterService.MetaData.WARN);
+	}
+
+	private void registerLinkDiscoveryDebugEvents() throws FloodlightModuleException {
+		if (debugEventService == null) {
+			log.error("Debug Event Service not found.");
+		}
+
+		eventCategory = debugEventService.buildEvent(DirectLinkEvent.class)
+				.setModuleName(PACKAGE)
+				.setEventName("linkevent")
+				.setEventDescription("Direct OpenFlow links discovered or timed-out")
+				.setEventType(EventType.ALWAYS_LOG)
+				.setBufferCapacity(100)
+				.register();
+	}
+
+	public class DirectLinkEvent {
+		@EventColumn(name = "srcSw", description = EventFieldType.DPID)
+		DatapathId srcDpid;
+
+		@EventColumn(name = "srcPort", description = EventFieldType.PRIMITIVE)
+		OFPort srcPort;
+
+		@EventColumn(name = "dstSw", description = EventFieldType.DPID)
+		DatapathId dstDpid;
+
+		@EventColumn(name = "dstPort", description = EventFieldType.PRIMITIVE)
+		OFPort dstPort;
+
+		@EventColumn(name = "reason", description = EventFieldType.STRING)
+		String reason;
+
+		public DirectLinkEvent(DatapathId srcDpid, OFPort srcPort, DatapathId dstDpid,
+				OFPort dstPort, String reason) {
+			this.srcDpid = srcDpid;
+			this.srcPort = srcPort;
+			this.dstDpid = dstDpid;
+			this.dstPort = dstPort;
+			this.reason = reason;
+		}
+	}
+
+
+	//*********************
+	//  IInfoProvider
+	//*********************
+
+	@Override
+	public Map<String, Object> getInfo(String type) {
+		if (!"summary".equals(type)) return null;
+
+		Map<String, Object> info = new HashMap<String, Object>();
+
+		int numDirectLinks = 0;
+		for (Set<Link> links : switchLinks.values()) {
+			for (Link link : links) {
+				LinkInfo linkInfo = this.getLinkInfo(link);
+				if (linkInfo != null &&
+						linkInfo.getLinkType() == LinkType.DIRECT_LINK) {
+					numDirectLinks++;
+				}
+			}
+		}
+		info.put("# inter-switch links", numDirectLinks / 2);
+		info.put("# quarantine ports", quarantineQueue.size());
+		return info;
+	}
+
+	//***************
+	// IHAListener
+	//***************
+
+	private class HAListenerDelegate implements IHAListener {
+		@Override
+		public void transitionToActive() {
+			if (log.isTraceEnabled()) {
+				log.trace("Sending LLDPs "
+						+ "to HA change from STANDBY->MASTER");
+			}
+			LinkDiscoveryManager.this.role = HARole.ACTIVE;
+			clearAllLinks();
+			readTopologyConfigFromStorage();
+			log.debug("Role Change to Master: Rescheduling discovery task.");
+			discoveryTask.reschedule(1, TimeUnit.MICROSECONDS);
+		}
+
+		@Override
+		public void controllerNodeIPsChanged(Map<String, String> curControllerNodeIPs,
+				Map<String, String> addedControllerNodeIPs,
+				Map<String, String> removedControllerNodeIPs) {
+			// ignore
+		}
+
+		@Override
+		public String getName() {
+			return LinkDiscoveryManager.this.getName();
+		}
+
+		@Override
+		public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
+				String name) {
+			return ("topology".equals(name));
+		}
+
+		@Override
+		public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
+				String name) {
+			return "tunnelmanager".equals(name);
+		}
+
+		@Override
+		public void transitionToStandby() {
+			//no-op
+		}
+	}
 
 }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java
index c2aa9d4e47dbf8a7d52020380466c50c62bd9660..c3dea4918245d2f30002315a229288202a388373 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java
@@ -27,6 +27,8 @@ import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.floodlightcontroller.linkdiscovery.LinkInfo;
 import net.floodlightcontroller.routing.Link;
 
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 
@@ -47,10 +49,10 @@ public class ExternalLinksResource extends ServerResource {
                 if (type == LinkType.MULTIHOP_LINK) {
                     LinkWithType lwt;
 
-                    long src = link.getSrc();
-                    long dst = link.getDst();
-                    short srcPort = link.getSrcPort();
-                    short dstPort = link.getDstPort();
+                    DatapathId src = link.getSrc();
+                    DatapathId dst = link.getDst();
+                    OFPort srcPort = link.getSrcPort();
+                    OFPort dstPort = link.getDstPort();
                     Link otherLink = new Link(dst, dstPort, src, srcPort);
                     LinkInfo otherInfo = links.get(otherLink);
                     LinkType otherType = null;
@@ -59,7 +61,8 @@ public class ExternalLinksResource extends ServerResource {
                     if (otherType == LinkType.MULTIHOP_LINK) {
                         // This is a bi-direcitonal link.
                         // It is sufficient to add only one side of it.
-                        if ((src < dst) || (src == dst && srcPort < dstPort)) {
+                        if ((src.getLong() < dst.getLong()) || (src.getLong() == dst.getLong() 
+                        		&& srcPort.getPortNumber() < dstPort.getPortNumber())) {
                             lwt = new LinkWithType(link,
                                     type,
                                     LinkDirection.BIDIRECTIONAL);
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
index d95235705d016ab44bc22bbacea79302198876a5..81b5094ddb2f5debff234a779bb4e2596781fc1a 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
@@ -18,12 +18,14 @@ package net.floodlightcontroller.linkdiscovery.web;
 
 import java.io.IOException;
 
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+
 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 com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import org.openflow.util.HexString;
 
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkDirection;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
@@ -36,10 +38,10 @@ import net.floodlightcontroller.routing.Link;
  */
 @JsonSerialize(using=LinkWithType.class)
 public class LinkWithType extends JsonSerializer<LinkWithType> {
-    public long srcSwDpid;
-    public short srcPort;
-    public long dstSwDpid;
-    public short dstPort;
+    public DatapathId srcSwDpid;
+    public OFPort srcPort;
+    public DatapathId dstSwDpid;
+    public OFPort dstPort;
     public LinkType type;
     public LinkDirection direction;
 
@@ -62,10 +64,10 @@ public class LinkWithType extends JsonSerializer<LinkWithType> {
             throws IOException, JsonProcessingException {
         // You ****MUST*** use lwt for the fields as it's actually a different object.
         jgen.writeStartObject();
-        jgen.writeStringField("src-switch", HexString.toHexString(lwt.srcSwDpid));
-        jgen.writeNumberField("src-port", lwt.srcPort);
-        jgen.writeStringField("dst-switch", HexString.toHexString(lwt.dstSwDpid));
-        jgen.writeNumberField("dst-port", lwt.dstPort);
+        jgen.writeStringField("src-switch", lwt.srcSwDpid.toString());
+        jgen.writeNumberField("src-port", lwt.srcPort.getPortNumber());
+        jgen.writeStringField("dst-switch", lwt.dstSwDpid.toString());
+        jgen.writeNumberField("dst-port", lwt.dstPort.getPortNumber());
         jgen.writeStringField("type", lwt.type.toString());
         jgen.writeStringField("direction", lwt.direction.toString());
         jgen.writeEndObject();
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
index 0e488ddf2e13e97c5834f6380515f7008a240916..c766fb179a228adb4050caf8d878435e0260ef8f 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
@@ -27,6 +27,8 @@ import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.floodlightcontroller.linkdiscovery.LinkInfo;
 import net.floodlightcontroller.routing.Link;
 
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 
@@ -47,10 +49,10 @@ public class LinksResource extends ServerResource {
                 if (type == LinkType.DIRECT_LINK || type == LinkType.TUNNEL) {
                     LinkWithType lwt;
 
-                    long src = link.getSrc();
-                    long dst = link.getDst();
-                    short srcPort = link.getSrcPort();
-                    short dstPort = link.getDstPort();
+                    DatapathId src = link.getSrc();
+                    DatapathId dst = link.getDst();
+                    OFPort srcPort = link.getSrcPort();
+                    OFPort dstPort = link.getDstPort();
                     Link otherLink = new Link(dst, dstPort, src, srcPort);
                     LinkInfo otherInfo = links.get(otherLink);
                     LinkType otherType = null;
@@ -60,7 +62,8 @@ public class LinksResource extends ServerResource {
                             otherType == LinkType.TUNNEL) {
                         // This is a bi-direcitonal link.
                         // It is sufficient to add only one side of it.
-                        if ((src < dst) || (src == dst && srcPort < dstPort)) {
+                        if ((src.getLong() < dst.getLong()) || (src.getLong() == dst.getLong()
+                        		&& srcPort.getPortNumber() < dstPort.getPortNumber())) {
                             lwt = new LinkWithType(link,
                                     type,
                                     LinkDirection.BIDIRECTIONAL);
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java
index 1d0a9bdadd16cca75dccb00cb3251cd4b160e59b..00f2141685a7adbec7da241dc6160b70d91421c3 100644
--- a/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java
@@ -18,10 +18,11 @@ package net.floodlightcontroller.loadbalancer;
 
 import java.util.ArrayList;
 
+import org.projectfloodlight.openflow.types.MacAddress;
+
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
 import net.floodlightcontroller.loadbalancer.LoadBalancer.IPClient;
-import net.floodlightcontroller.util.MACAddress;
 
 /**
  * Data structure for Load Balancer based on
@@ -46,7 +47,7 @@ public class LBVip {
     protected short adminState;
     protected short status;
     
-    protected MACAddress proxyMac;
+    protected MacAddress proxyMac;
     
     public static String LB_PROXY_MAC= "12:34:56:78:90:12";
     
@@ -65,7 +66,7 @@ public class LBVip {
         this.address = 0;
         this.status = 0;
         
-        this.proxyMac = MACAddress.valueOf(LB_PROXY_MAC);
+        this.proxyMac = MacAddress.of(LB_PROXY_MAC);
     }
     
     public String pickPool(IPClient client) {
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
index dabcef1e556231fdbb3c19d3496d5236e9714494..f14134c5f17b651c9294b031667fdb13f109b9fd 100644
--- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
@@ -24,34 +24,25 @@ import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-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.OFPort;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionDataLayerDestination;
-import org.openflow.protocol.action.OFActionDataLayerSource;
-import org.openflow.protocol.action.OFActionEnqueue;
-import org.openflow.protocol.action.OFActionNetworkLayerDestination;
-import org.openflow.protocol.action.OFActionNetworkLayerSource;
-import org.openflow.protocol.action.OFActionNetworkTypeOfService;
-import org.openflow.protocol.action.OFActionOutput;
-import org.openflow.protocol.action.OFActionStripVirtualLan;
-import org.openflow.protocol.action.OFActionTransportLayerDestination;
-import org.openflow.protocol.action.OFActionTransportLayerSource;
-import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
-import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
-import org.openflow.util.HexString;
-import org.openflow.util.U16;
+
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.match.Match;
+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.types.DatapathId;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U16;
+import org.projectfloodlight.openflow.types.U64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -59,11 +50,12 @@ import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 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.counter.ICounterStoreService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.devicemanager.SwitchPort;
@@ -80,7 +72,9 @@ import net.floodlightcontroller.routing.Route;
 import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.topology.NodePortTuple;
-import net.floodlightcontroller.util.MACAddress;
+import net.floodlightcontroller.util.ActionUtils;
+import net.floodlightcontroller.util.FlowModUtils;
+import net.floodlightcontroller.util.MatchUtils;
 import net.floodlightcontroller.util.OFMessageDamper;
 
 /**
@@ -102,21 +96,22 @@ public class LoadBalancer implements IFloodlightModule,
     protected static Logger log = LoggerFactory.getLogger(LoadBalancer.class);
 
     // Our dependencies
-    protected IFloodlightProviderService floodlightProvider;
-    protected IRestApiService restApi;
+    protected IFloodlightProviderService floodlightProviderService;
+    protected IRestApiService restApiService;
     
-    protected ICounterStoreService counterStore;
+    protected IDebugCounterService debugCounterService;
     protected OFMessageDamper messageDamper;
-    protected IDeviceService deviceManager;
-    protected IRoutingService routingEngine;
-    protected ITopologyService topology;
-    protected IStaticFlowEntryPusherService sfp;
+    protected IDeviceService deviceManagerService;
+    protected IRoutingService routingEngineService;
+    protected ITopologyService topologyService;
+    protected IStaticFlowEntryPusherService sfpService;
+    protected IOFSwitchService switchService;
     
     protected HashMap<String, LBVip> vips;
     protected HashMap<String, LBPool> pools;
     protected HashMap<String, LBMember> members;
     protected HashMap<Integer, String> vipIpToId;
-    protected HashMap<Integer, MACAddress> vipIpToMac;
+    protected HashMap<Integer, MacAddress> vipIpToMac;
     protected HashMap<Integer, String> memberIpToId;
     protected HashMap<IPClient, LBMember> clientToMember;
     
@@ -131,26 +126,24 @@ public class LoadBalancer implements IFloodlightModule,
             new Comparator<SwitchPort>() {
                 @Override
                 public int compare(SwitchPort d1, SwitchPort d2) {
-                    Long d1ClusterId = 
-                            topology.getL2DomainId(d1.getSwitchDPID());
-                    Long d2ClusterId = 
-                            topology.getL2DomainId(d2.getSwitchDPID());
+                    DatapathId d1ClusterId = topologyService.getL2DomainId(d1.getSwitchDPID());
+                    DatapathId d2ClusterId = topologyService.getL2DomainId(d2.getSwitchDPID());
                     return d1ClusterId.compareTo(d2ClusterId);
                 }
             };
 
     // data structure for storing connected
     public class IPClient {
-        int ipAddress;
-        byte nw_proto;
-        short srcPort; // tcp/udp src port. icmp type (OFMatch convention)
-        short targetPort; // tcp/udp dst port, icmp code (OFMatch convention)
+        IPv4Address ipAddress;
+        IpProtocol nw_proto;
+        TransportPort srcPort; // tcp/udp src port. icmp type (OFMatch convention)
+        TransportPort targetPort; // tcp/udp dst port, icmp code (OFMatch convention)
         
         public IPClient() {
-            ipAddress = 0;
-            nw_proto = 0;
-            srcPort = -1;
-            targetPort = -1;
+            ipAddress = IPv4Address.NONE;
+            nw_proto = IpProtocol.NONE;
+            srcPort = TransportPort.NONE;
+            targetPort = TransportPort.NONE;
         }
     }
     
@@ -185,12 +178,9 @@ public class LoadBalancer implements IFloodlightModule,
         return Command.CONTINUE;
     }
 
-    private net.floodlightcontroller.core.IListener.Command
-            processPacketIn(IOFSwitch sw, OFPacketIn pi,
-                            FloodlightContext cntx) {
+    private net.floodlightcontroller.core.IListener.Command processPacketIn(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
         
-        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
-                                                              IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
         IPacket pkt = eth.getPayload();
  
         if (eth.isBroadcast() || eth.isMulticast()) {
@@ -214,7 +204,7 @@ public class LoadBalancer implements IFloodlightModule,
                 IPv4 ip_pkt = (IPv4) pkt;
                 
                 // If match Vip and port, check pool and choose member
-                int destIpAddress = ip_pkt.getDestinationAddress();
+                int destIpAddress = ip_pkt.getDestinationAddress().getInt();
                 
                 if (vipIpToId.containsKey(destIpAddress)){
                     IPClient client = new IPClient();
@@ -231,8 +221,8 @@ public class LoadBalancer implements IFloodlightModule,
                         client.targetPort = udp_pkt.getDestinationPort();
                     }
                     if (ip_pkt.getPayload() instanceof ICMP) {
-                        client.srcPort = 8; 
-                        client.targetPort = 0; 
+                        client.srcPort = TransportPort.of(8); 
+                        client.targetPort = TransportPort.of(0); 
                     }
                     
                     LBVip vip = vips.get(vipIpToId.get(destIpAddress));
@@ -243,7 +233,7 @@ public class LoadBalancer implements IFloodlightModule,
                     pushBidirectionalVipRoutes(sw, pi, cntx, client, member);
                    
                     // packet out based on table rule
-                    pushPacket(pkt, sw, pi.getBufferId(), pi.getInPort(), OFPort.OFPP_TABLE.getValue(),
+                    pushPacket(pkt, sw, pi.getBufferId(), pi.getInPort(), OFPort.TABLE,
                                 cntx, true);
 
                     return Command.STOP;
@@ -274,7 +264,7 @@ public class LoadBalancer implements IFloodlightModule,
         ARP arpRequest = (ARP) eth.getPayload();
         
         // have to do proxy arp reply since at this point we cannot determine the requesting application type
-        byte[] vipProxyMacBytes = vips.get(vipId).proxyMac.toBytes();
+        byte[] vipProxyMacBytes = vips.get(vipId).proxyMac.getBytes();
         
         // generate proxy ARP reply
         IPacket arpReply = new Ethernet()
@@ -294,13 +284,12 @@ public class LoadBalancer implements IFloodlightModule,
                 .setSenderProtocolAddress(
                         arpRequest.getTargetProtocolAddress())
                 .setTargetHardwareAddress(
-                        eth.getSourceMACAddress())
+                        eth.getSourceMACAddress().getBytes())
                 .setTargetProtocolAddress(
                         arpRequest.getSenderProtocolAddress()));
                 
         // push ARP reply out
-        pushPacket(arpReply, sw, OFPacketOut.BUFFER_ID_NONE, OFPort.OFPP_NONE.getValue(),
-                   pi.getInPort(), cntx, true);
+        pushPacket(arpReply, sw, OFBufferId.NO_BUFFER, OFPort.ZERO, pi.getInPort(), cntx, true);
         log.debug("proxy ARP reply pushed as {}", IPv4.fromIPv4Address(vips.get(vipId).address));
         
         return;
@@ -319,9 +308,9 @@ public class LoadBalancer implements IFloodlightModule,
      */    
     public void pushPacket(IPacket packet, 
                            IOFSwitch sw,
-                           int bufferId,
-                           short inPort,
-                           short outPort, 
+                           OFBufferId bufferId,
+                           OFPort inPort,
+                           OFPort outPort, 
                            FloodlightContext cntx,
                            boolean flush) {
         if (log.isTraceEnabled()) {
@@ -329,25 +318,20 @@ public class LoadBalancer implements IFloodlightModule,
                       new Object[] {sw, inPort, outPort});
         }
 
-        OFPacketOut po =
-                (OFPacketOut) floodlightProvider.getOFMessageFactory()
-                                                .getMessage(OFType.PACKET_OUT);
+        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
 
         // set actions
         List<OFAction> actions = new ArrayList<OFAction>();
-        actions.add(new OFActionOutput(outPort, (short) 0xffff));
-
-        po.setActions(actions)
-          .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
-        short poLength =
-                (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
+        actions.add(sw.getOFFactory().actions().buildOutput().setPort(outPort).build());
 
+        pob.setActions(actions);
+        
         // set buffer_id, in_port
-        po.setBufferId(bufferId);
-        po.setInPort(inPort);
+        pob.setBufferId(bufferId);
+        pob.setInPort(inPort);
 
         // set data - only if buffer_id == -1
-        if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
+        if (pob.getBufferId() == OFBufferId.NO_BUFFER) {
             if (packet == null) {
                 log.error("BufferId is not set and packet data is null. " +
                           "Cannot send packetOut. " +
@@ -356,15 +340,12 @@ public class LoadBalancer implements IFloodlightModule,
                 return;
             }
             byte[] packetData = packet.serialize();
-            poLength += packetData.length;
-            po.setPacketData(packetData);
+            pob.setData(packetData);
         }
 
-        po.setLength(poLength);
-
         try {
-            counterStore.updatePktOutFMCounterStoreLocal(sw, po);
-            messageDamper.write(sw, po, cntx, flush);
+            //TODO @Ryan debugCounterService.updatePktOutFMCounterStoreLocal(sw, pob.build());
+            messageDamper.write(sw, pob.build(), cntx, flush);
         } catch (IOException e) {
             log.error("Failure writing packet out", e);
         }
@@ -386,14 +367,13 @@ public class LoadBalancer implements IFloodlightModule,
         IDevice dstDevice = null;
         
         // retrieve all known devices
-        Collection<? extends IDevice> allDevices = deviceManager
-                .getAllDevices();
+        Collection<? extends IDevice> allDevices = deviceManagerService.getAllDevices();
         
         for (IDevice d : allDevices) {
             for (int j = 0; j < d.getIPv4Addresses().length; j++) {
-                    if (srcDevice == null && client.ipAddress == d.getIPv4Addresses()[j])
+                    if (srcDevice == null && client.ipAddress.equals(d.getIPv4Addresses()[j]))
                         srcDevice = d;
-                    if (dstDevice == null && member.address == d.getIPv4Addresses()[j]) {
+                    if (dstDevice == null && member.address == d.getIPv4Addresses()[j].getInt()) {
                         dstDevice = d;
                         member.macString = dstDevice.getMACAddressString();
                     }
@@ -405,11 +385,11 @@ public class LoadBalancer implements IFloodlightModule,
         // srcDevice and/or dstDevice is null, no route can be pushed
         if (srcDevice == null || dstDevice == null) return;
         
-        Long srcIsland = topology.getL2DomainId(sw.getId());
+        DatapathId srcIsland = topologyService.getL2DomainId(sw.getId());
 
         if (srcIsland == null) {
             log.debug("No openflow island found for source {}/{}", 
-                      sw.getStringId(), pi.getInPort());
+                      sw.getId().toString(), pi.getInPort());
             return;
         }
         
@@ -418,12 +398,12 @@ public class LoadBalancer implements IFloodlightModule,
         boolean on_same_island = false;
         boolean on_same_if = false;
         for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) {
-            long dstSwDpid = dstDap.getSwitchDPID();
-            Long dstIsland = topology.getL2DomainId(dstSwDpid);
+            DatapathId dstSwDpid = dstDap.getSwitchDPID();
+            DatapathId dstIsland = topologyService.getL2DomainId(dstSwDpid);
             if ((dstIsland != null) && dstIsland.equals(srcIsland)) {
                 on_same_island = true;
-                if ((sw.getId() == dstSwDpid) &&
-                        (pi.getInPort() == dstDap.getPort())) {
+                if ((sw.getId().equals(dstSwDpid)) &&
+                        (pi.getInPort().equals(dstDap.getPort()))) {
                     on_same_if = true;
                 }
                 break;
@@ -463,10 +443,10 @@ public class LoadBalancer implements IFloodlightModule,
         while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) {
             SwitchPort srcDap = srcDaps[iSrcDaps];
             SwitchPort dstDap = dstDaps[iDstDaps];
-            Long srcCluster = 
-                    topology.getL2DomainId(srcDap.getSwitchDPID());
-            Long dstCluster = 
-                    topology.getL2DomainId(dstDap.getSwitchDPID());
+            DatapathId srcCluster = 
+                    topologyService.getL2DomainId(srcDap.getSwitchDPID());
+            DatapathId dstCluster = 
+                    topologyService.getL2DomainId(dstDap.getSwitchDPID());
 
             int srcVsDest = srcCluster.compareTo(dstCluster);
             if (srcVsDest == 0) {
@@ -474,15 +454,15 @@ public class LoadBalancer implements IFloodlightModule,
                         (srcCluster != null) && 
                         (dstCluster != null)) {
                     Route routeIn = 
-                            routingEngine.getRoute(srcDap.getSwitchDPID(),
-                                                   (short)srcDap.getPort(),
+                            routingEngineService.getRoute(srcDap.getSwitchDPID(),
+                                                   srcDap.getPort(),
                                                    dstDap.getSwitchDPID(),
-                                                   (short)dstDap.getPort(), 0);
+                                                   dstDap.getPort(), U64.of(0));
                     Route routeOut = 
-                            routingEngine.getRoute(dstDap.getSwitchDPID(),
-                                                   (short)dstDap.getPort(),
+                            routingEngineService.getRoute(dstDap.getSwitchDPID(),
+                                                   dstDap.getPort(),
                                                    srcDap.getSwitchDPID(),
-                                                   (short)srcDap.getPort(), 0);
+                                                   srcDap.getPort(), U64.of(0));
 
                     // use static flow entry pusher to push flow mod along in and out path
                     // in: match src client (ip, port), rewrite dest from vip ip/port to member ip/port, forward
@@ -516,37 +496,34 @@ public class LoadBalancer implements IFloodlightModule,
      * @param LBMember member
      * @param long pinSwitch
      */
-    public void pushStaticVipRoute(boolean inBound, Route route, IPClient client, LBMember member, long pinSwitch) {
+    public void pushStaticVipRoute(boolean inBound, Route route, IPClient client, LBMember member, DatapathId pinSwitch) {
         List<NodePortTuple> path = route.getPath();
-        if (path.size()>0) {
+        if (path.size() > 0) {
            for (int i = 0; i < path.size(); i+=2) {
                
-               long sw = path.get(i).getNodeId();
-               String swString = HexString.toHexString(path.get(i).getNodeId());
+               DatapathId sw = path.get(i).getNodeId();
+               String swString = path.get(i).getNodeId().toString();
                String entryName;
                String matchString = null;
                String actionString = null;
                
-               OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
-                       .getMessage(OFType.FLOW_MOD);
-
-               fm.setIdleTimeout((short) 0);   // infinite
-               fm.setHardTimeout((short) 0);   // infinite
-               fm.setBufferId(OFPacketOut.BUFFER_ID_NONE);
-               fm.setCommand((short) 0);
-               fm.setFlags((short) 0);
-               fm.setOutPort(OFPort.OFPP_NONE.getValue());
-               fm.setCookie((long) 0);  
-               fm.setPriority(Short.MAX_VALUE);
+               OFFlowMod.Builder fmb = switchService.getSwitch(pinSwitch).getOFFactory().buildFlowModify();
+
+               fmb.setIdleTimeout(FlowModUtils.INFINITE_TIMEOUT);
+               fmb.setHardTimeout(FlowModUtils.INFINITE_TIMEOUT);
+               fmb.setBufferId(OFBufferId.NO_BUFFER);
+               fmb.setOutPort(OFPort.ZERO);
+               fmb.setCookie(U64.of(0));  
+               fmb.setPriority(Short.MAX_VALUE);
                
                if (inBound) {
                    entryName = "inbound-vip-"+ member.vipId+"-client-"+client.ipAddress+"-port-"+client.targetPort
                            +"-srcswitch-"+path.get(0).getNodeId()+"-sw-"+sw;
-                   matchString = "nw_src="+IPv4.fromIPv4Address(client.ipAddress)+","
-                               + "nw_proto="+String.valueOf(client.nw_proto)+","
-                               + "tp_src="+String.valueOf(client.srcPort & 0xffff)+","
-                               + "dl_type="+LB_ETHER_TYPE+","
-                               + "in_port="+String.valueOf(path.get(i).getPortId());
+                   matchString = MatchUtils.STR_NW_SRC + "="+client.ipAddress.toString()+","
+                               + MatchUtils.STR_NW_PROTO + "="+String.valueOf(client.nw_proto)+","
+                               + MatchUtils.STR_TP_SRC + "="+client.srcPort.toString()+","
+                               + MatchUtils.STR_DL_TYPE + "="+LB_ETHER_TYPE+","
+                               + MatchUtils.STR_IN_PORT + "="+path.get(i).getPortId().toString();
 
                    if (sw == pinSwitch) {
                        actionString = "set-dst-ip="+IPv4.fromIPv4Address(member.address)+"," 
@@ -559,36 +536,35 @@ public class LoadBalancer implements IFloodlightModule,
                } else {
                    entryName = "outbound-vip-"+ member.vipId+"-client-"+client.ipAddress+"-port-"+client.targetPort
                            +"-srcswitch-"+path.get(0).getNodeId()+"-sw-"+sw;
-                   matchString = "nw_dst="+IPv4.fromIPv4Address(client.ipAddress)+","
-                               + "nw_proto="+String.valueOf(client.nw_proto)+","
-                               + "tp_dst="+String.valueOf(client.srcPort & 0xffff)+","
-                               + "dl_type="+LB_ETHER_TYPE+","
-                               + "in_port="+String.valueOf(path.get(i).getPortId());
+                   matchString = MatchUtils.STR_NW_DST + "="+client.ipAddress.toString()+","
+                               + MatchUtils.STR_NW_PROTO + "="+client.nw_proto.toString()+","
+                               + MatchUtils.STR_TP_DST + "="+client.srcPort.toString()+","
+                               + MatchUtils.STR_DL_TYPE + "="+LB_ETHER_TYPE+","
+                               + MatchUtils.STR_IN_PORT + "="+path.get(i).getPortId().toString();
 
                    if (sw == pinSwitch) {
-                       actionString = "set-src-ip="+IPv4.fromIPv4Address(vips.get(member.vipId).address)+","
-                               + "set-src-mac="+vips.get(member.vipId).proxyMac.toString()+","
-                               + "output="+path.get(i+1).getPortId();
+                       actionString = ActionUtils.STR_NW_SRC_SET + "="+IPv4.fromIPv4Address(vips.get(member.vipId).address)+","
+                               + ActionUtils.STR_DL_SRC_SET + "="+vips.get(member.vipId).proxyMac.toString()+","
+                               + ActionUtils.STR_OUTPUT + "="+path.get(i+1).getPortId();
                    } else {
-                       actionString = "output="+path.get(i+1).getPortId();
+                       actionString = ActionUtils.STR_OUTPUT + "="+path.get(i+1).getPortId();
                    }
                    
                }
                
-               parseActionString(fm, actionString, log);
+               ActionUtils.fromString(fmb, actionString, log);
 
-               fm.setPriority(U16.t(LB_PRIORITY));
+               fmb.setPriority(U16.t(LB_PRIORITY));
 
-               OFMatch ofMatch = new OFMatch();
+               Match match = null;
                try {
-                   ofMatch.fromString(matchString);
+                   match = MatchUtils.fromString(matchString, switchService.getSwitch(sw).getOFFactory().getVersion());
                } catch (IllegalArgumentException e) {
-                   log.debug("ignoring flow entry {} on switch {} with illegal OFMatch() key: "
-                                     + matchString, entryName, swString);
+                   log.debug("ignoring flow entry {} on switch {} with illegal OFMatch() key: " + matchString, entryName, swString);
                }
         
-               fm.setMatch(ofMatch);
-               sfp.addFlow(entryName, fm, swString);
+               fmb.setMatch(match);
+               sfpService.addFlow(entryName, fmb.build(), sw);
 
            }
         }
@@ -650,7 +626,7 @@ public class LoadBalancer implements IFloodlightModule,
 
     @Override
     public LBPool createPool(LBPool pool) {
-        if (pool==null)
+        if (pool == null)
             pool = new LBPool();
         
         pools.put(pool.id, pool);
@@ -673,7 +649,7 @@ public class LoadBalancer implements IFloodlightModule,
     @Override
     public int removePool(String poolId) {
         LBPool pool;
-        if(pools!=null){
+        if (pools != null) {
             pool = pools.get(poolId);
             if (pool.vipId != null)
                 vips.get(pool.vipId).pools.remove(poolId);
@@ -702,7 +678,7 @@ public class LoadBalancer implements IFloodlightModule,
         
         if(pools.containsKey(poolId)) {
             ArrayList<String> memberIds = pools.get(poolId).members;
-            for (int i=0; i<memberIds.size(); i++)
+            for (int i = 0; i<memberIds.size(); i++)
                 result.add(members.get(memberIds.get(i)));
         }
         return result;
@@ -749,31 +725,26 @@ public class LoadBalancer implements IFloodlightModule,
 
     @Override
     public Collection<LBMonitor> listMonitors() {
-        // TODO Auto-generated method stub
         return null;
     }
 
     @Override
     public Collection<LBMonitor> listMonitor(String monitorId) {
-        // TODO Auto-generated method stub
         return null;
     }
 
     @Override
     public LBMonitor createMonitor(LBMonitor monitor) {
-        // TODO Auto-generated method stub
         return null;
     }
 
     @Override
     public LBMonitor updateMonitor(LBMonitor monitor) {
-        // TODO Auto-generated method stub
         return null;
     }
 
     @Override
     public int removeMonitor(String monitorId) {
-        // TODO Auto-generated method stub
         return 0;
     }
 
@@ -803,8 +774,9 @@ public class LoadBalancer implements IFloodlightModule,
                 new ArrayList<Class<? extends IFloodlightService>>();
         l.add(IFloodlightProviderService.class);
         l.add(IRestApiService.class);
-        l.add(ICounterStoreService.class);
+        l.add(IOFSwitchService.class);
         l.add(IDeviceService.class);
+        l.add(IDebugCounterService.class);
         l.add(ITopologyService.class);
         l.add(IRoutingService.class);
         l.add(IStaticFlowEntryPusherService.class);
@@ -815,13 +787,14 @@ public class LoadBalancer implements IFloodlightModule,
     @Override
     public void init(FloodlightModuleContext context)
                                                  throws FloodlightModuleException {
-        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-        restApi = context.getServiceImpl(IRestApiService.class);
-        counterStore = context.getServiceImpl(ICounterStoreService.class);
-        deviceManager = context.getServiceImpl(IDeviceService.class);
-        routingEngine = context.getServiceImpl(IRoutingService.class);
-        topology = context.getServiceImpl(ITopologyService.class);
-        sfp = context.getServiceImpl(IStaticFlowEntryPusherService.class);
+        floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+        restApiService = context.getServiceImpl(IRestApiService.class);
+        debugCounterService = context.getServiceImpl(IDebugCounterService.class);
+        deviceManagerService = context.getServiceImpl(IDeviceService.class);
+        routingEngineService = context.getServiceImpl(IRoutingService.class);
+        topologyService = context.getServiceImpl(ITopologyService.class);
+        sfpService = context.getServiceImpl(IStaticFlowEntryPusherService.class);
+        switchService = context.getServiceImpl(IOFSwitchService.class);
         
         messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY, 
                                             EnumSet.of(OFType.FLOW_MOD),
@@ -831,501 +804,13 @@ public class LoadBalancer implements IFloodlightModule,
         pools = new HashMap<String, LBPool>();
         members = new HashMap<String, LBMember>();
         vipIpToId = new HashMap<Integer, String>();
-        vipIpToMac = new HashMap<Integer, MACAddress>();
+        vipIpToMac = new HashMap<Integer, MacAddress>();
         memberIpToId = new HashMap<Integer, String>();
     }
 
     @Override
     public void startUp(FloodlightModuleContext context) {
-        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-        restApi.addRestletRoutable(new LoadBalancerWebRoutable());
+        floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
+        restApiService.addRestletRoutable(new LoadBalancerWebRoutable());
     }
-
-    // Utilities borrowed from StaticFlowEntries
-    
-    private static class SubActionStruct {
-        OFAction action;
-        int      len;
-    }
-    
-    /**
-     * Parses OFFlowMod actions from strings.
-     * @param flowMod The OFFlowMod to set the actions for
-     * @param actionstr The string containing all the actions
-     * @param log A logger to log for errors.
-     */
-    public static void parseActionString(OFFlowMod flowMod, String actionstr, Logger log) {
-        List<OFAction> actions = new LinkedList<OFAction>();
-        int actionsLength = 0;
-        if (actionstr != null) {
-            actionstr = actionstr.toLowerCase();
-            for (String subaction : actionstr.split(",")) {
-                String action = subaction.split("[=:]")[0];
-                SubActionStruct subaction_struct = null;
-                
-                if (action.equals("output")) {
-                    subaction_struct = decode_output(subaction, log);
-                }
-                else if (action.equals("enqueue")) {
-                    subaction_struct = decode_enqueue(subaction, log);
-                }
-                else if (action.equals("strip-vlan")) {
-                    subaction_struct = decode_strip_vlan(subaction, log);
-                }
-                else if (action.equals("set-vlan-id")) {
-                    subaction_struct = decode_set_vlan_id(subaction, log);
-                }
-                else if (action.equals("set-vlan-priority")) {
-                    subaction_struct = decode_set_vlan_priority(subaction, log);
-                }
-                else if (action.equals("set-src-mac")) {
-                    subaction_struct = decode_set_src_mac(subaction, log);
-                }
-                else if (action.equals("set-dst-mac")) {
-                    subaction_struct = decode_set_dst_mac(subaction, log);
-                }
-                else if (action.equals("set-tos-bits")) {
-                    subaction_struct = decode_set_tos_bits(subaction, log);
-                }
-                else if (action.equals("set-src-ip")) {
-                    subaction_struct = decode_set_src_ip(subaction, log);
-                }
-                else if (action.equals("set-dst-ip")) {
-                    subaction_struct = decode_set_dst_ip(subaction, log);
-                }
-                else if (action.equals("set-src-port")) {
-                    subaction_struct = decode_set_src_port(subaction, log);
-                }
-                else if (action.equals("set-dst-port")) {
-                    subaction_struct = decode_set_dst_port(subaction, log);
-                }
-                else {
-                    log.error("Unexpected action '{}', '{}'", action, subaction);
-                }
-                
-                if (subaction_struct != null) {
-                    actions.add(subaction_struct.action);
-                    actionsLength += subaction_struct.len;
-                }
-            }
-        }
-        log.debug("action {}", actions);
-        
-        flowMod.setActions(actions);
-        flowMod.setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLength);
-    } 
-    
-    private static SubActionStruct decode_output(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n;
-        
-        n = Pattern.compile("output=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(subaction);
-        if (n.matches()) {
-            OFActionOutput action = new OFActionOutput();
-            action.setMaxLength(Short.MAX_VALUE);
-            short port = OFPort.OFPP_NONE.getValue();
-            if (n.group(1) != null) {
-                try {
-                    port = get_short(n.group(1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid port in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-            else if (n.group(2) != null)
-                port = OFPort.OFPP_ALL.getValue();
-            else if (n.group(3) != null)
-                port = OFPort.OFPP_CONTROLLER.getValue();
-            else if (n.group(4) != null)
-                port = OFPort.OFPP_LOCAL.getValue();
-            else if (n.group(5) != null)
-                port = OFPort.OFPP_IN_PORT.getValue();
-            else if (n.group(6) != null)
-                port = OFPort.OFPP_NORMAL.getValue();
-            else if (n.group(7) != null)
-                port = OFPort.OFPP_FLOOD.getValue();
-            action.setPort(port);
-            log.debug("action {}", action);
-            
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionOutput.MINIMUM_LENGTH;
-        }
-        else {
-            log.error("Invalid subaction: '{}'", subaction);
-            return null;
-        }
-        
-        return sa;
-    }
-    
-    private static SubActionStruct decode_enqueue(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n;
-        
-        n = Pattern.compile("enqueue=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(subaction);
-        if (n.matches()) {
-            short portnum = 0;
-            if (n.group(1) != null) {
-                try {
-                    portnum = get_short(n.group(1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid port-num in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-
-            int queueid = 0;
-            if (n.group(2) != null) {
-                try {
-                    queueid = get_int(n.group(2));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid queue-id in: '{}' (error ignored)", subaction);
-                    return null;
-               }
-            }
-            
-            OFActionEnqueue action = new OFActionEnqueue();
-            action.setPort(portnum);
-            action.setQueueId(queueid);
-            log.debug("action {}", action);
-            
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionEnqueue.MINIMUM_LENGTH;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-        
-        return sa;
-    }
-    
-    private static SubActionStruct decode_strip_vlan(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("strip-vlan").matcher(subaction);
-        
-        if (n.matches()) {
-            OFActionStripVirtualLan action = new OFActionStripVirtualLan();
-            log.debug("action {}", action);
-            
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionStripVirtualLan.MINIMUM_LENGTH;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_vlan_id(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction);
-        
-        if (n.matches()) {            
-            if (n.group(1) != null) {
-                try {
-                    short vlanid = get_short(n.group(1));
-                    OFActionVirtualLanIdentifier action = new OFActionVirtualLanIdentifier();
-                    action.setVirtualLanIdentifier(vlanid);
-                    log.debug("  action {}", action);
-
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionVirtualLanIdentifier.MINIMUM_LENGTH;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid VLAN in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }          
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_vlan_priority(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction); 
-        
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    byte prior = get_byte(n.group(1));
-                    OFActionVirtualLanPriorityCodePoint action = new OFActionVirtualLanPriorityCodePoint();
-                    action.setVirtualLanPriorityCodePoint(prior);
-                    log.debug("  action {}", action);
-                    
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionVirtualLanPriorityCodePoint.MINIMUM_LENGTH;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid VLAN priority in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_src_mac(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); 
-
-        if (n.matches()) {
-            byte[] macaddr = get_mac_addr(n, subaction, log);
-            if (macaddr != null) {
-                OFActionDataLayerSource action = new OFActionDataLayerSource();
-                action.setDataLayerAddress(macaddr);
-                log.debug("action {}", action);
-
-                sa = new SubActionStruct();
-                sa.action = action;
-                sa.len = OFActionDataLayerSource.MINIMUM_LENGTH;
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_mac(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
-        
-        if (n.matches()) {
-            byte[] macaddr = get_mac_addr(n, subaction, log);
-            if (macaddr != null) {
-                OFActionDataLayerDestination action = new OFActionDataLayerDestination();
-                action.setDataLayerAddress(macaddr);
-                log.debug("  action {}", action);
-                
-                sa = new SubActionStruct();
-                sa.action = action;
-                sa.len = OFActionDataLayerDestination.MINIMUM_LENGTH;
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_tos_bits(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction); 
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    byte tosbits = get_byte(n.group(1));
-                    OFActionNetworkTypeOfService action = new OFActionNetworkTypeOfService();
-                    action.setNetworkTypeOfService(tosbits);
-                    log.debug("  action {}", action);
-                    
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionNetworkTypeOfService.MINIMUM_LENGTH;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid dst-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_src_ip(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
-
-        if (n.matches()) {
-            int ipaddr = get_ip_addr(n, subaction, log);
-            OFActionNetworkLayerSource action = new OFActionNetworkLayerSource();
-            action.setNetworkAddress(ipaddr);
-            log.debug("  action {}", action);
-
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionNetworkLayerSource.MINIMUM_LENGTH;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_ip(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
-
-        if (n.matches()) {
-            int ipaddr = get_ip_addr(n, subaction, log);
-            OFActionNetworkLayerDestination action = new OFActionNetworkLayerDestination();
-            action.setNetworkAddress(ipaddr);
-            log.debug("action {}", action);
- 
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionNetworkLayerDestination.MINIMUM_LENGTH;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_src_port(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction); 
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    short portnum = get_short(n.group(1));
-                    OFActionTransportLayerSource action = new OFActionTransportLayerSource();
-                    action.setTransportPort(portnum);
-                    log.debug("action {}", action);
-                    
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionTransportLayerSource.MINIMUM_LENGTH;;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_port(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction);
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    short portnum = get_short(n.group(1));
-                    OFActionTransportLayerDestination action = new OFActionTransportLayerDestination();
-                    action.setTransportPort(portnum);
-                    log.debug("action {}", action);
-                    
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionTransportLayerDestination.MINIMUM_LENGTH;;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid dst-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static byte[] get_mac_addr(Matcher n, String subaction, Logger log) {
-        byte[] macaddr = new byte[6];
-        
-        for (int i=0; i<6; i++) {
-            if (n.group(i+1) != null) {
-                try {
-                    macaddr[i] = get_byte("0x" + n.group(i+1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-mac in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-            else { 
-                log.debug("Invalid src-mac in: '{}' (null, error ignored)", subaction);
-                return null;
-            }
-        }
-        
-        return macaddr;
-    }
-    
-    private static int get_ip_addr(Matcher n, String subaction, Logger log) {
-        int ipaddr = 0;
-
-        for (int i=0; i<4; i++) {
-            if (n.group(i+1) != null) {
-                try {
-                    ipaddr = ipaddr<<8;
-                    ipaddr = ipaddr | get_int(n.group(i+1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-ip in: '{}' (error ignored)", subaction);
-                    return 0;
-                }
-            }
-            else {
-                log.debug("Invalid src-ip in: '{}' (null, error ignored)", subaction);
-                return 0;
-            }
-        }
-        
-        return ipaddr;
-    }
-    
-    // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static int get_int(String str) {
-        return Integer.decode(str);
-    }
-   
-    // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static short get_short(String str) {
-        return (short)(int)Integer.decode(str);
-    }
-   
-    // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static byte get_byte(String str) {
-        return Integer.decode(str).byteValue();
-    }
-
-    
 }
diff --git a/src/main/java/net/floodlightcontroller/packet/BSNPROBE.java b/src/main/java/net/floodlightcontroller/packet/BSNPROBE.java
index c9115eacb5c22c459cbaded572a64063125118c6..63f710e58748881ca2aabe1360e559448253fec8 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.openflow.util.HexString;
+import org.projectfloodlight.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 60887b3158e27a3d714927aab4f57b7085242164..2b9d0ea3a88fe2933f63ac2a898471022109635b 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 net.floodlightcontroller.util.MACAddress;
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.VlanVid;
 
 /**
  *
@@ -36,7 +36,7 @@ public class Ethernet extends BasePacket {
     public static final short TYPE_IPv4 = 0x0800;
     public static final short TYPE_LLDP = (short) 0x88cc;
     public static final short TYPE_BSN = (short) 0x8942;
-    public static final short VLAN_UNTAGGED = (short)0xffff;
+    public static final short VLAN_UNTAGGED = VlanVid.ZERO.getVlan(); // untagged vlan must be 0x0000 for loxi. We can use the convenient ZERO field
     public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
     public static Map<Short, Class<? extends IPacket>> etherTypeClassMap;
 
@@ -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;
@@ -64,17 +64,10 @@ public class Ethernet extends BasePacket {
         this.vlanID = VLAN_UNTAGGED;
     }
     
-    /**
-     * @return the destination MAC as a byte array
-     */
-    public byte[] getDestinationMACAddress() {
-        return destinationMACAddress.toBytes();
-    }
-    
     /**
      * @return the destination MAC
      */
-    public MACAddress getDestinationMAC() {
+    public MacAddress getDestinationMACAddress() {
         return destinationMACAddress;
     }
 
@@ -82,29 +75,30 @@ public class Ethernet extends BasePacket {
      * @param destinationMACAddress the destination MAC to set
      */
     public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) {
-        this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
+        this.destinationMACAddress = MacAddress.of(destinationMACAddress);
         return this;
     }
-
+    
     /**
      * @param destinationMACAddress the destination MAC to set
      */
-    public Ethernet setDestinationMACAddress(String destinationMACAddress) {
-        this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
+    public Ethernet setDestinationMACAddress(MacAddress destinationMACAddress) {
+        this.destinationMACAddress = destinationMACAddress;
         return this;
     }
 
     /**
-     * @return the source MACAddress as a byte array
+     * @param destinationMACAddress the destination MAC to set
      */
-    public byte[] getSourceMACAddress() {
-        return sourceMACAddress.toBytes();
+    public Ethernet setDestinationMACAddress(String destinationMACAddress) {
+        this.destinationMACAddress = MacAddress.of(destinationMACAddress);
+        return this;
     }
-    
+
     /**
      * @return the source MACAddress
      */
-    public MACAddress getSourceMAC() {
+    public MacAddress getSourceMACAddress() {
         return sourceMACAddress;
     }
 
@@ -112,7 +106,15 @@ public class Ethernet extends BasePacket {
      * @param sourceMACAddress the source MAC to set
      */
     public Ethernet setSourceMACAddress(byte[] sourceMACAddress) {
-        this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
+        this.sourceMACAddress = MacAddress.of(sourceMACAddress);
+        return this;
+    }
+    
+    /**
+     * @param sourceMACAddress the source MAC to set
+     */
+    public Ethernet setSourceMACAddress(MacAddress sourceMACAddress) {
+        this.sourceMACAddress = sourceMACAddress;
         return this;
     }
 
@@ -120,7 +122,7 @@ public class Ethernet extends BasePacket {
      * @param sourceMACAddress the source MAC to set
      */
     public Ethernet setSourceMACAddress(String sourceMACAddress) {
-        this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
+        this.sourceMACAddress = MacAddress.of(sourceMACAddress);
         return this;
     }
 
@@ -173,7 +175,7 @@ public class Ethernet extends BasePacket {
      * @return True if the Ethernet frame is broadcast, false otherwise
      */
     public boolean isBroadcast() {
-        assert(destinationMACAddress.length() == 6);
+        assert(destinationMACAddress.getLength() == 6);
         return destinationMACAddress.isBroadcast();
     }
     
@@ -213,8 +215,8 @@ public class Ethernet extends BasePacket {
         }
         byte[] data = new byte[length];
         ByteBuffer bb = ByteBuffer.wrap(data);
-        bb.put(destinationMACAddress.toBytes());
-        bb.put(sourceMACAddress.toBytes());
+        bb.put(destinationMACAddress.getBytes());
+        bb.put(sourceMACAddress.getBytes());
         if (vlanID != VLAN_UNTAGGED) {
             bb.putShort((short) 0x8100);
             bb.putShort((short) ((priorityCode << 13) | (vlanID & 0x0fff)));
@@ -234,16 +236,16 @@ public class Ethernet extends BasePacket {
             return null;
         ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
         if (this.destinationMACAddress == null)
-            this.destinationMACAddress = MACAddress.valueOf(new byte[6]);
-        byte[] dstAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
+            this.destinationMACAddress = MacAddress.of(new byte[6]);
+        byte[] dstAddr = new byte[MacAddress.NONE.getLength()];
         bb.get(dstAddr);
-        this.destinationMACAddress = MACAddress.valueOf(dstAddr);
+        this.destinationMACAddress = MacAddress.of(dstAddr);
 
         if (this.sourceMACAddress == null)
-            this.sourceMACAddress = MACAddress.valueOf(new byte[6]);
-        byte[] srcAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
+            this.sourceMACAddress = MacAddress.of(new byte[6]);
+        byte[] srcAddr = new byte[MacAddress.NONE.getLength()];
         bb.get(srcAddr);
-        this.sourceMACAddress = MACAddress.valueOf(srcAddr);
+        this.sourceMACAddress = MacAddress.of(srcAddr);
 
         short etherType = bb.getShort();
         if (etherType == (short) 0x8100) {
@@ -322,7 +324,7 @@ public class Ethernet extends BasePacket {
      * @return The macAddress as a byte array 
      */
     public static byte[] toMACAddress(String macAddress) {
-        return MACAddress.valueOf(macAddress).toBytes();
+        return MacAddress.of(macAddress).getBytes();
     }
 
 
@@ -333,7 +335,7 @@ public class Ethernet extends BasePacket {
      * @return a long containing the mac address bytes
      */
     public static long toLong(byte[] macAddress) {
-        return MACAddress.valueOf(macAddress).toLong();
+        return MacAddress.of(macAddress).getLong();
     }
 
     /**
@@ -342,7 +344,7 @@ public class Ethernet extends BasePacket {
      * @return the bytes of the mac address
      */
     public static byte[] toByteArray(long macAddress) {
-        return MACAddress.valueOf(macAddress).toBytes();
+        return MacAddress.of(macAddress).getBytes();
     }
     
     /* (non-Javadoc)
@@ -418,9 +420,9 @@ public class Ethernet extends BasePacket {
         sb.append("\ndl_vlan_pcp: ");
         sb.append(this.getPriorityCode());
         sb.append("\ndl_src: ");
-        sb.append(HexString.toHexString(this.getSourceMACAddress()));
+        sb.append(this.getSourceMACAddress().toString());
         sb.append("\ndl_dst: ");
-        sb.append(HexString.toHexString(this.getDestinationMACAddress()));
+        sb.append(this.getDestinationMACAddress().toString());
 
 
         if (pkt instanceof ARP) {
@@ -443,9 +445,9 @@ public class Ethernet extends BasePacket {
         else if (pkt instanceof IPv4) {
             IPv4 p = (IPv4) pkt;
             sb.append("\nnw_src: ");
-            sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
+            sb.append(p.getSourceAddress().toString());
             sb.append("\nnw_dst: ");
-            sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
+            sb.append(p.getDestinationAddress().toString());
             sb.append("\nnw_tos: ");
             sb.append(p.getDiffServ());
             sb.append("\nnw_proto: ");
diff --git a/src/main/java/net/floodlightcontroller/packet/ICMP.java b/src/main/java/net/floodlightcontroller/packet/ICMP.java
index 2988106484530d437df2b5fe62aac2c0a0bea480..6f0d95006aa0170b88a1b386842dd3c7e3d7f800 100644
--- a/src/main/java/net/floodlightcontroller/packet/ICMP.java
+++ b/src/main/java/net/floodlightcontroller/packet/ICMP.java
@@ -21,6 +21,8 @@ import java.nio.ByteBuffer;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.projectfloodlight.openflow.types.IpProtocol;
+
 /**
  * Implements ICMP packet format
  * @author shudong.zhou@bigswitch.com
@@ -126,7 +128,7 @@ public class ICMP extends BasePacket {
             bb.put(payloadData);
 
         if (this.parent != null && this.parent instanceof IPv4)
-            ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_ICMP);
+            ((IPv4)this.parent).setProtocol(IpProtocol.ICMP);
 
         // compute checksum if needed
         if (this.checksum == 0) {
diff --git a/src/main/java/net/floodlightcontroller/packet/IPv4.java b/src/main/java/net/floodlightcontroller/packet/IPv4.java
index 61d9730ba2040dd330e951f574b7c8471dcc051b..4f8efb07a31061a597646d7bc4bf46cbd5f47c60 100644
--- a/src/main/java/net/floodlightcontroller/packet/IPv4.java
+++ b/src/main/java/net/floodlightcontroller/packet/IPv4.java
@@ -26,6 +26,10 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.U8;
+
 /**
  * @author David Erickson (daviderickson@cs.stanford.edu)
  *
@@ -57,10 +61,10 @@ public class IPv4 extends BasePacket {
     protected byte flags;
     protected short fragmentOffset;
     protected byte ttl;
-    protected byte protocol;
+    protected IpProtocol protocol;
     protected short checksum;
-    protected int sourceAddress;
-    protected int destinationAddress;
+    protected IPv4Address sourceAddress;
+    protected IPv4Address destinationAddress;
     protected byte[] options;
 
     protected boolean isTruncated;
@@ -199,14 +203,14 @@ public class IPv4 extends BasePacket {
     /**
      * @return the protocol
      */
-    public byte getProtocol() {
+    public IpProtocol getProtocol() {
         return protocol;
     }
 
     /**
      * @param protocol the protocol to set
      */
-    public IPv4 setProtocol(byte protocol) {
+    public IPv4 setProtocol(IpProtocol protocol) {
         this.protocol = protocol;
         return this;
     }
@@ -234,46 +238,62 @@ public class IPv4 extends BasePacket {
     /**
      * @return the sourceAddress
      */
-    public int getSourceAddress() {
+    public IPv4Address getSourceAddress() {
         return sourceAddress;
     }
 
     /**
      * @param sourceAddress the sourceAddress to set
      */
-    public IPv4 setSourceAddress(int sourceAddress) {
+    public IPv4 setSourceAddress(IPv4Address sourceAddress) {
         this.sourceAddress = sourceAddress;
         return this;
     }
+    
+    /**
+     * @param sourceAddress the sourceAddress to set
+     */
+    public IPv4 setSourceAddress(int sourceAddress) {
+        this.sourceAddress = IPv4Address.of(sourceAddress);
+        return this;
+    }
 
     /**
      * @param sourceAddress the sourceAddress to set
      */
     public IPv4 setSourceAddress(String sourceAddress) {
-        this.sourceAddress = IPv4.toIPv4Address(sourceAddress);
+        this.sourceAddress = IPv4Address.of(sourceAddress);
         return this;
     }
 
     /**
      * @return the destinationAddress
      */
-    public int getDestinationAddress() {
+    public IPv4Address getDestinationAddress() {
         return destinationAddress;
     }
 
     /**
      * @param destinationAddress the destinationAddress to set
      */
-    public IPv4 setDestinationAddress(int destinationAddress) {
+    public IPv4 setDestinationAddress(IPv4Address destinationAddress) {
         this.destinationAddress = destinationAddress;
         return this;
     }
+    
+    /**
+     * @param destinationAddress the destinationAddress to set
+     */
+    public IPv4 setDestinationAddress(int destinationAddress) {
+        this.destinationAddress = IPv4Address.of(destinationAddress);
+        return this;
+    }
 
     /**
      * @param destinationAddress the destinationAddress to set
      */
     public IPv4 setDestinationAddress(String destinationAddress) {
-        this.destinationAddress = IPv4.toIPv4Address(destinationAddress);
+        this.destinationAddress = IPv4Address.of(destinationAddress);
         return this;
     }
 
@@ -328,10 +348,10 @@ public class IPv4 extends BasePacket {
         bb.putShort((short)(((this.flags & IPV4_FLAGS_MASK) << IPV4_FLAGS_SHIFT)
                 | (this.fragmentOffset & IPV4_OFFSET_MASK)));
         bb.put(this.ttl);
-        bb.put(this.protocol);
+        bb.putShort(this.protocol.getIpProtocolNumber());
         bb.putShort(this.checksum);
-        bb.putInt(this.sourceAddress);
-        bb.putInt(this.destinationAddress);
+        bb.putInt(this.sourceAddress.getInt());
+        bb.putInt(this.destinationAddress.getInt());
         if (this.options != null)
             bb.put(this.options);
         if (payloadData != null)
@@ -373,10 +393,10 @@ public class IPv4 extends BasePacket {
         this.flags = (byte) ((sscratch >> IPV4_FLAGS_SHIFT) & IPV4_FLAGS_MASK);
         this.fragmentOffset = (short) (sscratch & IPV4_OFFSET_MASK);
         this.ttl = bb.get();
-        this.protocol = bb.get();
+        this.protocol = IpProtocol.of(U8.f(bb.get()));
         this.checksum = bb.getShort();
-        this.sourceAddress = bb.getInt();
-        this.destinationAddress = bb.getInt();
+        this.sourceAddress = IPv4Address.of(bb.getInt());
+        this.destinationAddress = IPv4Address.of(bb.getInt());
 
         if (this.headerLength > 5) {
             int optionsLength = (this.headerLength - 5) * 4;
@@ -398,8 +418,8 @@ public class IPv4 extends BasePacket {
         } else {
             if (log.isTraceEnabled() && isFragment) {
                 log.trace("IPv4 fragment detected {}->{}, forward using IP header only",
-                        fromIPv4Address(this.sourceAddress),
-                        fromIPv4Address(this.destinationAddress));
+                        this.sourceAddress.toString(),
+                        this.destinationAddress.toString());
             }
             payload = new Data();
         }
@@ -540,15 +560,15 @@ public class IPv4 extends BasePacket {
         final int prime = 2521;
         int result = super.hashCode();
         result = prime * result + checksum;
-        result = prime * result + destinationAddress;
+        result = prime * result + destinationAddress.getInt();
         result = prime * result + diffServ;
         result = prime * result + flags;
         result = prime * result + fragmentOffset;
         result = prime * result + headerLength;
         result = prime * result + identification;
         result = prime * result + Arrays.hashCode(options);
-        result = prime * result + protocol;
-        result = prime * result + sourceAddress;
+        result = prime * result + protocol.getIpProtocolNumber();
+        result = prime * result + sourceAddress.getInt();
         result = prime * result + totalLength;
         result = prime * result + ttl;
         result = prime * result + version;
@@ -569,7 +589,7 @@ public class IPv4 extends BasePacket {
         IPv4 other = (IPv4) obj;
         if (checksum != other.checksum)
             return false;
-        if (destinationAddress != other.destinationAddress)
+        if (!destinationAddress.equals(other.destinationAddress))
             return false;
         if (diffServ != other.diffServ)
             return false;
@@ -583,9 +603,9 @@ public class IPv4 extends BasePacket {
             return false;
         if (!Arrays.equals(options, other.options))
             return false;
-        if (protocol != other.protocol)
+        if (!protocol.equals(other.protocol))
             return false;
-        if (sourceAddress != other.sourceAddress)
+        if (!sourceAddress.equals(other.sourceAddress))
             return false;
         if (totalLength != other.totalLength)
             return false;
diff --git a/src/main/java/net/floodlightcontroller/packet/TCP.java b/src/main/java/net/floodlightcontroller/packet/TCP.java
index 6af5932a55c15d9e4b5729ff6eac8998c9dc16eb..f4b9a50260c94137a3d0ab7eefe9debdf14d8ba7 100644
--- a/src/main/java/net/floodlightcontroller/packet/TCP.java
+++ b/src/main/java/net/floodlightcontroller/packet/TCP.java
@@ -20,13 +20,16 @@ package net.floodlightcontroller.packet;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.TransportPort;
+
 /**
  *
  * @author shudong.zhou@bigswitch.com
  */
 public class TCP extends BasePacket {
-    protected short sourcePort;
-    protected short destinationPort;
+    protected TransportPort sourcePort;
+    protected TransportPort destinationPort;
     protected int sequence;
     protected int acknowledge;
     protected byte dataOffset;
@@ -39,32 +42,48 @@ public class TCP extends BasePacket {
     /**
      * @return the sourcePort
      */
-    public short getSourcePort() {
+    public TransportPort getSourcePort() {
         return sourcePort;
     }
 
     /**
      * @param sourcePort the sourcePort to set
      */
-    public TCP setSourcePort(short sourcePort) {
+    public TCP setSourcePort(TransportPort sourcePort) {
         this.sourcePort = sourcePort;
         return this;
     }
+    
+    /**
+     * @param sourcePort the sourcePort to set
+     */
+    public TCP setSourcePort(int sourcePort) {
+        this.sourcePort = TransportPort.of(sourcePort);
+        return this;
+    }
 
     /**
      * @return the destinationPort
      */
-    public short getDestinationPort() {
+    public TransportPort getDestinationPort() {
         return destinationPort;
     }
 
     /**
      * @param destinationPort the destinationPort to set
      */
-    public TCP setDestinationPort(short destinationPort) {
+    public TCP setDestinationPort(TransportPort destinationPort) {
         this.destinationPort = destinationPort;
         return this;
     }
+    
+    /**
+     * @param destinationPort the destinationPort to set
+     */
+    public TCP setDestinationPort(short destinationPort) {
+        this.destinationPort = TransportPort.of(destinationPort);
+        return this;
+    }
 
     /**
      * @return the checksum
@@ -166,8 +185,8 @@ public class TCP extends BasePacket {
         byte[] data = new byte[length];
         ByteBuffer bb = ByteBuffer.wrap(data);
 
-        bb.putShort(this.sourcePort);
-        bb.putShort(this.destinationPort);
+        bb.putShort((short)this.sourcePort.getPort()); //TCP ports are defined to be 16 bits
+        bb.putShort((short)this.destinationPort.getPort());
         bb.putInt(this.sequence);
         bb.putInt(this.acknowledge);
         bb.putShort((short) (this.flags | (dataOffset << 12)));
@@ -185,7 +204,7 @@ public class TCP extends BasePacket {
             bb.put(payloadData);
 
         if (this.parent != null && this.parent instanceof IPv4)
-            ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_TCP);
+            ((IPv4)this.parent).setProtocol(IpProtocol.TCP);
 
         // compute checksum if needed
         if (this.checksum == 0) {
@@ -195,11 +214,11 @@ public class TCP extends BasePacket {
             // compute pseudo header mac
             if (this.parent != null && this.parent instanceof IPv4) {
                 IPv4 ipv4 = (IPv4) this.parent;
-                accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
-                        + (ipv4.getSourceAddress() & 0xffff);
-                accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
-                        + (ipv4.getDestinationAddress() & 0xffff);
-                accumulation += ipv4.getProtocol() & 0xff;
+                accumulation += ((ipv4.getSourceAddress().getInt() >> 16) & 0xffff)
+                        + (ipv4.getSourceAddress().getInt() & 0xffff);
+                accumulation += ((ipv4.getDestinationAddress().getInt() >> 16) & 0xffff)
+                        + (ipv4.getDestinationAddress().getInt() & 0xffff);
+                accumulation += ipv4.getProtocol().getIpProtocolNumber() & 0xff;
                 accumulation += length & 0xffff;
             }
 
@@ -227,8 +246,8 @@ public class TCP extends BasePacket {
         final int prime = 5807;
         int result = super.hashCode();
         result = prime * result + checksum;
-        result = prime * result + destinationPort;
-        result = prime * result + sourcePort;
+        result = prime * result + destinationPort.getPort();
+        result = prime * result + sourcePort.getPort();
         return result;
     }
 
@@ -261,8 +280,8 @@ public class TCP extends BasePacket {
     public IPacket deserialize(byte[] data, int offset, int length)
             throws PacketParsingException {
         ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.sourcePort = bb.getShort();
-        this.destinationPort = bb.getShort();
+        this.sourcePort = TransportPort.of(bb.getShort());
+        this.destinationPort = TransportPort.of(bb.getShort());
         this.sequence = bb.getInt();
         this.acknowledge = bb.getInt();
         this.flags = bb.getShort();
diff --git a/src/main/java/net/floodlightcontroller/packet/UDP.java b/src/main/java/net/floodlightcontroller/packet/UDP.java
index 710762c097137bede7a84da1fa7cd6de2a586057..fad7a128f85ccbb074665a11dc250189e540a884 100644
--- a/src/main/java/net/floodlightcontroller/packet/UDP.java
+++ b/src/main/java/net/floodlightcontroller/packet/UDP.java
@@ -21,6 +21,9 @@ import java.nio.ByteBuffer;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.TransportPort;
+
 /**
  *
  * @author David Erickson (daviderickson@cs.stanford.edu)
@@ -40,40 +43,56 @@ public class UDP extends BasePacket {
         
     }
 
-    protected short sourcePort;
-    protected short destinationPort;
+    protected TransportPort sourcePort;
+    protected TransportPort destinationPort;
     protected short length;
     protected short checksum;
 
     /**
      * @return the sourcePort
      */
-    public short getSourcePort() {
+    public TransportPort getSourcePort() {
         return sourcePort;
     }
 
     /**
      * @param sourcePort the sourcePort to set
      */
-    public UDP setSourcePort(short sourcePort) {
+    public UDP setSourcePort(TransportPort sourcePort) {
         this.sourcePort = sourcePort;
         return this;
     }
+    
+    /**
+     * @param sourcePort the sourcePort to set
+     */
+    public UDP setSourcePort(short sourcePort) {
+        this.sourcePort = TransportPort.of(sourcePort);
+        return this;
+    }
 
     /**
      * @return the destinationPort
      */
-    public short getDestinationPort() {
+    public TransportPort getDestinationPort() {
         return destinationPort;
     }
 
     /**
      * @param destinationPort the destinationPort to set
      */
-    public UDP setDestinationPort(short destinationPort) {
+    public UDP setDestinationPort(TransportPort destinationPort) {
         this.destinationPort = destinationPort;
         return this;
     }
+    
+    /**
+     * @param destinationPort the destinationPort to set
+     */
+    public UDP setDestinationPort(short destinationPort) {
+        this.destinationPort = TransportPort.of(destinationPort);
+        return this;
+    }
 
     /**
      * @return the length
@@ -122,15 +141,15 @@ public class UDP extends BasePacket {
         byte[] data = new byte[this.length];
         ByteBuffer bb = ByteBuffer.wrap(data);
 
-        bb.putShort(this.sourcePort);
-        bb.putShort(this.destinationPort);
+        bb.putShort((short)this.sourcePort.getPort()); // UDP packet port numbers are 16 bit
+        bb.putShort((short)this.destinationPort.getPort());
         bb.putShort(this.length);
         bb.putShort(this.checksum);
         if (payloadData != null)
             bb.put(payloadData);
 
         if (this.parent != null && this.parent instanceof IPv4)
-            ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_UDP);
+            ((IPv4)this.parent).setProtocol(IpProtocol.UDP);
 
         // compute checksum if needed
         if (this.checksum == 0) {
@@ -140,11 +159,11 @@ public class UDP extends BasePacket {
             // compute pseudo header mac
             if (this.parent != null && this.parent instanceof IPv4) {
                 IPv4 ipv4 = (IPv4) this.parent;
-                accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
-                        + (ipv4.getSourceAddress() & 0xffff);
-                accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
-                        + (ipv4.getDestinationAddress() & 0xffff);
-                accumulation += ipv4.getProtocol() & 0xff;
+                accumulation += ((ipv4.getSourceAddress().getInt() >> 16) & 0xffff)
+                        + (ipv4.getSourceAddress().getInt() & 0xffff);
+                accumulation += ((ipv4.getDestinationAddress().getInt() >> 16) & 0xffff)
+                        + (ipv4.getDestinationAddress().getInt() & 0xffff);
+                accumulation += ipv4.getProtocol().getIpProtocolNumber() & 0xff;
                 accumulation += this.length & 0xffff;
             }
 
@@ -172,9 +191,9 @@ public class UDP extends BasePacket {
         final int prime = 5807;
         int result = super.hashCode();
         result = prime * result + checksum;
-        result = prime * result + destinationPort;
+        result = prime * result + destinationPort.getPort();
         result = prime * result + length;
-        result = prime * result + sourcePort;
+        result = prime * result + sourcePort.getPort();
         return result;
     }
 
@@ -205,8 +224,8 @@ public class UDP extends BasePacket {
     public IPacket deserialize(byte[] data, int offset, int length)
             throws PacketParsingException {
         ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        this.sourcePort = bb.getShort();
-        this.destinationPort = bb.getShort();
+        this.sourcePort = TransportPort.of(bb.getShort());
+        this.destinationPort = TransportPort.of(bb.getShort());
         this.length = bb.getShort();
         this.checksum = bb.getShort();
 
diff --git a/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java b/src/main/java/net/floodlightcontroller/perfmon/IPktInProcessingTimeService.java
index cc70487eb8497e4330b59f679196450a57e5559d..0198d16a45863b9c89ce9b51aec59ddc4a787532 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.openflow.protocol.OFMessage;
+import org.projectfloodlight.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 51641ccc7651f80c7aec121763a3b04a7273b7b8..c10bc93a67a665d270e520fcee7d0b0965335b11 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.openflow.protocol.OFMessage;
+import org.projectfloodlight.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 366721120e332de7eb700ed383b521c7afb1a116..9e754469d917481db367d2afb67e014866b28c1e 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.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.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 0c3703c97f9b3f8f07002203a0a7946c776cf0e7..28ca79f843a5f4984ab25eb012e95141c062c2bb 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.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
 
 public class BroadcastTree {
-    protected HashMap<Long, Link> links;
-    protected HashMap<Long, Integer> costs;
+    protected HashMap<DatapathId, Link> links;
+    protected HashMap<DatapathId, Integer> costs;
 
     public BroadcastTree() {
-        links = new HashMap<Long, Link>();
-        costs = new HashMap<Long, Integer>();
+        links = new HashMap<DatapathId, Link>();
+        costs = new HashMap<DatapathId, Integer>();
     }
 
-    public BroadcastTree(HashMap<Long, Link> links, HashMap<Long, Integer> costs) {
+    public BroadcastTree(HashMap<DatapathId, Link> links, HashMap<DatapathId, Integer> costs) {
         this.links = links;
         this.costs = costs;
     }
 
-    public Link getTreeLink(long node) {
+    public Link getTreeLink(DatapathId node) {
         return links.get(node);
     }
 
-    public int getCost(long node) {
+    public int getCost(DatapathId node) {
         if (costs.get(node) == null) return -1;
         return (costs.get(node));
     }
 
-    public HashMap<Long, Link> getLinks() {
+    public HashMap<DatapathId, Link> getLinks() {
         return links;
     }
 
-    public void addTreeLink(long myNode, Link link) {
+    public void addTreeLink(DatapathId myNode, Link link) {
         links.put(myNode, link);
     }
 
     public String toString() {
         StringBuffer sb = new StringBuffer();
-        for(long n: links.keySet()) {
-            sb.append("[" + HexString.toHexString(n) + ": cost=" + costs.get(n) + ", " + links.get(n) + "]");
+        for(DatapathId n: links.keySet()) {
+            sb.append("[" + n.toString() + ": cost=" + costs.get(n) + ", " + links.get(n) + "]");
         }
         return sb.toString();
     }
 
-    public HashMap<Long, Integer> getCosts() {
+    public HashMap<DatapathId, 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 2ef42197bd8a3a6a42c1b76df0682e37db5bf10e..878db1c99116ab3e4249d6c4a75a473a165a2077 100644
--- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
+++ b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
@@ -32,11 +32,11 @@ 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.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.devicemanager.SwitchPort;
-import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
 import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.IRoutingDecision;
@@ -46,14 +46,22 @@ import net.floodlightcontroller.topology.NodePortTuple;
 import net.floodlightcontroller.util.OFMessageDamper;
 import net.floodlightcontroller.util.TimedCache;
 
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
+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.OFVersion;
+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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -63,553 +71,445 @@ import org.slf4j.LoggerFactory;
  * decision.
  */
 @LogMessageCategory("Flow Programming")
-public abstract class ForwardingBase
-    implements IOFMessageListener {
-
-    protected static Logger log =
-            LoggerFactory.getLogger(ForwardingBase.class);
-
-    protected static int OFMESSAGE_DAMPER_CAPACITY = 10000; // TODO: find sweet spot
-    protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
-
-    public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds
-    public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
-
-    public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT_CONSTANT = 5;
-    public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT_CONSTANT = 0;
-
-    protected IFloodlightProviderService floodlightProvider;
-    protected IDeviceService deviceManager;
-    protected IRoutingService routingEngine;
-    protected ITopologyService topology;
-    protected ICounterStoreService counterStore;
-
-    protected OFMessageDamper messageDamper;
-
-    // for broadcast loop suppression
-    protected boolean broadcastCacheFeature = true;
-    public final int prime1 = 2633;  // for hash calculation
-    public final static int prime2 = 4357;  // for hash calculation
-    public TimedCache<Long> broadcastCache =
-        new TimedCache<Long>(100, 5*1000);  // 5 seconds interval;
-
-    // flow-mod - for use in the cookie
-    public static final int FORWARDING_APP_ID = 2; // TODO: This must be managed
-                                                   // by a global APP_ID class
-    static {
-        AppCookie.registerApp(FORWARDING_APP_ID, "Forwarding");
-    }
-    public static final long appCookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
-
-    // Comparator for sorting by SwitchCluster
-    public Comparator<SwitchPort> clusterIdComparator =
-            new Comparator<SwitchPort>() {
-                @Override
-                public int compare(SwitchPort d1, SwitchPort d2) {
-                    Long d1ClusterId =
-                            topology.getL2DomainId(d1.getSwitchDPID());
-                    Long d2ClusterId =
-                            topology.getL2DomainId(d2.getSwitchDPID());
-                    return d1ClusterId.compareTo(d2ClusterId);
-                }
-            };
-
-    /**
-     * init data structures
-     *
-     */
-    protected void init() {
-        messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
-                                            EnumSet.of(OFType.FLOW_MOD),
-                                            OFMESSAGE_DAMPER_TIMEOUT);
-    }
-
-    /**
-     * Adds a listener for devicemanager and registers for PacketIns.
-     */
-    protected void startUp() {
-        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-    }
-
-    /**
-     * Returns the application name "forwarding".
-     */
-    @Override
-    public String getName() {
-        return "forwarding";
-    }
-
-    /**
-     * All subclasses must define this function if they want any specific
-     * forwarding action
-     *
-     * @param sw
-     *            Switch that the packet came in from
-     * @param pi
-     *            The packet that came in
-     * @param decision
-     *            Any decision made by a policy engine
-     */
-    public abstract Command
-            processPacketInMessage(IOFSwitch sw, OFPacketIn pi,
-                                   IRoutingDecision decision,
-                                   FloodlightContext cntx);
-
-    @Override
-    public Command receive(IOFSwitch sw, OFMessage msg,
-                           FloodlightContext cntx) {
-        switch (msg.getType()) {
-            case PACKET_IN:
-                IRoutingDecision decision = null;
-                if (cntx != null)
-                     decision =
-                             IRoutingDecision.rtStore.get(cntx,
-                                                          IRoutingDecision.CONTEXT_DECISION);
-
-                return this.processPacketInMessage(sw,
-                                                   (OFPacketIn) msg,
-                                                   decision,
-                                                   cntx);
-            default:
-                break;
-        }
-        return Command.CONTINUE;
-    }
-
-    /**
-     * Push routes from back to front
-     * @param route Route to push
-     * @param match OpenFlow fields to match on
-     * @param srcSwPort Source switch port for the first hop
-     * @param dstSwPort Destination switch port for final hop
-     * @param cookie The cookie to set in each flow_mod
-     * @param cntx The floodlight context
-     * @param reqeustFlowRemovedNotifn if set to true then the switch would
-     * send a flow mod removal notification when the flow mod expires
-     * @param doFlush if set to true then the flow mod would be immediately
-     *        written to the switch
-     * @param flowModCommand flow mod. command to use, e.g. OFFlowMod.OFPFC_ADD,
-     *        OFFlowMod.OFPFC_MODIFY etc.
-     * @return srcSwitchIincluded True if the source switch is included in this route
-     */
-    @LogMessageDocs({
-        @LogMessageDoc(level="WARN",
-            message="Unable to push route, switch at DPID {dpid} not available",
-            explanation="A switch along the calculated path for the " +
-                        "flow has disconnected.",
-            recommendation=LogMessageDoc.CHECK_SWITCH),
-        @LogMessageDoc(level="ERROR",
-            message="Failure writing flow mod",
-            explanation="An I/O error occurred while writing a " +
-                        "flow modification to a switch",
-            recommendation=LogMessageDoc.CHECK_SWITCH)
-    })
-    public boolean pushRoute(Route route, OFMatch match,
-                             Integer wildcard_hints,
-                             OFPacketIn pi,
-                             long pinSwitch,
-                             long cookie,
-                             FloodlightContext cntx,
-                             boolean reqeustFlowRemovedNotifn,
-                             boolean doFlush,
-                             short   flowModCommand) {
-
-        boolean srcSwitchIncluded = false;
-        OFFlowMod fm =
-                (OFFlowMod) floodlightProvider.getOFMessageFactory()
-                                              .getMessage(OFType.FLOW_MOD);
-        OFActionOutput action = new OFActionOutput();
-        action.setMaxLength((short)0xffff);
-        List<OFAction> actions = new ArrayList<OFAction>();
-        actions.add(action);
-
-        fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
-            .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
-            .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-            .setCookie(cookie)
-            .setCommand(flowModCommand)
-            .setMatch(match)
-            .setActions(actions)
-            .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
-
-        List<NodePortTuple> switchPortList = route.getPath();
-
-        for (int indx = switchPortList.size()-1; indx > 0; indx -= 2) {
-            // indx and indx-1 will always have the same switch DPID.
-            long switchDPID = switchPortList.get(indx).getNodeId();
-            IOFSwitch sw = floodlightProvider.getSwitch(switchDPID);
-            if (sw == null) {
-                if (log.isWarnEnabled()) {
-                    log.warn("Unable to push route, switch at DPID {} " +
-                            "not available", switchDPID);
-                }
-                return srcSwitchIncluded;
-            }
-
-            // set the match.
-            fm.setMatch(wildcard(match, sw, wildcard_hints));
-
-            // set buffer id if it is the source switch
-            if (1 == indx) {
-                // Set the flag to request flow-mod removal notifications only for the
-                // source switch. The removal message is used to maintain the flow
-                // cache. Don't set the flag for ARP messages - TODO generalize check
-                if ((reqeustFlowRemovedNotifn)
-                        && (match.getDataLayerType() != Ethernet.TYPE_ARP)) {
-                    /**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());
-                }
-            }
-
-            short outPort = switchPortList.get(indx).getPortId();
-            short inPort = switchPortList.get(indx-1).getPortId();
-            // set input and output ports on the switch
-            fm.getMatch().setInputPort(inPort);
-            ((OFActionOutput)fm.getActions().get(0)).setPort(outPort);
-
-            try {
-                counterStore.updatePktOutFMCounterStoreLocal(sw, fm);
-                if (log.isTraceEnabled()) {
-                    log.trace("Pushing Route flowmod routeIndx={} " +
-                            "sw={} inPort={} outPort={}",
-                            new Object[] {indx,
-                                          sw,
-                                          fm.getMatch().getInputPort(),
-                                          outPort });
-                }
-                messageDamper.write(sw, fm, cntx);
-                if (doFlush) {
-                    sw.flush();
-                    counterStore.updateFlush();
-                }
-
-                // Push the packet out the source switch
-                if (sw.getId() == pinSwitch) {
-                    // TODO: Instead of doing a packetOut here we could also
-                    // send a flowMod with bufferId set....
-                    pushPacket(sw, pi, false, outPort, cntx);
-                    srcSwitchIncluded = true;
-                }
-            } catch (IOException e) {
-                log.error("Failure writing flow mod", e);
-            }
-
-            try {
-                fm = fm.clone();
-            } catch (CloneNotSupportedException e) {
-                log.error("Failure cloning flow mod", e);
-            }
-        }
-
-        return srcSwitchIncluded;
-    }
-
-    protected OFMatch wildcard(OFMatch match, IOFSwitch sw,
-                               Integer wildcard_hints) {
-        if (wildcard_hints != null) {
-            return match.clone().setWildcards(wildcard_hints.intValue());
-        }
-        return match.clone();
-    }
-
-    /**
-     * Pushes a packet-out to a switch. If bufferId != BUFFER_ID_NONE we
-     * assume that the packetOut switch is the same as the packetIn switch
-     * and we will use the bufferId. In this case the packet can be null
-     * Caller needs to make sure that inPort and outPort differs
-     * @param packet    packet data to send.
-     * @param sw        switch from which packet-out is sent
-     * @param bufferId  bufferId
-     * @param inPort    input port
-     * @param outPort   output port
-     * @param cntx      context of the packet
-     * @param flush     force to flush the packet.
-     */
-    @LogMessageDocs({
-        @LogMessageDoc(level="ERROR",
-            message="BufferId is not and packet data is null. " +
-                    "Cannot send packetOut. " +
-                    "srcSwitch={dpid} inPort={port} outPort={port}",
-            explanation="The switch send a malformed packet-in." +
-                        "The packet will be dropped",
-            recommendation=LogMessageDoc.REPORT_SWITCH_BUG),
-        @LogMessageDoc(level="ERROR",
-            message="Failure writing packet out",
-            explanation="An I/O error occurred while writing a " +
-                    "packet out to a switch",
-            recommendation=LogMessageDoc.CHECK_SWITCH)
-    })
-
-    /**
-     * Pushes a packet-out to a switch.  The assumption here is that
-     * the packet-in was also generated from the same switch.  Thus, if the input
-     * port of the packet-in and the outport are the same, the function will not
-     * push the packet-out.
-     * @param sw        switch that generated the packet-in, and from which packet-out is sent
-     * @param pi        packet-in
-     * @param useBufferId  if true, use the bufferId from the packet in and
-     * do not add the packetIn's payload. If false set bufferId to
-     * BUFFER_ID_NONE and use the packetIn's payload
-     * @param outport   output port
-     * @param cntx      context of the packet
-     */
-    protected void pushPacket(IOFSwitch sw, OFPacketIn pi,
-                           boolean useBufferId,
-                           short outport, FloodlightContext cntx) {
-
-        if (pi == null) {
-            return;
-        }
-
-        // The assumption here is (sw) is the switch that generated the
-        // packet-in. If the input port is the same as output port, then
-        // the packet-out should be ignored.
-        if (pi.getInPort() == outport) {
-            if (log.isDebugEnabled()) {
-                log.debug("Attempting to do packet-out to the same " +
-                          "interface as packet-in. Dropping packet. " +
-                          " SrcSwitch={}, pi={}",
-                          new Object[]{sw, pi});
-                return;
-            }
-        }
-
-        if (log.isTraceEnabled()) {
-            log.trace("PacketOut srcSwitch={} pi={}",
-                      new Object[] {sw, pi});
-        }
-
-        OFPacketOut po =
-                (OFPacketOut) floodlightProvider.getOFMessageFactory()
-                                                .getMessage(OFType.PACKET_OUT);
-
-        // set actions
-        List<OFAction> actions = new ArrayList<OFAction>();
-        actions.add(new OFActionOutput(outport, (short) 0xffff));
-
-        po.setActions(actions)
-          .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
-        short poLength =
-                (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
-
-        if (useBufferId) {
-            po.setBufferId(pi.getBufferId());
-        } else {
-            po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
-        }
-
-        if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
-            byte[] packetData = pi.getPacketData();
-            poLength += packetData.length;
-            po.setPacketData(packetData);
-        }
-
-        po.setInPort(pi.getInPort());
-        po.setLength(poLength);
-
-        try {
-            counterStore.updatePktOutFMCounterStoreLocal(sw, po);
-            messageDamper.write(sw, po, cntx);
-        } catch (IOException e) {
-            log.error("Failure writing packet out", e);
-        }
-    }
-
-
-    /**
-     * Write packetout message to sw with output actions to one or more
-     * output ports with inPort/outPorts passed in.
-     * @param packetData
-     * @param sw
-     * @param inPort
-     * @param ports
-     * @param cntx
-     */
-    public void packetOutMultiPort(byte[] packetData,
-                                   IOFSwitch sw,
-                                   short inPort,
-                                   Set<Integer> outPorts,
-                                   FloodlightContext cntx) {
-        //setting actions
-        List<OFAction> actions = new ArrayList<OFAction>();
-
-        Iterator<Integer> j = outPorts.iterator();
-
-        while (j.hasNext())
-        {
-            actions.add(new OFActionOutput(j.next().shortValue(),
-                                           (short) 0));
-        }
-
-        OFPacketOut po =
-                (OFPacketOut) floodlightProvider.getOFMessageFactory().
-                getMessage(OFType.PACKET_OUT);
-        po.setActions(actions);
-        po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH *
-                outPorts.size()));
-
-        // set buffer-id to BUFFER_ID_NONE, and set in-port to OFPP_NONE
-        po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
-        po.setInPort(inPort);
-
-        // data (note buffer_id is always BUFFER_ID_NONE) and length
-        short poLength = (short)(po.getActionsLength() +
-                OFPacketOut.MINIMUM_LENGTH);
-        poLength += packetData.length;
-        po.setPacketData(packetData);
-        po.setLength(poLength);
-
-        try {
-            counterStore.updatePktOutFMCounterStoreLocal(sw, po);
-            if (log.isTraceEnabled()) {
-                log.trace("write broadcast packet on switch-id={} " +
-                        "interfaces={} packet-out={}",
-                        new Object[] {sw.getId(), outPorts, po});
-            }
-            messageDamper.write(sw, po, cntx);
-
-        } catch (IOException e) {
-            log.error("Failure writing packet out", e);
-        }
-    }
-
-    /**
-     * @see packetOutMultiPort
-     * Accepts a PacketIn instead of raw packet data. Note that the inPort
-     * and switch can be different than the packet in switch/port
-     */
-    public void packetOutMultiPort(OFPacketIn pi,
-                                   IOFSwitch sw,
-                                   short inPort,
-                                   Set<Integer> outPorts,
-                                   FloodlightContext cntx) {
-        packetOutMultiPort(pi.getPacketData(), sw, inPort, outPorts, cntx);
-    }
-
-    /**
-     * @see packetOutMultiPort
-     * Accepts an IPacket instead of raw packet data. Note that the inPort
-     * and switch can be different than the packet in switch/port
-     */
-    public void packetOutMultiPort(IPacket packet,
-                                   IOFSwitch sw,
-                                   short inPort,
-                                   Set<Integer> outPorts,
-                                   FloodlightContext cntx) {
-        packetOutMultiPort(packet.serialize(), sw, inPort, outPorts, cntx);
-    }
-
-    protected boolean isInBroadcastCache(IOFSwitch sw, OFPacketIn pi,
-                        FloodlightContext cntx) {
-        // Get the cluster id of the switch.
-        // Get the hash of the Ethernet packet.
-        if (sw == null) return true;
-
-        // If the feature is disabled, always return false;
-        if (!broadcastCacheFeature) return false;
-
-        Ethernet eth =
-            IFloodlightProviderService.bcStore.get(cntx,
-                IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-
-        Long broadcastHash;
-        broadcastHash = topology.getL2DomainId(sw.getId()) * prime1 +
-                        pi.getInPort() * prime2 + eth.hashCode();
-        if (broadcastCache.update(broadcastHash)) {
-            sw.updateBroadcastCache(broadcastHash, pi.getInPort());
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    protected boolean isInSwitchBroadcastCache(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
-        if (sw == null) return true;
-
-        // If the feature is disabled, always return false;
-        if (!broadcastCacheFeature) return false;
-
-        // Get the hash of the Ethernet packet.
-        Ethernet eth =
-                IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-
-        long hash =  pi.getInPort() * prime2 + eth.hashCode();
-
-        // some FORWARD_OR_FLOOD packets are unicast with unknown destination mac
-        return sw.updateBroadcastCache(hash, pi.getInPort());
-    }
-
-    @LogMessageDocs({
-        @LogMessageDoc(level="ERROR",
-            message="Failure writing deny flow mod",
-            explanation="An I/O error occurred while writing a " +
-                    "deny flow mod to a switch",
-            recommendation=LogMessageDoc.CHECK_SWITCH)
-    })
-    public static boolean
-            blockHost(IFloodlightProviderService floodlightProvider,
-                      SwitchPort sw_tup, long host_mac,
-                      short hardTimeout, long cookie) {
-
-        if (sw_tup == null) {
-            return false;
-        }
-
-        IOFSwitch sw =
-                floodlightProvider.getSwitch(sw_tup.getSwitchDPID());
-        if (sw == null) return false;
-        int inputPort = sw_tup.getPort();
-        log.debug("blockHost sw={} port={} mac={}",
-                  new Object[] { sw, sw_tup.getPort(), Long.valueOf(host_mac) });
-
-        // Create flow-mod based on packet-in and src-switch
-        OFFlowMod fm =
-                (OFFlowMod) floodlightProvider.getOFMessageFactory()
-                                              .getMessage(OFType.FLOW_MOD);
-        OFMatch match = new OFMatch();
-        List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to
-                                                            // drop
-        match.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);
-        }
-        fm.setCookie(cookie)
-          .setHardTimeout(hardTimeout)
-          .setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
-          .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-          .setMatch(match)
-          .setActions(actions)
-          .setLengthU(OFFlowMod.MINIMUM_LENGTH); // +OFActionOutput.MINIMUM_LENGTH);
-
-        try {
-            log.debug("write drop flow-mod sw={} match={} flow-mod={}",
-                      new Object[] { sw, match, fm });
-            // TODO: can't use the message damper sine this method is static
-            sw.write(fm, null);
-        } catch (IOException e) {
-            log.error("Failure writing deny flow mod", e);
-            return false;
-        }
-        return true;
-
-    }
-
-    @Override
-    public boolean isCallbackOrderingPrereq(OFType type, String name) {
-        return (type.equals(OFType.PACKET_IN) &&
-                (name.equals("topology") ||
-                 name.equals("devicemanager")));
-    }
-
-    @Override
-    public boolean isCallbackOrderingPostreq(OFType type, String name) {
-        return false;
-    }
+public abstract class ForwardingBase implements IOFMessageListener {
+
+	protected static Logger log =
+			LoggerFactory.getLogger(ForwardingBase.class);
+
+	protected static int OFMESSAGE_DAMPER_CAPACITY = 10000; // TODO: find sweet spot
+	protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
+
+	public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds
+	public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
+
+	public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT_CONSTANT = 5;
+	public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT_CONSTANT = 0;
+
+	protected IFloodlightProviderService floodlightProviderService;
+	protected IOFSwitchService switchService;
+	protected IDeviceService deviceManagerService;
+	protected IRoutingService routingEngineService;
+	protected ITopologyService topologyService;
+	protected IDebugCounterService debugCounterService;
+
+	protected OFMessageDamper messageDamper;
+
+	// for broadcast loop suppression
+	protected boolean broadcastCacheFeature = true;
+	public final int prime1 = 2633;  // for hash calculation
+	public final static int prime2 = 4357;  // for hash calculation
+	public TimedCache<Long> broadcastCache = new TimedCache<Long>(100, 5*1000);  // 5 seconds interval;
+
+	// flow-mod - for use in the cookie
+	public static final int FORWARDING_APP_ID = 2; // TODO: This must be managed
+	// by a global APP_ID class
+	static {
+		AppCookie.registerApp(FORWARDING_APP_ID, "Forwarding");
+	}
+	public static final U64 appCookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
+
+	// Comparator for sorting by SwitchCluster
+	public Comparator<SwitchPort> clusterIdComparator =
+			new Comparator<SwitchPort>() {
+		@Override
+		public int compare(SwitchPort d1, SwitchPort d2) {
+			DatapathId d1ClusterId = topologyService.getL2DomainId(d1.getSwitchDPID());
+			DatapathId d2ClusterId = topologyService.getL2DomainId(d2.getSwitchDPID());
+			return d1ClusterId.compareTo(d2ClusterId);
+		}
+	};
+
+	/**
+	 * init data structures
+	 *
+	 */
+	protected void init() {
+		messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
+				EnumSet.of(OFType.FLOW_MOD),
+				OFMESSAGE_DAMPER_TIMEOUT);
+
+	}
+
+	/**
+	 * Adds a listener for devicemanager and registers for PacketIns.
+	 */
+	protected void startUp() {
+		floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
+	}
+
+	/**
+	 * Returns the application name "forwarding".
+	 */
+	@Override
+	public String getName() {
+		return "forwarding";
+	}
+
+	/**
+	 * All subclasses must define this function if they want any specific
+	 * forwarding action
+	 *
+	 * @param sw
+	 *            Switch that the packet came in from
+	 * @param pi
+	 *            The packet that came in
+	 * @param decision
+	 *            Any decision made by a policy engine
+	 */
+	public abstract Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, 
+			IRoutingDecision decision, FloodlightContext cntx);
+
+	@Override
+	public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+		switch (msg.getType()) {
+		case PACKET_IN:
+			IRoutingDecision decision = null;
+			if (cntx != null) {
+				decision = RoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION);
+			}
+
+			return this.processPacketInMessage(sw, (OFPacketIn) msg, decision, cntx);
+		default:
+			break;
+		}
+		return Command.CONTINUE;
+	}
+
+	/**
+	 * Push routes from back to front
+	 * @param route Route to push
+	 * @param match OpenFlow fields to match on
+	 * @param srcSwPort Source switch port for the first hop
+	 * @param dstSwPort Destination switch port for final hop
+	 * @param cookie The cookie to set in each flow_mod
+	 * @param cntx The floodlight context
+	 * @param reqeustFlowRemovedNotifn if set to true then the switch would
+	 * send a flow mod removal notification when the flow mod expires
+	 * @param doFlush if set to true then the flow mod would be immediately
+	 *        written to the switch
+	 * @param flowModCommand flow mod. command to use, e.g. OFFlowMod.OFPFC_ADD,
+	 *        OFFlowMod.OFPFC_MODIFY etc.
+	 * @return srcSwitchIincluded True if the source switch is included in this route
+	 */
+	@LogMessageDocs({
+		@LogMessageDoc(level="WARN",
+				message="Unable to push route, switch at DPID {dpid} not available",
+				explanation="A switch along the calculated path for the " +
+						"flow has disconnected.",
+						recommendation=LogMessageDoc.CHECK_SWITCH),
+						@LogMessageDoc(level="ERROR",
+						message="Failure writing flow mod",
+						explanation="An I/O error occurred while writing a " +
+								"flow modification to a switch",
+								recommendation=LogMessageDoc.CHECK_SWITCH)
+	})
+	public boolean pushRoute(Route route, Match match, OFPacketIn pi,
+			DatapathId pinSwitch, U64 cookie, FloodlightContext cntx,
+			boolean reqeustFlowRemovedNotifn, boolean doFlush,
+			OFFlowModCommand flowModCommand) {
+
+		boolean srcSwitchIncluded = false;
+
+		List<NodePortTuple> switchPortList = route.getPath();
+
+		for (int indx = switchPortList.size() - 1; indx > 0; indx -= 2) {
+			// indx and indx-1 will always have the same switch DPID.
+			DatapathId switchDPID = switchPortList.get(indx).getNodeId();
+			IOFSwitch sw = switchService.getSwitch(switchDPID);
+
+			if (sw == null) {
+				if (log.isWarnEnabled()) {
+					log.warn("Unable to push route, switch at DPID {} " + "not available", switchDPID);
+				}
+				return srcSwitchIncluded;
+			}
+			
+			// need to build flow mod based on what type it is. Cannot set command later
+			OFFlowMod.Builder fmb;
+			switch (flowModCommand) {
+			case ADD:
+				fmb = sw.getOFFactory().buildFlowAdd();
+				break;
+			case DELETE:
+				fmb = sw.getOFFactory().buildFlowDelete();
+				break;
+			case DELETE_STRICT:
+				fmb = sw.getOFFactory().buildFlowDeleteStrict();
+				break;
+			case MODIFY:
+				fmb = sw.getOFFactory().buildFlowModify();
+				break;
+			default:
+				log.error("Could not decode OFFlowModCommand. Using MODIFY_STRICT. (Should another be used as the default?)");        
+			case MODIFY_STRICT:
+				fmb = sw.getOFFactory().buildFlowModifyStrict();
+				break;			
+			}
+			
+			OFActionOutput.Builder aob = sw.getOFFactory().actions().buildOutput();
+			List<OFAction> actions = new ArrayList<OFAction>();	
+			//Match.Builder mb = match.createBuilder();
+
+			// set input and output ports on the switch
+			OFPort outPort = switchPortList.get(indx).getPortId();
+			//OFPort inPort = switchPortList.get(indx - 1).getPortId();
+			//mb.setExact(MatchField.IN_PORT, inPort);
+			aob.setPort(outPort);
+			aob.setMaxLen(Integer.MAX_VALUE);
+			actions.add(aob.build());
+			
+			// compile
+			fmb.setMatch(match) //mb.build()
+			.setActions(actions)
+			.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
+			.setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+			.setBufferId(OFBufferId.NO_BUFFER)
+			.setCookie(cookie)
+			.setOutPort(outPort); // TODO @Ryan why does this need to be set in addition to the action???
+
+			try {
+				//TODO @Ryan counterStore.updatePktOutFMCounterStoreLocal(sw, fm);
+				if (log.isTraceEnabled()) {
+					log.trace("Pushing Route flowmod routeIndx={} " +
+							"sw={} inPort={} outPort={}",
+							new Object[] {indx,
+							sw,
+							fmb.getMatch().get(MatchField.IN_PORT),
+							outPort });
+				}
+				messageDamper.write(sw, fmb.build(), cntx);
+				if (doFlush) {
+					sw.flush();
+					//TODO @Ryan counterStore.updateFlush();
+				}
+
+				// Push the packet out the source switch
+				if (sw.getId().equals(pinSwitch)) {
+					// TODO: Instead of doing a packetOut here we could also
+					// send a flowMod with bufferId set....
+					pushPacket(sw, pi, false, outPort, cntx);
+					srcSwitchIncluded = true;
+				}
+			} catch (IOException e) {
+				log.error("Failure writing flow mod", e);
+			}
+		}
+
+		return srcSwitchIncluded;
+	}
+
+	/**
+	 * Pushes a packet-out to a switch. If bufferId != BUFFER_ID_NONE we
+	 * assume that the packetOut switch is the same as the packetIn switch
+	 * and we will use the bufferId. In this case the packet can be null
+	 * Caller needs to make sure that inPort and outPort differs
+	 * @param packet    packet data to send.
+	 * @param sw        switch from which packet-out is sent
+	 * @param bufferId  bufferId
+	 * @param inPort    input port
+	 * @param outPort   output port
+	 * @param cntx      context of the packet
+	 * @param flush     force to flush the packet.
+	 */
+	@LogMessageDocs({
+		@LogMessageDoc(level="ERROR",
+				message="BufferId is not and packet data is null. " +
+						"Cannot send packetOut. " +
+						"srcSwitch={dpid} inPort={port} outPort={port}",
+						explanation="The switch send a malformed packet-in." +
+								"The packet will be dropped",
+								recommendation=LogMessageDoc.REPORT_SWITCH_BUG),
+								@LogMessageDoc(level="ERROR",
+								message="Failure writing packet out",
+								explanation="An I/O error occurred while writing a " +
+										"packet out to a switch",
+										recommendation=LogMessageDoc.CHECK_SWITCH)
+	})
+
+	/**
+	 * Pushes a packet-out to a switch.  The assumption here is that
+	 * the packet-in was also generated from the same switch.  Thus, if the input
+	 * port of the packet-in and the outport are the same, the function will not
+	 * push the packet-out.
+	 * @param sw        switch that generated the packet-in, and from which packet-out is sent
+	 * @param pi        packet-in
+	 * @param useBufferId  if true, use the bufferId from the packet in and
+	 * do not add the packetIn's payload. If false set bufferId to
+	 * BUFFER_ID_NONE and use the packetIn's payload
+	 * @param outport   output port
+	 * @param cntx      context of the packet
+	 */
+	protected void pushPacket(IOFSwitch sw, OFPacketIn pi, boolean useBufferId,
+			OFPort outport, FloodlightContext cntx) {
+
+		if (pi == null) {
+			return;
+		}
+
+		// The assumption here is (sw) is the switch that generated the
+		// packet-in. If the input port is the same as output port, then
+		// the packet-out should be ignored.
+		if ((pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)).equals(outport)) {
+			if (log.isDebugEnabled()) {
+				log.debug("Attempting to do packet-out to the same " +
+						"interface as packet-in. Dropping packet. " +
+						" SrcSwitch={}, pi={}",
+						new Object[]{sw, pi});
+				return;
+			}
+		}
+
+		if (log.isTraceEnabled()) {
+			log.trace("PacketOut srcSwitch={} pi={}",
+					new Object[] {sw, pi});
+		}
+
+		OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
+		// set actions
+		List<OFAction> actions = new ArrayList<OFAction>();
+		actions.add(sw.getOFFactory().actions().output(outport, Integer.MAX_VALUE));
+		pob.setActions(actions);
+
+		if (useBufferId) {
+			pob.setBufferId(pi.getBufferId());
+		} else {
+			pob.setBufferId(OFBufferId.NO_BUFFER);
+		}
+
+		if (pob.getBufferId() == OFBufferId.NO_BUFFER) {
+			byte[] packetData = pi.getData();
+			pob.setData(packetData);
+		}
+
+		pob.setInPort((pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+
+		try {
+			//TODO @Ryan counterStore.updatePktOutFMCounterStoreLocal(sw, po);
+			messageDamper.write(sw, pob.build(), cntx);
+		} catch (IOException e) {
+			log.error("Failure writing packet out", e);
+		}
+	}
+
+
+	/**
+	 * Write packetout message to sw with output actions to one or more
+	 * output ports with inPort/outPorts passed in.
+	 * @param packetData
+	 * @param sw
+	 * @param inPort
+	 * @param ports
+	 * @param cntx
+	 */
+	public void packetOutMultiPort(byte[] packetData, IOFSwitch sw, 
+			OFPort inPort, Set<OFPort> outPorts, FloodlightContext cntx) {
+		//setting actions
+		List<OFAction> actions = new ArrayList<OFAction>();
+
+		Iterator<OFPort> j = outPorts.iterator();
+
+		while (j.hasNext()) {
+			actions.add(sw.getOFFactory().actions().output(j.next(), 0));
+		}
+
+		OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
+		pob.setActions(actions);
+
+		pob.setBufferId(OFBufferId.NO_BUFFER);
+		pob.setInPort(inPort);
+
+		pob.setData(packetData);
+
+		try {
+			//TODO @Ryan 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()});
+			}
+			messageDamper.write(sw, pob.build(), cntx);
+
+		} catch (IOException e) {
+			log.error("Failure writing packet out", e);
+		}
+	}
+
+	/**
+	 * @see packetOutMultiPort
+	 * Accepts a PacketIn instead of raw packet data. Note that the inPort
+	 * and switch can be different than the packet in switch/port
+	 */
+	public void packetOutMultiPort(OFPacketIn pi, IOFSwitch sw,
+			OFPort inPort, Set<OFPort> outPorts, FloodlightContext cntx) {
+		packetOutMultiPort(pi.getData(), sw, inPort, outPorts, cntx);
+	}
+
+	/**
+	 * @see packetOutMultiPort
+	 * Accepts an IPacket instead of raw packet data. Note that the inPort
+	 * and switch can be different than the packet in switch/port
+	 */
+	public void packetOutMultiPort(IPacket packet, IOFSwitch sw,
+			OFPort inPort, Set<OFPort> outPorts, FloodlightContext cntx) {
+		packetOutMultiPort(packet.serialize(), sw, inPort, outPorts, cntx);
+	}
+
+	@LogMessageDocs({
+		@LogMessageDoc(level="ERROR",
+				message="Failure writing deny flow mod",
+				explanation="An I/O error occurred while writing a " +
+						"deny flow mod to a switch",
+						recommendation=LogMessageDoc.CHECK_SWITCH)
+	})
+	public static boolean blockHost(IOFSwitchService switchService,
+			SwitchPort sw_tup, MacAddress host_mac, short hardTimeout, U64 cookie) {
+
+		if (sw_tup == null) {
+			return false;
+		}
+
+		IOFSwitch sw = switchService.getSwitch(sw_tup.getSwitchDPID());
+		if (sw == null) {
+			return false;
+		}
+
+		OFPort inputPort = sw_tup.getPort();
+		log.debug("blockHost sw={} port={} mac={}",
+				new Object[] { sw, sw_tup.getPort(), host_mac.getLong() });
+
+		// Create flow-mod based on packet-in and src-switch
+		OFFlowMod.Builder fmb = sw.getOFFactory().buildFlowAdd();
+
+		Match.Builder mb = sw.getOFFactory().buildMatch();
+		List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to drop
+		mb.setExact(MatchField.IN_PORT, inputPort);
+		if (host_mac.getLong() != -1L) {
+			mb.setExact(MatchField.ETH_SRC, host_mac);
+		}
+
+		fmb.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());
+		
+		return true;
+	}
+
+	@Override
+	public boolean isCallbackOrderingPrereq(OFType type, String name) {
+		return (type.equals(OFType.PACKET_IN) && (name.equals("topology") || name.equals("devicemanager")));
+	}
+
+	@Override
+	public boolean isCallbackOrderingPostreq(OFType type, String name) {
+		return false;
+	}
 
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java b/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
index ab09375486b9f61b2cfa98b83a5e9eeb483bd20b..bc9df880fd08a4a72f98d9104d09f7245edabfc0 100644
--- a/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
+++ b/src/main/java/net/floodlightcontroller/routing/IRoutingDecision.java
@@ -19,6 +19,8 @@ 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;
@@ -57,8 +59,8 @@ public interface IRoutingDecision {
     public void addDestinationDevice(IDevice d);
     public List<SwitchPort> getMulticastInterfaces();
     public void setMulticastInterfaces(List<SwitchPort> lspt);
-    public Integer getWildcards();
-    public void setWildcards(Integer wildcards);
+    public Match getMatch();
+    public void setMatch(Match match);
     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 a3d77a83ba6309c02c6f99c19d2523eab2ecfa3b..fde607b89cef1ca00a78e8867748c0c2f4c2c795 100644
--- a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
+++ b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
@@ -19,6 +19,10 @@ package net.floodlightcontroller.routing;
 
 import java.util.ArrayList;
 
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
+
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.routing.Route;
 
@@ -33,7 +37,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(long src, long dst, long cookie);
+    public Route getRoute(DatapathId src, DatapathId dst, U64 cookie);
 
     /**
      * Provides a route between src and dst, with option to allow or
@@ -43,7 +47,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(long src, long dst, long cookie, boolean tunnelEnabled);
+    public Route getRoute(DatapathId src, DatapathId dst, U64 cookie, boolean tunnelEnabled);
 
     /**
      * Provides a route between srcPort on src and dstPort on dst.
@@ -53,8 +57,7 @@ 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(long srcId, short srcPort,
-                             long dstId, short dstPort, long cookie);
+    public Route getRoute(DatapathId srcId, OFPort srcPort, DatapathId dstId, OFPort dstPort, U64 cookie);
 
     /**
      * Provides a route between srcPort on src and dstPort on dst.
@@ -65,21 +68,19 @@ public interface IRoutingService extends IFloodlightService {
      * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
      * @param tunnelEnabled boolean option.
      */
-    public Route getRoute(long srcId, short srcPort,
-                             long dstId, short dstPort, long cookie,
-                             boolean tunnelEnabled);
+    public Route getRoute(DatapathId srcId, OFPort srcPort, DatapathId dstId, OFPort dstPort, U64 cookie, boolean tunnelEnabled);
 
     /** return all routes, if available */
-    public ArrayList<Route> getRoutes(long longSrcDpid, long longDstDpid, boolean tunnelEnabled);
+    public ArrayList<Route> getRoutes(DatapathId longSrcDpid, DatapathId longDstDpid, boolean tunnelEnabled);
 
     /** Check if a route exists between src and dst, including tunnel links
      *  in the path.
      */
-    public boolean routeExists(long src, long dst);
+    public boolean routeExists(DatapathId src, DatapathId 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(long src, long dst, boolean tunnelEnabled);
+    public boolean routeExists(DatapathId src, DatapathId dst, boolean tunnelEnabled);
 
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/Link.java b/src/main/java/net/floodlightcontroller/routing/Link.java
index 561ae04c09ba4b4d3849763da46796dff4c03f95..a2f125f5a5b2cd73c9ce6bfaa65e4b56e87d6ff6 100755
--- a/src/main/java/net/floodlightcontroller/routing/Link.java
+++ b/src/main/java/net/floodlightcontroller/routing/Link.java
@@ -18,34 +18,28 @@
 package net.floodlightcontroller.routing;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-import org.openflow.util.HexString;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
 
 public class Link implements Comparable<Link> {
     @JsonProperty("src-switch")
-    private long src;
+    private DatapathId src;
     @JsonProperty("src-port")
-    private short srcPort;
+    private OFPort srcPort;
     @JsonProperty("dst-switch")
-    private long dst;
+    private DatapathId dst;
     @JsonProperty("dst-port")
-    private short dstPort;
+    private OFPort dstPort;
 
 
-    public Link(long srcId, short srcPort, long dstId, short dstPort) {
+    public Link(DatapathId srcId, OFPort srcPort, DatapathId dstId, OFPort 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
@@ -54,35 +48,35 @@ public class Link implements Comparable<Link> {
         super();
     }
 
-    public long getSrc() {
+    public DatapathId getSrc() {
         return src;
     }
 
-    public short getSrcPort() {
+    public OFPort getSrcPort() {
         return srcPort;
     }
 
-    public long getDst() {
+    public DatapathId getDst() {
         return dst;
     }
 
-    public short getDstPort() {
+    public OFPort getDstPort() {
         return dstPort;
     }
 
-    public void setSrc(long src) {
+    public void setSrc(DatapathId src) {
         this.src = src;
     }
 
-    public void setSrcPort(short srcPort) {
+    public void setSrcPort(OFPort srcPort) {
         this.srcPort = srcPort;
     }
 
-    public void setDst(long dst) {
+    public void setDst(DatapathId dst) {
         this.dst = dst;
     }
 
-    public void setDstPort(short dstPort) {
+    public void setDstPort(OFPort dstPort) {
         this.dstPort = dstPort;
     }
 
@@ -90,10 +84,10 @@ public class Link implements Comparable<Link> {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + (int) (dst ^ (dst >>> 32));
-        result = prime * result + dstPort;
-        result = prime * result + (int) (src ^ (src >>> 32));
-        result = prime * result + srcPort;
+        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();
         return result;
     }
 
@@ -120,35 +114,36 @@ public class Link implements Comparable<Link> {
 
     @Override
     public String toString() {
-        return "Link [src=" + HexString.toHexString(this.src) 
+        return "Link [src=" + this.src.toString() 
                 + " outPort="
-                + (srcPort & 0xffff)
-                + ", dst=" + HexString.toHexString(this.dst)
+                + srcPort.toString()
+                + ", dst=" + this.dst.toString()
                 + ", inPort="
-                + (dstPort & 0xffff)
+                + dstPort.toString()
                 + "]";
     }
     
+    //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 (HexString.toHexString(this.src) + "|" +
-    			(this.srcPort & 0xffff) + "|" +
-    			HexString.toHexString(this.dst) + "|" +
-    		    (this.dstPort & 0xffff) );
+    	return (this.src.toString() + "|" +
+    			this.srcPort.toString() + "|" +
+    			this.dst.toString() + "|" +
+    		    this.dstPort.toString());
     }
 
     @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() - a.getSrc());
+            return (int) (this.getSrc().getLong() - a.getSrc().getLong());
         
         if (this.getSrcPort() != a.getSrcPort())
-            return (int) (this.getSrc() - a.getSrc());
+            return (int) (this.getSrc().getLong() - a.getSrc().getLong());
         
         if (this.getDst() != a.getDst())
-            return (int) (this.getDst() - a.getDst());
+            return (int) (this.getDst().getLong() - a.getDst().getLong());
         
-        return this.getDstPort() - a.getDstPort();
+        return this.getDstPort().getPortNumber() - a.getDstPort().getPortNumber();
     }
 }
 
diff --git a/src/main/java/net/floodlightcontroller/routing/Route.java b/src/main/java/net/floodlightcontroller/routing/Route.java
index da00d50b7b82a3d3498b1523543a8558abbd579a..f41a9aaf1e159249e4eb831da30cf80abe993ad5 100755
--- a/src/main/java/net/floodlightcontroller/routing/Route.java
+++ b/src/main/java/net/floodlightcontroller/routing/Route.java
@@ -20,6 +20,8 @@ package net.floodlightcontroller.routing;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.projectfloodlight.openflow.types.DatapathId;
+
 import net.floodlightcontroller.topology.NodePortTuple;
 
 /**
@@ -39,7 +41,7 @@ public class Route implements Comparable<Route> {
         this.routeCount = 0; // useful if multipath routing available
     }
 
-    public Route(Long src, Long dst) {
+    public Route(DatapathId src, DatapathId 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 511db735969aa849d619783cdd88229d1922b27a..dce125111fc4baaf20342c07d5a991a9a8539b57 100755
--- a/src/main/java/net/floodlightcontroller/routing/RouteId.java
+++ b/src/main/java/net/floodlightcontroller/routing/RouteId.java
@@ -17,7 +17,8 @@
 
 package net.floodlightcontroller.routing;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.U64;
 
 /**
  * Stores the endpoints of a route, in this case datapath ids
@@ -25,46 +26,46 @@ import org.openflow.util.HexString;
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
 public class RouteId implements Cloneable, Comparable<RouteId> {
-    protected Long src;
-    protected Long dst;
-    protected long cookie;
+    protected DatapathId src;
+    protected DatapathId dst;
+    protected U64 cookie;
 
-    public RouteId(Long src, Long dst) {
+    public RouteId(DatapathId src, DatapathId dst) {
         super();
         this.src = src;
         this.dst = dst;
-        this.cookie = 0;
+        this.cookie = U64.of(0);
     }
 
-    public RouteId(Long src, Long dst, long cookie) {
+    public RouteId(DatapathId src, DatapathId dst, U64 cookie) {
         super();
         this.src = src;
         this.dst = dst;
         this.cookie = cookie;
     }
 
-    public Long getSrc() {
+    public DatapathId getSrc() {
         return src;
     }
 
-    public void setSrc(Long src) {
+    public void setSrc(DatapathId src) {
         this.src = src;
     }
 
-    public Long getDst() {
+    public DatapathId getDst() {
         return dst;
     }
 
-    public void setDst(Long dst) {
+    public void setDst(DatapathId dst) {
         this.dst = dst;
     }
 
-    public long getCookie() {
+    public U64 getCookie() {
         return cookie;
     }
 
     public void setCookie(int cookie) {
-        this.cookie = cookie;
+        this.cookie = U64.of(cookie);
     }
 
     @Override
@@ -73,7 +74,7 @@ public class RouteId implements Cloneable, Comparable<RouteId> {
         Long result = new Long(1);
         result = prime * result + ((dst == null) ? 0 : dst.hashCode());
         result = prime * result + ((src == null) ? 0 : src.hashCode());
-        result = prime * result + cookie; 
+        result = prime * result + cookie.getValue(); 
         // To cope with long cookie, use Long to compute hash then use Long's 
         // built-in hash to produce int hash code
         return result.hashCode(); 
@@ -103,8 +104,8 @@ public class RouteId implements Cloneable, Comparable<RouteId> {
 
     @Override
     public String toString() {
-        return "RouteId [src=" + HexString.toHexString(this.src) + " dst="
-                + HexString.toHexString(this.dst) + "]";
+        return "RouteId [src=" + this.src.toString() + " dst="
+                + this.dst.toString() + "]";
     }
 
     @Override
diff --git a/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java b/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java
index aa4b3dde823ab75a38671e53767294d1964012f3..0e1935cab3c31499821845635219598d79b5e2c5 100644
--- a/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java
+++ b/src/main/java/net/floodlightcontroller/routing/RoutingDecision.java
@@ -20,6 +20,10 @@ 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;
@@ -28,25 +32,23 @@ import net.floodlightcontroller.devicemanager.SwitchPort;
 public class RoutingDecision implements IRoutingDecision {
 
     protected RoutingAction action;
-    protected Integer wildcards;
+    protected Match match;
     protected short hardTimeout;
     protected SwitchPort srcPort;
     protected IDevice srcDevice;
     protected List<IDevice> destDevices;
     protected List<SwitchPort> broadcastIntertfaces;
 
-    public RoutingDecision(long swDipd,
-                                  short inPort,
+    public RoutingDecision(DatapathId swDipd,
+                                  OFPort inPort,
                                   IDevice srcDevice,
                                   RoutingAction action) {
         this.srcPort = new SwitchPort(swDipd, inPort);
         this.srcDevice = srcDevice;
-        this.destDevices = 
-                Collections.synchronizedList(new ArrayList<IDevice>());
-        this.broadcastIntertfaces = 
-                Collections.synchronizedList(new ArrayList<SwitchPort>());
+        this.destDevices = Collections.synchronizedList(new ArrayList<IDevice>());
+        this.broadcastIntertfaces = Collections.synchronizedList(new ArrayList<SwitchPort>());
         this.action = action;
-        this.wildcards = null;
+        this.match = null;
         this.hardTimeout = ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT;
     }
     
@@ -93,13 +95,13 @@ public class RoutingDecision implements IRoutingDecision {
     }
     
     @Override
-    public Integer getWildcards() {
-        return this.wildcards;
+    public Match getMatch() {
+        return this.match;
     }
     
     @Override
-    public void setWildcards(Integer wildcards) {
-        this.wildcards = wildcards;
+    public void setMatch(Match match) {
+        this.match = match;
     }
    
     @Override
@@ -120,6 +122,6 @@ public class RoutingDecision implements IRoutingDecision {
     public String toString() {
         return "action " + action +
                " wildcard " +
-               ((wildcards == null) ? null : "0x"+Integer.toHexString(wildcards.intValue()));
+               ((match == null) ? null : match.toString());
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java b/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java
index a900b5b34863bfa0a83ad2d9f61251f00123cdd1..22b60197be03a9dbd2063552c78b121de6297620 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java
@@ -18,7 +18,8 @@ package net.floodlightcontroller.staticflowentry;
 
 import java.util.Map;
 
-import org.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.types.DatapathId;
 
 import net.floodlightcontroller.core.module.IFloodlightService;
 
@@ -29,7 +30,7 @@ public interface IStaticFlowEntryPusherService extends IFloodlightService {
      * @param fm The flow to push.
      * @param swDpid The switch DPID to push it to, in 00:00:00:00:00:00:00:01 notation.
      */
-    public void addFlow(String name, OFFlowMod fm, String swDpid);
+    public void addFlow(String name, OFFlowMod fm, DatapathId swDpid);
     
     /**
      * Deletes a static flow
@@ -41,7 +42,7 @@ public interface IStaticFlowEntryPusherService extends IFloodlightService {
      * Deletes all static flows for a practicular switch
      * @param dpid The DPID of the switch to delete flows for.
      */
-    public void deleteFlowsForSwitch(long dpid);
+    public void deleteFlowsForSwitch(DatapathId dpid);
     
     /**
      * Deletes all flows.
@@ -56,5 +57,6 @@ public interface IStaticFlowEntryPusherService extends IFloodlightService {
     /**
      * Gets a list of flows by switch
      */
-    public Map<String, OFFlowMod> getFlows(String dpid);
+    public Map<String, OFFlowMod> getFlows(DatapathId dpid);
+
 }
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java
index 42329e5b4490da20f86c6af7182e93321f49470c..72d52bd49d05bd64f29d382519ad0f867cad698f 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java
@@ -17,45 +17,28 @@
 package net.floodlightcontroller.staticflowentry;
 
 import java.io.IOException;
-import java.util.Arrays;
 import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.Iterator;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import net.floodlightcontroller.core.annotations.LogMessageCategory;
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
 import net.floodlightcontroller.core.util.AppCookie;
-import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.util.ActionUtils;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 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.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFPort;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionDataLayerDestination;
-import org.openflow.protocol.action.OFActionDataLayerSource;
-import org.openflow.protocol.action.OFActionEnqueue;
-import org.openflow.protocol.action.OFActionNetworkLayerDestination;
-import org.openflow.protocol.action.OFActionNetworkLayerSource;
-import org.openflow.protocol.action.OFActionNetworkTypeOfService;
-import org.openflow.protocol.action.OFActionOutput;
-import org.openflow.protocol.action.OFActionStripVirtualLan;
-import org.openflow.protocol.action.OFActionTransportLayerDestination;
-import org.openflow.protocol.action.OFActionTransportLayerSource;
-import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
-import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
-import org.openflow.util.HexString;
+
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
 
 /**
  * Represents static flow entries to be maintained by the controller on the 
@@ -63,785 +46,364 @@ import org.openflow.util.HexString;
  */
 @LogMessageCategory("Static Flow Pusher")
 public class StaticFlowEntries {
-    protected static Logger log = LoggerFactory.getLogger(StaticFlowEntries.class);
-    
-    private static class SubActionStruct {
-        OFAction action;
-        int      len;
-    }
-    
-    private static byte[] zeroMac = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
-    
-    /**
-     * This function generates a random hash for the bottom half of the cookie
-     * 
-     * @param fm
-     * @param userCookie
-     * @param name
-     * @return A cookie that encodes the application ID and a hash
-     */
-    public static long computeEntryCookie(OFFlowMod fm, int userCookie, String name) {
-        // flow-specific hash is next 20 bits LOOK! who knows if this 
-        int prime = 211;
-        int flowHash = 2311;
-        for (int i=0; i < name.length(); i++)
-            flowHash = flowHash * prime + (int)name.charAt(i);
-
-        return AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, flowHash);
-    }
-    
-    /**
-     * Sets defaults for an OFFlowMod
-     * @param fm The OFFlowMod to set defaults for
-     * @param entryName The name of the entry. Used to compute the cookie.
-     */
-    public static void initDefaultFlowMod(OFFlowMod fm, String entryName) {
-        fm.setIdleTimeout((short) 0);   // infinite
-        fm.setHardTimeout((short) 0);   // infinite
-        fm.setBufferId(OFPacketOut.BUFFER_ID_NONE);
-        fm.setCommand((short) 0);
-        fm.setFlags((short) 0);
-        fm.setOutPort(OFPort.OFPP_NONE.getValue());
-        fm.setCookie(computeEntryCookie(fm, 0, entryName));  
-        fm.setPriority(Short.MAX_VALUE);
-    }
-    
-    /**
-     * Gets the entry name of a flow mod
-     * @param fmJson The OFFlowMod in a JSON representation
-     * @return The name of the OFFlowMod, null if not found
-     * @throws IOException If there was an error parsing the JSON
-     */
-    public static String getEntryNameFromJson(String fmJson) throws IOException{
-        MappingJsonFactory f = new MappingJsonFactory();
-        JsonParser jp;
-        
-        try {
-            jp = f.createJsonParser(fmJson);
-        } catch (JsonParseException e) {
-            throw new IOException(e);
-        }
-        
-        jp.nextToken();
-        if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
-            throw new IOException("Expected START_OBJECT");
-        }
-        
-        while (jp.nextToken() != JsonToken.END_OBJECT) {
-            if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
-                throw new IOException("Expected FIELD_NAME");
-            }
-            
-            String n = jp.getCurrentName();
-            jp.nextToken();
-            if (jp.getText().equals("")) 
-                continue;
-            
-            if (n == "name")
-                return jp.getText();
-        }
-        
-        return null;
-    }
-    
-    /**
-     * Parses an OFFlowMod (and it's inner OFMatch) to the storage entry format.
-     * @param fm The FlowMod to parse
-     * @param sw The switch the FlowMod is going to be installed on
-     * @param name The name of this static flow entry
-     * @return A Map representation of the storage entry 
-     */
-    public static Map<String, Object> flowModToStorageEntry(OFFlowMod fm, String sw, String name) {
-        Map<String, Object> entry = new HashMap<String, Object>();
-        OFMatch match = fm.getMatch();
-        entry.put(StaticFlowEntryPusher.COLUMN_NAME, name);
-        entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, sw);
-        entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true));
-        entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Short.toString(fm.getPriority()));
-        entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, Integer.toString(match.getWildcards()));
-        
-        if ((fm.getActions() != null) && (fm.getActions().size() > 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, StaticFlowEntries.flowModActionsToString(fm.getActions()));
-        
-        if (match.getInputPort() != 0)
-        	entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, Short.toString(match.getInputPort()));
-        
-        if (!Arrays.equals(match.getDataLayerSource(), zeroMac))
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, HexString.toHexString(match.getDataLayerSource()));
-
-        if (!Arrays.equals(match.getDataLayerDestination(), zeroMac))
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, HexString.toHexString(match.getDataLayerDestination()));
-        
-        if (match.getDataLayerVirtualLan() != -1)
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, Short.toString(match.getDataLayerVirtualLan()));
-        
-        if (match.getDataLayerVirtualLanPriorityCodePoint() != 0)
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, Short.toString(match.getDataLayerVirtualLanPriorityCodePoint()));
-        
-        if (match.getDataLayerType() != 0)
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, Short.toString(match.getDataLayerType()));
-        
-        if (match.getNetworkTypeOfService() != 0)
-        	entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, Short.toString(match.getNetworkTypeOfService()));
-        
-        if (match.getNetworkProtocol() != 0)
-        	entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Short.toString(match.getNetworkProtocol()));
-        
-        if (match.getNetworkSource() != 0)
-        	entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, IPv4.fromIPv4Address(match.getNetworkSource()));
-        
-        if (match.getNetworkDestination() != 0)
-        	entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, IPv4.fromIPv4Address(match.getNetworkDestination()));
-        
-        if (match.getTransportSource() != 0)
-        	entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, Short.toString(match.getTransportSource()));
-        
-        if (match.getTransportDestination() != 0)
-        	entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, Short.toString(match.getTransportDestination()));
-        
-        return entry;
-    }
-    
-    /**
-     * Returns a String representation of all the openflow actions.
-     * @param fmActions A list of OFActions to encode into one string
-     * @return A string of the actions encoded for our database
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Could not decode action {action}",
-            explanation="A static flow entry contained an invalid action",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    private static String flowModActionsToString(List<OFAction> fmActions) {
-        StringBuilder sb = new StringBuilder();
-        for (OFAction a : fmActions) {
-            if (sb.length() > 0) {
-                sb.append(',');
-            }
-            switch(a.getType()) {
-                case OUTPUT:
-                    sb.append("output=" + Short.toString(((OFActionOutput)a).getPort()));
-                    break;
-                case OPAQUE_ENQUEUE:
-                    int queue = ((OFActionEnqueue)a).getQueueId();
-                    short port = ((OFActionEnqueue)a).getPort();
-                    sb.append("enqueue=" + Short.toString(port) + ":0x" + String.format("%02x", queue));
-                    break;
-                case STRIP_VLAN:
-                    sb.append("strip-vlan");
-                    break;
-                case SET_VLAN_ID:
-                    sb.append("set-vlan-id=" + 
-                        Short.toString(((OFActionVirtualLanIdentifier)a).getVirtualLanIdentifier()));
-                    break;
-                case SET_VLAN_PCP:
-                    sb.append("set-vlan-priority=" +
-                        Byte.toString(((OFActionVirtualLanPriorityCodePoint)a).getVirtualLanPriorityCodePoint()));
-                    break;
-                case SET_DL_SRC:
-                    sb.append("set-src-mac=" + 
-                        HexString.toHexString(((OFActionDataLayerSource)a).getDataLayerAddress()));
-                    break;
-                case SET_DL_DST:
-                    sb.append("set-dst-mac=" + 
-                        HexString.toHexString(((OFActionDataLayerDestination)a).getDataLayerAddress()));
-                    break;
-                case SET_NW_TOS:
-                    sb.append("set-tos-bits=" +
-                        Byte.toString(((OFActionNetworkTypeOfService)a).getNetworkTypeOfService()));
-                    break;
-                case SET_NW_SRC:
-                    sb.append("set-src-ip=" +
-                        IPv4.fromIPv4Address(((OFActionNetworkLayerSource)a).getNetworkAddress()));
-                    break;
-                case SET_NW_DST:
-                    sb.append("set-dst-ip=" +
-                        IPv4.fromIPv4Address(((OFActionNetworkLayerDestination)a).getNetworkAddress()));
-                    break;
-                case SET_TP_SRC:
-                    sb.append("set-src-port=" +
-                        Short.toString(((OFActionTransportLayerSource)a).getTransportPort()));
-                    break;
-                case SET_TP_DST:
-                    sb.append("set-dst-port=" +
-                        Short.toString(((OFActionTransportLayerDestination)a).getTransportPort()));
-                    break;
-                default:
-                    log.error("Could not decode action: {}", a);
-                    break;
-            }
-                
-        }
-        return sb.toString();
-    }
-    
-    /**
-     * Turns a JSON formatted Static Flow Pusher string into a storage entry
-     * Expects a string in JSON along the lines of:
-     *        {
-     *            "switch":       "AA:BB:CC:DD:EE:FF:00:11",
-     *            "name":         "flow-mod-1",
-     *            "cookie":       "0",
-     *            "priority":     "32768",
-     *            "ingress-port": "1",
-     *            "actions":      "output=2",
-     *        }
-     * @param fmJson The JSON formatted static flow pusher entry
-     * @return The map of the storage entry
-     * @throws IOException If there was an error parsing the JSON
-     */
-    public static Map<String, Object> jsonToStorageEntry(String fmJson) throws IOException {
-        Map<String, Object> entry = new HashMap<String, Object>();
-        MappingJsonFactory f = new MappingJsonFactory();
-        JsonParser jp;
-        
-        try {
-            jp = f.createJsonParser(fmJson);
-        } catch (JsonParseException e) {
-            throw new IOException(e);
-        }
-        
-        jp.nextToken();
-        if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
-            throw new IOException("Expected START_OBJECT");
-        }
-        
-        while (jp.nextToken() != JsonToken.END_OBJECT) {
-            if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
-                throw new IOException("Expected FIELD_NAME");
-            }
-            
-            String n = jp.getCurrentName();
-            jp.nextToken();
-            if (jp.getText().equals("")) 
-                continue;
-            
-            if (n == "name")
-                entry.put(StaticFlowEntryPusher.COLUMN_NAME, jp.getText());
-            else if (n == "switch")
-                entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, jp.getText());
-            else if (n == "actions")
-                entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, jp.getText());
-            else if (n == "priority")
-                entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, jp.getText());
-            else if (n == "active")
-                entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, jp.getText());
-            else if (n == "wildcards")
-                entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, jp.getText());
-            else if (n == "ingress-port")
-                entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, jp.getText());
-            else if (n == "src-mac")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, jp.getText());
-            else if (n == "dst-mac")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, jp.getText());
-            else if (n == "vlan-id")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, jp.getText());
-            else if (n == "vlan-priority")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, jp.getText());
-            else if (n == "ether-type")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, jp.getText());
-            else if (n == "tos-bits")
-                entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, jp.getText());
-            else if (n == "protocol")
-                entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, jp.getText());
-            else if (n == "src-ip")
-                entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, jp.getText());
-            else if (n == "dst-ip")
-                entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, jp.getText());
-            else if (n == "src-port")
-                entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, jp.getText());
-            else if (n == "dst-port")
-                entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, jp.getText());
-        }
-        
-        return entry;
-    }
-    
-    /**
-     * Parses OFFlowMod actions from strings.
-     * @param flowMod The OFFlowMod to set the actions for
-     * @param actionstr The string containing all the actions
-     * @param log A logger to log for errors.
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Unexpected action '{action}', '{subaction}'",
-            explanation="A static flow entry contained an invalid action",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    public static void parseActionString(OFFlowMod flowMod, String actionstr, Logger log) {
-        List<OFAction> actions = new LinkedList<OFAction>();
-        int actionsLength = 0;
-        if (actionstr != null) {
-            actionstr = actionstr.toLowerCase();
-            for (String subaction : actionstr.split(",")) {
-                String action = subaction.split("[=:]")[0];
-                SubActionStruct subaction_struct = null;
-                
-                if (action.equals("output")) {
-                    subaction_struct = StaticFlowEntries.decode_output(subaction, log);
-                }
-                else if (action.equals("enqueue")) {
-                    subaction_struct = decode_enqueue(subaction, log);
-                }
-                else if (action.equals("strip-vlan")) {
-                    subaction_struct = decode_strip_vlan(subaction, log);
-                }
-                else if (action.equals("set-vlan-id")) {
-                    subaction_struct = decode_set_vlan_id(subaction, log);
-                }
-                else if (action.equals("set-vlan-priority")) {
-                    subaction_struct = decode_set_vlan_priority(subaction, log);
-                }
-                else if (action.equals("set-src-mac")) {
-                    subaction_struct = decode_set_src_mac(subaction, log);
-                }
-                else if (action.equals("set-dst-mac")) {
-                    subaction_struct = decode_set_dst_mac(subaction, log);
-                }
-                else if (action.equals("set-tos-bits")) {
-                    subaction_struct = decode_set_tos_bits(subaction, log);
-                }
-                else if (action.equals("set-src-ip")) {
-                    subaction_struct = decode_set_src_ip(subaction, log);
-                }
-                else if (action.equals("set-dst-ip")) {
-                    subaction_struct = decode_set_dst_ip(subaction, log);
-                }
-                else if (action.equals("set-src-port")) {
-                    subaction_struct = decode_set_src_port(subaction, log);
-                }
-                else if (action.equals("set-dst-port")) {
-                    subaction_struct = decode_set_dst_port(subaction, log);
-                }
-                else {
-                    log.error("Unexpected action '{}', '{}'", action, subaction);
-                }
-                
-                if (subaction_struct != null) {
-                    actions.add(subaction_struct.action);
-                    actionsLength += subaction_struct.len;
-                }
-            }
-        }
-        log.debug("action {}", actions);
-        
-        flowMod.setActions(actions);
-        flowMod.setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLength);
-    } 
-    
-    @LogMessageDoc(level="ERROR",
-            message="Invalid subaction: '{subaction}'",
-            explanation="A static flow entry contained an invalid subaction",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    private static SubActionStruct decode_output(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n;
-        
-        n = Pattern.compile("output=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(subaction);
-        if (n.matches()) {
-            OFActionOutput action = new OFActionOutput();
-            action.setMaxLength(Short.MAX_VALUE);
-            short port = OFPort.OFPP_NONE.getValue();
-            if (n.group(1) != null) {
-                try {
-                    port = get_short(n.group(1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid port in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-            else if (n.group(2) != null)
-                port = OFPort.OFPP_ALL.getValue();
-            else if (n.group(3) != null)
-                port = OFPort.OFPP_CONTROLLER.getValue();
-            else if (n.group(4) != null)
-                port = OFPort.OFPP_LOCAL.getValue();
-            else if (n.group(5) != null)
-                port = OFPort.OFPP_IN_PORT.getValue();
-            else if (n.group(6) != null)
-                port = OFPort.OFPP_NORMAL.getValue();
-            else if (n.group(7) != null)
-                port = OFPort.OFPP_FLOOD.getValue();
-            action.setPort(port);
-            log.debug("action {}", action);
-            
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionOutput.MINIMUM_LENGTH;
-        }
-        else {
-            log.error("Invalid subaction: '{}'", subaction);
-            return null;
-        }
-        
-        return sa;
-    }
-    
-    private static SubActionStruct decode_enqueue(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n;
-        
-        n = Pattern.compile("enqueue=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(subaction);
-        if (n.matches()) {
-            short portnum = 0;
-            if (n.group(1) != null) {
-                try {
-                    portnum = get_short(n.group(1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid port-num in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-
-            int queueid = 0;
-            if (n.group(2) != null) {
-                try {
-                    queueid = get_int(n.group(2));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid queue-id in: '{}' (error ignored)", subaction);
-                    return null;
-               }
-            }
-            
-            OFActionEnqueue action = new OFActionEnqueue();
-            action.setPort(portnum);
-            action.setQueueId(queueid);
-            log.debug("action {}", action);
-            
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionEnqueue.MINIMUM_LENGTH;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-        
-        return sa;
-    }
-    
-    private static SubActionStruct decode_strip_vlan(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("strip-vlan").matcher(subaction);
-        
-        if (n.matches()) {
-            OFActionStripVirtualLan action = new OFActionStripVirtualLan();
-            log.debug("action {}", action);
-            
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionStripVirtualLan.MINIMUM_LENGTH;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_vlan_id(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction);
-        
-        if (n.matches()) {            
-            if (n.group(1) != null) {
-                try {
-                    short vlanid = get_short(n.group(1));
-                    OFActionVirtualLanIdentifier action = new OFActionVirtualLanIdentifier();
-                    action.setVirtualLanIdentifier(vlanid);
-                    log.debug("  action {}", action);
-
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionVirtualLanIdentifier.MINIMUM_LENGTH;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid VLAN in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }          
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_vlan_priority(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction); 
-        
-        if (n.matches()) {            
-            if (n.group(1) != null) {
-                try {
-                    byte prior = get_byte(n.group(1));
-                    OFActionVirtualLanPriorityCodePoint action = new OFActionVirtualLanPriorityCodePoint();
-                    action.setVirtualLanPriorityCodePoint(prior);
-                    log.debug("  action {}", action);
-                    
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionVirtualLanPriorityCodePoint.MINIMUM_LENGTH;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid VLAN priority in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_src_mac(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); 
-
-        if (n.matches()) {
-            byte[] macaddr = get_mac_addr(n, subaction, log);
-            if (macaddr != null) {
-                OFActionDataLayerSource action = new OFActionDataLayerSource();
-                action.setDataLayerAddress(macaddr);
-                log.debug("action {}", action);
-
-                sa = new SubActionStruct();
-                sa.action = action;
-                sa.len = OFActionDataLayerSource.MINIMUM_LENGTH;
-            }            
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_mac(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
-        
-        if (n.matches()) {
-            byte[] macaddr = get_mac_addr(n, subaction, log);            
-            if (macaddr != null) {
-                OFActionDataLayerDestination action = new OFActionDataLayerDestination();
-                action.setDataLayerAddress(macaddr);
-                log.debug("  action {}", action);
-                
-                sa = new SubActionStruct();
-                sa.action = action;
-                sa.len = OFActionDataLayerDestination.MINIMUM_LENGTH;
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_tos_bits(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction); 
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    byte tosbits = get_byte(n.group(1));
-                    OFActionNetworkTypeOfService action = new OFActionNetworkTypeOfService();
-                    action.setNetworkTypeOfService(tosbits);
-                    log.debug("  action {}", action);
-                    
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionNetworkTypeOfService.MINIMUM_LENGTH;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid dst-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_src_ip(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
-
-        if (n.matches()) {
-            int ipaddr = get_ip_addr(n, subaction, log);
-            OFActionNetworkLayerSource action = new OFActionNetworkLayerSource();
-            action.setNetworkAddress(ipaddr);
-            log.debug("  action {}", action);
-
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionNetworkLayerSource.MINIMUM_LENGTH;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_ip(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
-
-        if (n.matches()) {
-            int ipaddr = get_ip_addr(n, subaction, log);
-            OFActionNetworkLayerDestination action = new OFActionNetworkLayerDestination();
-            action.setNetworkAddress(ipaddr);
-            log.debug("action {}", action);
- 
-            sa = new SubActionStruct();
-            sa.action = action;
-            sa.len = OFActionNetworkLayerDestination.MINIMUM_LENGTH;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_src_port(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction); 
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    short portnum = get_short(n.group(1));
-                    OFActionTransportLayerSource action = new OFActionTransportLayerSource();
-                    action.setTransportPort(portnum);
-                    log.debug("action {}", action);
-                    
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionTransportLayerSource.MINIMUM_LENGTH;;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_port(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction);
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    short portnum = get_short(n.group(1));
-                    OFActionTransportLayerDestination action = new OFActionTransportLayerDestination();
-                    action.setTransportPort(portnum);
-                    log.debug("action {}", action);
-                    
-                    sa = new SubActionStruct();
-                    sa.action = action;
-                    sa.len = OFActionTransportLayerDestination.MINIMUM_LENGTH;;
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid dst-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static byte[] get_mac_addr(Matcher n, String subaction, Logger log) {
-        byte[] macaddr = new byte[6];
-        
-        for (int i=0; i<6; i++) {
-            if (n.group(i+1) != null) {
-                try {
-                    macaddr[i] = get_byte("0x" + n.group(i+1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-mac in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-            else { 
-                log.debug("Invalid src-mac in: '{}' (null, error ignored)", subaction);
-                return null;
-            }
-        }
-        
-        return macaddr;
-    }
-    
-    private static int get_ip_addr(Matcher n, String subaction, Logger log) {
-        int ipaddr = 0;
-
-        for (int i=0; i<4; i++) {
-            if (n.group(i+1) != null) {
-                try {
-                    ipaddr = ipaddr<<8;
-                    ipaddr = ipaddr | get_int(n.group(i+1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-ip in: '{}' (error ignored)", subaction);
-                    return 0;
-                }
-            }
-            else {
-                log.debug("Invalid src-ip in: '{}' (null, error ignored)", subaction);
-                return 0;
-            }
-        }
-        
-        return ipaddr;
-    }
-    
-    // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static int get_int(String str) {
-        return Integer.decode(str);
-    }
-   
-    // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static short get_short(String str) {
-        return (short)(int)Integer.decode(str);
-    }
-   
-    // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static byte get_byte(String str) {
-        return Integer.decode(str).byteValue();
-    }
-
+	protected static Logger log = LoggerFactory.getLogger(StaticFlowEntries.class);
+	private static final int INFINITE_TIMEOUT = 0;
+
+	/**
+	 * This function generates a random hash for the bottom half of the cookie
+	 * 
+	 * @param fm
+	 * @param userCookie
+	 * @param name
+	 * @return A cookie that encodes the application ID and a hash
+	 */
+	public static U64 computeEntryCookie(int userCookie, String name) {
+		// flow-specific hash is next 20 bits LOOK! who knows if this 
+		int prime = 211;
+		int flowHash = 2311;
+		for (int i=0; i < name.length(); i++) {
+			flowHash = flowHash * prime + (int)name.charAt(i);
+		}
+
+		return AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, flowHash);
+	}
+
+	/**
+	 * Sets defaults for an OFFlowMod used in the StaticFlowEntryPusher
+	 * @param fm The OFFlowMod to set defaults for
+	 * @param entryName The name of the entry. Used to compute the cookie.
+	 */
+	public static void initDefaultFlowMod(OFFlowMod.Builder fmb, String entryName) {
+		fmb.setIdleTimeout(INFINITE_TIMEOUT) // not setting these would also work
+		.setHardTimeout(INFINITE_TIMEOUT)
+		.setBufferId(OFBufferId.NO_BUFFER)
+		.setOutPort(OFPort.ANY) 
+		.setCookie(computeEntryCookie(0, entryName))
+		.setPriority(Integer.MAX_VALUE);
+		return;
+	}
+
+	/**
+	 * Gets the entry name of a flow mod
+	 * @param fmJson The OFFlowMod in a JSON representation
+	 * @return The name of the OFFlowMod, null if not found
+	 * @throws IOException If there was an error parsing the JSON
+	 */
+	public static String getEntryNameFromJson(String fmJson) throws IOException{
+		MappingJsonFactory f = new MappingJsonFactory();
+		JsonParser jp;
+
+		try {
+			jp = f.createJsonParser(fmJson);
+		} catch (JsonParseException e) {
+			throw new IOException(e);
+		}
+
+		jp.nextToken();
+		if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
+			throw new IOException("Expected START_OBJECT");
+		}
+
+		while (jp.nextToken() != JsonToken.END_OBJECT) {
+			if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
+				throw new IOException("Expected FIELD_NAME");
+			}
+
+			String n = jp.getCurrentName();
+			jp.nextToken();
+			if (jp.getText().equals("")) 
+				continue;
+
+			if (n == StaticFlowEntryPusher.COLUMN_NAME)
+				return jp.getText();
+		}
+		return null;
+	}
+
+	/**
+	 * Parses an OFFlowMod (and it's inner Match) to the storage entry format.
+	 * @param fm The FlowMod to parse
+	 * @param sw The switch the FlowMod is going to be installed on
+	 * @param name The name of this static flow entry
+	 * @return A Map representation of the storage entry 
+	 */
+	public static Map<String, Object> flowModToStorageEntry(OFFlowMod fm, String sw, String name) {
+		Map<String, Object> entry = new HashMap<String, Object>();
+		entry.put(StaticFlowEntryPusher.COLUMN_NAME, name);
+		entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, sw);
+		entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true));
+		entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Integer.toString(fm.getPriority()));
+
+		if ((fm.getActions() != null) && (fm.getActions().size() > 0)) {
+			entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, ActionUtils.actionsToString(fm.getActions(), log));
+		}
+
+		Match match = fm.getMatch();
+		boolean setTOS = false;
+		Iterator<MatchField<?>> itr = match.getMatchFields().iterator(); // only get exact or masked fields (not fully wildcarded)
+		while(itr.hasNext()) {
+			@SuppressWarnings("rawtypes") // this is okay here
+			MatchField mf = itr.next();
+			switch (mf.id) {
+			case IN_PORT: // iterates over only exact/masked fields. No need to check for null entries.
+				entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, Integer.toString((match.get(MatchField.IN_PORT)).getPortNumber()));
+				break;
+			case ETH_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, match.get(MatchField.ETH_SRC).toString());
+				break;
+			case ETH_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, match.get(MatchField.ETH_DST).toString());
+				break;
+			case VLAN_VID:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, match.get(MatchField.VLAN_VID).getVlan());
+				break;
+			case VLAN_PCP:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, Byte.toString(match.get(MatchField.VLAN_PCP).getValue()));
+				break;
+			case ETH_TYPE:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, match.get(MatchField.ETH_TYPE).getValue());
+				break;
+			case IP_ECN: // TOS = [DSCP bits 0-5] + [ECN bits 6-7] --> bitwise OR to get TOS byte
+				if (setTOS) { //TODO @Ryan need to break TOS into ECN and DSCP columns
+					entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, 
+							Byte.toString((byte) (match.get(MatchField.IP_ECN).getEcnValue() 
+									| (Byte.parseByte(entry.get(StaticFlowEntryPusher.COLUMN_NW_TOS).toString())))));
+				} else {
+					entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, Byte.toString((byte) (match.get(MatchField.IP_ECN).getEcnValue())));
+				}
+				setTOS = true;
+				break;
+			case IP_DSCP:
+				if (setTOS) {
+					entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, 
+							Byte.toString((byte) (match.get(MatchField.IP_DSCP).getDscpValue() 
+									| (Byte.parseByte(entry.get(StaticFlowEntryPusher.COLUMN_NW_TOS).toString())))));
+				} else {
+					entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, Byte.toString((byte) (match.get(MatchField.IP_ECN).getEcnValue())));
+				}
+				setTOS = true;
+				break;
+			case IP_PROTO:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Short.toString(match.get(MatchField.IP_PROTO).getIpProtocolNumber()));
+				break;
+			case IPV4_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, match.get(MatchField.IPV4_SRC).toString());
+				break;
+			case IPV4_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, match.get(MatchField.IPV4_DST).toString());
+				break;
+			case TCP_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.TCP_SRC).getPort());
+				break;
+			case UDP_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.UDP_SRC).getPort());
+				break;
+			case SCTP_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.SCTP_SRC).getPort());
+				break;
+			case TCP_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, match.get(MatchField.TCP_DST).getPort());
+				break;
+			case UDP_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, match.get(MatchField.UDP_DST).getPort());
+				break;
+			case SCTP_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, match.get(MatchField.SCTP_DST).getPort());
+				break;
+			case ICMPV4_TYPE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ICMP_TYPE, match.get(MatchField.ICMPV4_TYPE).getType());
+				break;
+			case ICMPV4_CODE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ICMP_CODE, match.get(MatchField.ICMPV4_CODE).getCode());
+				break;
+			case ARP_OP:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_OPCODE, match.get(MatchField.ARP_OP).getOpcode());
+				break;
+			case ARP_SHA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_SHA, match.get(MatchField.ARP_SHA).toString());
+				break;
+			case ARP_THA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_DHA, match.get(MatchField.ARP_THA).toString());
+				break;
+			case ARP_SPA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_SPA, match.get(MatchField.ARP_SPA).toString());
+				break;
+			case ARP_TPA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_DPA, match.get(MatchField.ARP_TPA).toString());
+				break;
+			case MPLS_LABEL:
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_LABEL, match.get(MatchField.MPLS_LABEL).getValue());
+				break;
+			case MPLS_TC:
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_TC, match.get(MatchField.MPLS_TC).getValue());
+				break;
+				// case MPLS_BOS not implemented in loxi
+			case METADATA:
+				entry.put(StaticFlowEntryPusher.COLUMN_METADATA, match.get(MatchField.METADATA).getValue().getValue());
+				break;
+				// case TUNNEL_ID not implemented in loxi
+				// case PBB_ISID not implemented in loxi
+			default:
+				log.error("Unhandled Match when parsing OFFlowMod: {}, {}", mf, mf.id);
+				break;
+			} // end switch-case
+		} // end while
+		return entry;
+	}
+
+	/**
+	 * Turns a JSON formatted Static Flow Pusher string into a storage entry
+	 * Expects a string in JSON along the lines of:
+	 *        {
+	 *            "switch":       "AA:BB:CC:DD:EE:FF:00:11",
+	 *            "name":         "flow-mod-1",
+	 *            "cookie":       "0",
+	 *            "priority":     "32768",
+	 *            "ingress-port": "1",
+	 *            "actions":      "output=2",
+	 *        }
+	 * @param fmJson The JSON formatted static flow pusher entry
+	 * @return The map of the storage entry
+	 * @throws IOException If there was an error parsing the JSON
+	 */
+	public static Map<String, Object> jsonToStorageEntry(String fmJson) throws IOException {
+		Map<String, Object> entry = new HashMap<String, Object>();
+		MappingJsonFactory f = new MappingJsonFactory();
+		JsonParser jp;
+
+		try {
+			jp = f.createJsonParser(fmJson);
+		} catch (JsonParseException e) {
+			throw new IOException(e);
+		}
+
+		jp.nextToken();
+		if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
+			throw new IOException("Expected START_OBJECT");
+		}
+
+		while (jp.nextToken() != JsonToken.END_OBJECT) {
+			if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
+				throw new IOException("Expected FIELD_NAME");
+			}
+
+			String n = jp.getCurrentName();
+			jp.nextToken();
+			if (jp.getText().equals("")) {
+				continue;
+			}
+
+			// Java 7 switch-case on strings automatically checks for (deep) string equality.
+			// IMHO, this makes things easier on the eyes than if, else if, else's
+
+			// A simplification is to make the column names the same strings as those used to
+			// compose the JSON flow entry; keeps all names/keys centralized and reduces liklihood
+			// for future string errors.
+			switch (n) {
+			case StaticFlowEntryPusher.COLUMN_NAME:
+				entry.put(StaticFlowEntryPusher.COLUMN_NAME, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_SWITCH:
+				entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ACTIVE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_IDLE_TIMEOUT: // store TO's, but conditionally push them
+				entry.put(StaticFlowEntryPusher.COLUMN_IDLE_TIMEOUT, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_HARD_TIMEOUT:
+				entry.put(StaticFlowEntryPusher.COLUMN_HARD_TIMEOUT, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_PRIORITY:
+				entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_COOKIE: // set manually, or computed from name
+				entry.put(StaticFlowEntryPusher.COLUMN_COOKIE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_IN_PORT:
+				entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_VLAN:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_TYPE:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_NW_TOS:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_NW_PROTO:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_NW_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_NW_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_TP_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_TP_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ICMP_TYPE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ICMP_TYPE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ICMP_CODE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ICMP_CODE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_OPCODE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_OPCODE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_SHA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_SHA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_DHA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_DHA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_SPA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_SPA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_DPA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_DPA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_MPLS_LABEL:
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_LABEL, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_MPLS_TC:
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_TC, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_MPLS_BOS: // not supported as match in loxi right now
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_BOS, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_METADATA:
+				entry.put(StaticFlowEntryPusher.COLUMN_METADATA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_TUNNEL_ID: // not supported as match in loxi right now
+				entry.put(StaticFlowEntryPusher.COLUMN_TUNNEL_ID, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_PBB_ISID: // not supported as match in loxi right now
+				entry.put(StaticFlowEntryPusher.COLUMN_PBB_ISID, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ACTIONS:
+				entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, jp.getText());
+				break;
+			default:
+				log.error("Could not decode field from JSON string: {}", n);
+			}  
+		}       
+		return entry;
+	}   
 }
 
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java
index 029d4a00da8eee4f0ac68ef69f1f3a57f1d4643a..66300be1ed663116829131f8be8e81cfedb45f01 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java
@@ -16,7 +16,6 @@
 
 package net.floodlightcontroller.staticflowentry;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -36,9 +35,10 @@ import net.floodlightcontroller.core.IHAListener;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.IOFSwitchListener;
-import net.floodlightcontroller.core.ImmutablePort;
+import net.floodlightcontroller.core.PortChangeType;
 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;
@@ -50,14 +50,22 @@ import net.floodlightcontroller.storage.IResultSet;
 import net.floodlightcontroller.storage.IStorageSourceListener;
 import net.floodlightcontroller.storage.IStorageSourceService;
 import net.floodlightcontroller.storage.StorageException;
-
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFFlowRemoved;
-import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
-import org.openflow.util.HexString;
-import org.openflow.util.U16;
+import net.floodlightcontroller.util.ActionUtils;
+import net.floodlightcontroller.util.FlowModUtils;
+import net.floodlightcontroller.util.MatchUtils;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowDeleteStrict;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
+import org.projectfloodlight.openflow.protocol.OFFlowRemovedReason;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.U16;
+import org.projectfloodlight.openflow.types.U64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -68,637 +76,642 @@ import org.slf4j.LoggerFactory;
  * is responsible for ensuring they make sense for the network.
  */
 public class StaticFlowEntryPusher
-    implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
-        IStorageSourceListener, IOFMessageListener {
-    protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryPusher.class);
-    public static final String StaticFlowName = "staticflowentry";
-
-    public static final int STATIC_FLOW_APP_ID = 10;
-    static {
-        AppCookie.registerApp(STATIC_FLOW_APP_ID, StaticFlowName);
-    }
-
-    public static final String TABLE_NAME = "controller_staticflowtableentry";
-    public static final String COLUMN_NAME = "name";
-    public static final String COLUMN_SWITCH = "switch_id";
-    public static final String COLUMN_ACTIVE = "active";
-    public static final String COLUMN_IDLE_TIMEOUT = "idle_timeout";
-    public static final String COLUMN_HARD_TIMEOUT = "hard_timeout";
-    public static final String COLUMN_PRIORITY = "priority";
-    public static final String COLUMN_COOKIE = "cookie";
-    public static final String COLUMN_WILDCARD = "wildcards";
-    public static final String COLUMN_IN_PORT = "in_port";
-    public static final String COLUMN_DL_SRC = "dl_src";
-    public static final String COLUMN_DL_DST = "dl_dst";
-    public static final String COLUMN_DL_VLAN = "dl_vlan";
-    public static final String COLUMN_DL_VLAN_PCP = "dl_vlan_pcp";
-    public static final String COLUMN_DL_TYPE = "dl_type";
-    public static final String COLUMN_NW_TOS = "nw_tos";
-    public static final String COLUMN_NW_PROTO = "nw_proto";
-    public static final String COLUMN_NW_SRC = "nw_src"; // includes CIDR-style
-                                                         // netmask, e.g.
-                                                         // "128.8.128.0/24"
-    public static final String COLUMN_NW_DST = "nw_dst";
-    public static final String COLUMN_TP_DST = "tp_dst";
-    public static final String COLUMN_TP_SRC = "tp_src";
-    public static final String COLUMN_ACTIONS = "actions";
-    public static String ColumnNames[] = { COLUMN_NAME, COLUMN_SWITCH,
-            COLUMN_ACTIVE, COLUMN_IDLE_TIMEOUT, COLUMN_HARD_TIMEOUT,
-            COLUMN_PRIORITY, COLUMN_COOKIE, COLUMN_WILDCARD, COLUMN_IN_PORT,
-            COLUMN_DL_SRC, COLUMN_DL_DST, COLUMN_DL_VLAN, COLUMN_DL_VLAN_PCP,
-            COLUMN_DL_TYPE, COLUMN_NW_TOS, COLUMN_NW_PROTO, COLUMN_NW_SRC,
-            COLUMN_NW_DST, COLUMN_TP_DST, COLUMN_TP_SRC, COLUMN_ACTIONS };
-
-
-    protected IFloodlightProviderService floodlightProvider;
-    protected IStorageSourceService storageSource;
-    protected IRestApiService restApi;
-
-    private IHAListener haListener;
-
-    // Map<DPID, Map<Name, FlowMod>>; FlowMod can be null to indicate non-active
-    protected Map<String, Map<String, OFFlowMod>> entriesFromStorage;
-    // Entry Name -> DPID of Switch it's on
-    protected Map<String, String> entry2dpid;
-
-    // Class to sort FlowMod's by priority, from lowest to highest
-    class FlowModSorter implements Comparator<String> {
-        private String dpid;
-        public FlowModSorter(String dpid) {
-            this.dpid = dpid;
-        }
-        @Override
-        public int compare(String o1, String o2) {
-            OFFlowMod f1 = entriesFromStorage.get(dpid).get(o1);
-            OFFlowMod f2 = entriesFromStorage.get(dpid).get(o2);
-            if (f1 == null || f2 == null) // sort active=false flows by key
-                return o1.compareTo(o2);
-            return U16.f(f1.getPriority()) - U16.f(f2.getPriority());
-        }
-    };
-
-    /**
-     * used for debugging and unittests
-     * @return the number of static flow entries as cached from storage
-     */
-    public int countEntries() {
-        int size = 0;
-        if (entriesFromStorage == null)
-            return 0;
-        for (String ofswitch : entriesFromStorage.keySet())
-            size += entriesFromStorage.get(ofswitch).size();
-        return size;
-    }
-
-    public IFloodlightProviderService getFloodlightProvider() {
-        return floodlightProvider;
-    }
-
-    public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) {
-        this.floodlightProvider = floodlightProvider;
-    }
-
-    public void setStorageSource(IStorageSourceService storageSource) {
-        this.storageSource = storageSource;
-    }
-
-    /**
-     * Reads from our entriesFromStorage for the specified switch and
-     * sends the FlowMods down to the controller in <b>sorted</b> order.
-     *
-     * Sorted is important to maintain correctness of the switch:
-     * if a packet would match both a lower and a higher priority
-     * rule, then we want it to match the higher priority or nothing,
-     * but never just the lower priority one.  Inserting from high to
-     * low priority fixes this.
-     *
-     * TODO consider adding a "block all" flow mod and then removing it
-     * while starting up.
-     *
-     * @param sw The switch to send entries to
-     */
-    protected void sendEntriesToSwitch(long switchId) {
-        IOFSwitch sw = floodlightProvider.getSwitch(switchId);
-        if (sw == null)
-            return;
-        String stringId = sw.getStringId();
-
-        if ((entriesFromStorage != null) && (entriesFromStorage.containsKey(stringId))) {
-            Map<String, OFFlowMod> entries = entriesFromStorage.get(stringId);
-            List<String> sortedList = new ArrayList<String>(entries.keySet());
-            // weird that Collections.sort() returns void
-            Collections.sort( sortedList, new FlowModSorter(stringId));
-            for (String entryName : sortedList) {
-                OFFlowMod flowMod = entries.get(entryName);
-                if (flowMod != null) {
-                    if (log.isDebugEnabled()) {
-                        log.debug("Pushing static entry {} for {}", stringId, entryName);
-                    }
-                    writeFlowModToSwitch(sw, flowMod);
-                }
-            }
-        }
-    }
-
-    /**
-     * Used only for bundle-local indexing
-     *
-     * @param map
-     * @return
-     */
-
-    protected Map<String, String> computeEntry2DpidMap(
-                Map<String, Map<String, OFFlowMod>> map) {
-        Map<String, String> ret = new ConcurrentHashMap<String, String>();
-        for(String dpid : map.keySet()) {
-            for( String entry: map.get(dpid).keySet())
-                ret.put(entry, dpid);
-        }
-        return ret;
-    }
-
-    /**
-     * Read entries from storageSource, and store them in a hash
-     *
-     * @return
-     */
-    @LogMessageDoc(level="ERROR",
-            message="failed to access storage: {reason}",
-            explanation="Could not retrieve static flows from the system " +
-            		"database",
-            recommendation=LogMessageDoc.CHECK_CONTROLLER)
-    private Map<String, Map<String, OFFlowMod>> readEntriesFromStorage() {
-        Map<String, Map<String, OFFlowMod>> entries = new ConcurrentHashMap<String, Map<String, OFFlowMod>>();
-        try {
-            Map<String, Object> row;
-            // null1=no predicate, null2=no ordering
-            IResultSet resultSet = storageSource.executeQuery(TABLE_NAME,
-                    ColumnNames, null, null);
-            for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
-                row = it.next().getRow();
-                parseRow(row, entries);
-            }
-        } catch (StorageException e) {
-            log.error("failed to access storage: {}", e.getMessage());
-            // if the table doesn't exist, then wait to populate later via
-            // setStorageSource()
-        }
-        return entries;
-    }
-
-    /**
-     * Take a single row, turn it into a flowMod, and add it to the
-     * entries{$dpid}.{$entryName}=FlowMod
-     *
-     * IF an entry is in active, mark it with FlowMod = null
-     *
-     * @param row
-     * @param entries
-     */
-    void parseRow(Map<String, Object> row, Map<String, Map<String, OFFlowMod>> entries) {
-        String switchName = null;
-        String entryName = null;
-
-        StringBuffer matchString = new StringBuffer();
-
-        OFFlowMod flowMod = (OFFlowMod) floodlightProvider.getOFMessageFactory()
-                .getMessage(OFType.FLOW_MOD);
-
-        if (!row.containsKey(COLUMN_SWITCH) || !row.containsKey(COLUMN_NAME)) {
-            log.debug(
-                    "skipping entry with missing required 'switch' or 'name' entry: {}",
-                    row);
-            return;
-        }
-        // most error checking done with ClassCastException
-        try {
-            // first, snag the required entries, for debugging info
-            switchName = (String) row.get(COLUMN_SWITCH);
-            entryName = (String) row.get(COLUMN_NAME);
-            if (!entries.containsKey(switchName))
-                entries.put(switchName, new HashMap<String, OFFlowMod>());
-            StaticFlowEntries.initDefaultFlowMod(flowMod, entryName);
-
-            for (String key : row.keySet()) {
-                if (row.get(key) == null)
-                    continue;
-                if (key.equals(COLUMN_SWITCH) || key.equals(COLUMN_NAME)
-                        || key.equals("id"))
-                    continue; // already handled
-                // explicitly ignore timeouts and wildcards
-                if (key.equals(COLUMN_HARD_TIMEOUT) || key.equals(COLUMN_IDLE_TIMEOUT) ||
-                        key.equals(COLUMN_WILDCARD))
-                    continue;
-                if (key.equals(COLUMN_ACTIVE)) {
-                    if  (!Boolean.valueOf((String) row.get(COLUMN_ACTIVE))) {
-                        log.debug("skipping inactive entry {} for switch {}",
-                                entryName, switchName);
-                        entries.get(switchName).put(entryName, null);  // mark this an inactive
-                        return;
-                    }
-                } else if (key.equals(COLUMN_ACTIONS)){
-                    StaticFlowEntries.parseActionString(flowMod, (String) row.get(COLUMN_ACTIONS), log);
-                } else if (key.equals(COLUMN_COOKIE)) {
-                    flowMod.setCookie(
-                            StaticFlowEntries.computeEntryCookie(flowMod,
-                                    Integer.valueOf((String) row.get(COLUMN_COOKIE)),
-                                    entryName));
-                } else if (key.equals(COLUMN_PRIORITY)) {
-                    flowMod.setPriority(U16.t(Integer.valueOf((String) row.get(COLUMN_PRIORITY))));
-                } else { // the rest of the keys are for OFMatch().fromString()
-                    if (matchString.length() > 0)
-                        matchString.append(",");
-                    matchString.append(key + "=" + row.get(key).toString());
-                }
-            }
-        } catch (ClassCastException e) {
-            if (entryName != null && switchName != null) {
-                log.warn(
-                        "Skipping entry {} on switch {} with bad data : "
-                                + e.getMessage(), entryName, switchName);
-            } else {
-                log.warn("Skipping entry with bad data: {} :: {} ",
-                        e.getMessage(), e.getStackTrace());
-            }
-        }
-
-        OFMatch ofMatch = new OFMatch();
-        String match = matchString.toString();
-        try {
-            ofMatch.fromString(match);
-        } catch (IllegalArgumentException e) {
-            log.debug(
-                    "ignoring flow entry {} on switch {} with illegal OFMatch() key: "
-                            + match, entryName, switchName);
-            return;
-        }
-        flowMod.setMatch(ofMatch);
-
-        entries.get(switchName).put(entryName, flowMod);
-    }
-
-    @Override
-    public void switchAdded(long switchId) {
-        log.debug("Switch {} connected; processing its static entries",
-                  HexString.toHexString(switchId));
-        sendEntriesToSwitch(switchId);
-    }
-
-    @Override
-    public void switchRemoved(long switchId) {
-        // do NOT delete from our internal state; we're tracking the rules,
-        // not the switches
-    }
-
-    @Override
-    public void switchActivated(long switchId) {
-        // no-op
-    }
-
-    @Override
-    public void switchChanged(long switchId) {
-        // no-op
-    }
-
-    @Override
-    public void switchPortChanged(long switchId,
-                                  ImmutablePort port,
-                                  IOFSwitch.PortChangeType type) {
-        // no-op
-    }
-
-
-    @Override
-    public void rowsModified(String tableName, Set<Object> rowKeys) {
-        // This handles both rowInsert() and rowUpdate()
-        log.debug("Modifying Table {}", tableName);
-        HashMap<String, Map<String, OFFlowMod>> entriesToAdd =
-            new HashMap<String, Map<String, OFFlowMod>>();
-        // build up list of what was added
-        for (Object key: rowKeys) {
-            IResultSet resultSet = storageSource.getRow(tableName, key);
-            Iterator<IResultSet> it = resultSet.iterator();
-            while (it.hasNext()) {
-                Map<String, Object> row = it.next().getRow();
-                parseRow(row, entriesToAdd);
-            }
-        }
-        // batch updates by switch and blast them out
-        for (String dpid : entriesToAdd.keySet()) {
-            if (!entriesFromStorage.containsKey(dpid))
-                entriesFromStorage.put(dpid, new HashMap<String, OFFlowMod>());
-
-            List<OFMessage> outQueue = new ArrayList<OFMessage>();
-            for(String entry : entriesToAdd.get(dpid).keySet()) {
-                OFFlowMod newFlowMod = entriesToAdd.get(dpid).get(entry);
-                //OFFlowMod oldFlowMod = entriesFromStorage.get(dpid).get(entry);
-                OFFlowMod oldFlowMod = null;
-                String dpidOldFlowMod = entry2dpid.get(entry);
-                if (dpidOldFlowMod != null) {
-                    oldFlowMod = entriesFromStorage.get(dpidOldFlowMod).remove(entry);
-                }
-                if (oldFlowMod != null && newFlowMod != null) {
-                    // set the new flow mod to modify a pre-existing rule if these fields match
-                    if(oldFlowMod.getMatch().equals(newFlowMod.getMatch())
-                            && oldFlowMod.getCookie() == newFlowMod.getCookie()
-                            && oldFlowMod.getPriority() == newFlowMod.getPriority()){
-                        newFlowMod.setCommand(OFFlowMod.OFPFC_MODIFY_STRICT);
-                    // if they don't match delete the old flow
-                    } else{
-                        oldFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
-                        if (dpidOldFlowMod.equals(dpid)) {
-                            outQueue.add(oldFlowMod);
-                        } else {
-                            writeOFMessageToSwitch(HexString.toLong(dpidOldFlowMod), oldFlowMod);
-                        }
-                    }
-                }
-                // write the new flow
-                if (newFlowMod != null) {
-                    entriesFromStorage.get(dpid).put(entry, newFlowMod);
-                    outQueue.add(newFlowMod);
-                    entry2dpid.put(entry, dpid);
-                } else {
-                    entriesFromStorage.get(dpid).remove(entry);
-                    entry2dpid.remove(entry);
-                }
-            }
-            writeOFMessagesToSwitch(HexString.toLong(dpid), outQueue);
-        }
-    }
-
-    @Override
-    public void rowsDeleted(String tableName, Set<Object> rowKeys) {
-        if (log.isDebugEnabled()) {
-            log.debug("Deleting from table {}", tableName);
-        }
-
-        for(Object obj : rowKeys) {
-            if (!(obj instanceof String)) {
-                log.debug("Tried to delete non-string key {}; ignoring", obj);
-                continue;
-            }
-            deleteStaticFlowEntry((String) obj);
-        }
-    }
-
-    @LogMessageDoc(level="ERROR",
-            message="inconsistent internal state: no switch has rule {rule}",
-            explanation="Inconsistent internat state discovered while " +
-                    "deleting a static flow rule",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    private void deleteStaticFlowEntry(String entryName) {
-        String dpid = entry2dpid.remove(entryName);
-
-        if (dpid == null) {
-            // assume state has been cleared by deleteFlowsForSwitch() or
-            // deleteAllFlows()
-            return;
-        }
-
-        if (log.isDebugEnabled()) {
-            log.debug("Sending delete flow mod for flow {} for switch {}", entryName, dpid);
-        }
-
-        // send flow_mod delete
-        OFFlowMod flowMod = entriesFromStorage.get(dpid).get(entryName);
-        flowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
-
-        if (entriesFromStorage.containsKey(dpid) &&
-                entriesFromStorage.get(dpid).containsKey(entryName)) {
-            entriesFromStorage.get(dpid).remove(entryName);
-        } else {
-            log.debug("Tried to delete non-existent entry {} for switch {}",
-                    entryName, dpid);
-            return;
-        }
-
-        writeFlowModToSwitch(HexString.toLong(dpid), flowMod);
-        return;
-    }
-
-    /**
-     * Writes a list of OFMessages to a switch
-     * @param dpid The datapath ID of the switch to write to
-     * @param messages The list of OFMessages to write.
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Tried to write to switch {switch} but got {error}",
-            explanation="An I/O error occured while trying to write a " +
-                    "static flow to a switch",
-            recommendation=LogMessageDoc.CHECK_SWITCH)
-    private void writeOFMessagesToSwitch(long dpid, List<OFMessage> messages) {
-        IOFSwitch ofswitch = floodlightProvider.getSwitch(dpid);
-        if (ofswitch != null) {  // is the switch connected
-            try {
-                if (log.isDebugEnabled()) {
-                    log.debug("Sending {} new entries to {}", messages.size(), dpid);
-                }
-                ofswitch.write(messages, null);
-                ofswitch.flush();
-            } catch (IOException e) {
-                log.error("Tried to write to switch {} but got {}", dpid, e.getMessage());
-            }
-        }
-    }
-
-    /**
-     * Writes a single OFMessage to a switch
-     * @param dpid The datapath ID of the switch to write to
-     * @param message The OFMessage to write.
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Tried to write to switch {switch} but got {error}",
-            explanation="An I/O error occured while trying to write a " +
-                    "static flow to a switch",
-            recommendation=LogMessageDoc.CHECK_SWITCH)
-    private void writeOFMessageToSwitch(long dpid, OFMessage message) {
-        IOFSwitch ofswitch = floodlightProvider.getSwitch(dpid);
-        if (ofswitch != null) {  // is the switch connected
-            try {
-                if (log.isDebugEnabled()) {
-                    log.debug("Sending 1 new entries to {}", HexString.toHexString(dpid));
-                }
-                ofswitch.write(message, null);
-                ofswitch.flush();
-            } catch (IOException e) {
-                log.error("Tried to write to switch {} but got {}", dpid, e.getMessage());
-            }
-        }
-    }
-
-    /**
-     * Writes an OFFlowMod to a switch. It checks to make sure the switch
-     * exists before it sends
-     * @param dpid The data  to write the flow mod to
-     * @param flowMod The OFFlowMod to write
-     */
-    private void writeFlowModToSwitch(long dpid, OFFlowMod flowMod) {
-        IOFSwitch ofSwitch = floodlightProvider.getSwitch(dpid);
-        if (ofSwitch == null) {
-            if (log.isDebugEnabled()) {
-                log.debug("Not deleting key {} :: switch {} not connected",
-                          dpid);
-            }
-            return;
-        }
-        writeFlowModToSwitch(ofSwitch, flowMod);
-    }
-
-    /**
-     * Writes an OFFlowMod to a switch
-     * @param sw The IOFSwitch to write to
-     * @param flowMod The OFFlowMod to write
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Tried to write OFFlowMod to {switch} but got {error}",
-            explanation="An I/O error occured while trying to write a " +
-                    "static flow to a switch",
-            recommendation=LogMessageDoc.CHECK_SWITCH)
-    private void writeFlowModToSwitch(IOFSwitch sw, OFFlowMod flowMod) {
-        try {
-            sw.write(flowMod, null);
-            sw.flush();
-        } catch (IOException e) {
-            log.error("Tried to write OFFlowMod to {} but failed: {}",
-                    HexString.toHexString(sw.getId()), e.getMessage());
-        }
-    }
-
-    @Override
-    public String getName() {
-        return StaticFlowName;
-    }
-
-    /**
-     * Handles a flow removed message from a switch. If the flow was removed
-     * and we did not explicitly delete it we re-install it. If we explicitly
-     * removed the flow we stop the processing of the flow removed message.
-     * @param sw The switch that sent the flow removed message.
-     * @param msg The flow removed message.
-     * @param cntx The associated context.
-     * @return Whether to continue processing this message.
-     */
-    public Command handleFlowRemoved(IOFSwitch sw, OFFlowRemoved msg, FloodlightContext cntx) {
-        long cookie = msg.getCookie();
-        /**
-         * This is just to sanity check our assumption that static flows
-         * never expire.
-         */
-        if (AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) {
-            if (msg.getReason() != OFFlowRemoved.OFFlowRemovedReason.OFPRR_DELETE)
-                log.error("Got a FlowRemove message for a infinite " +
-                          "timeout flow: {} from switch {}", msg, sw);
-            // Stop the processing chain since we sent the delete.
-            return Command.STOP;
-        }
-
-        return Command.CONTINUE;
-    }
-
-    @Override
-    @LogMessageDoc(level="ERROR",
-        message="Got a FlowRemove message for a infinite " +
-                "timeout flow: {flow} from switch {switch}",
-        explanation="Flows with infinite timeouts should not expire. " +
-        		"The switch has expired the flow anyway.",
-        recommendation=LogMessageDoc.REPORT_SWITCH_BUG)
-    public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
-        switch (msg.getType()) {
-        case FLOW_REMOVED:
-            return handleFlowRemoved(sw, (OFFlowRemoved) msg, cntx);
-        default:
-            return Command.CONTINUE;
-        }
-    }
-
-    @Override
-    public boolean isCallbackOrderingPrereq(OFType type, String name) {
-        return false;  // no dependency for non-packet in
-    }
-
-    @Override
-    public boolean isCallbackOrderingPostreq(OFType type, String name) {
-        return false;  // no dependency for non-packet in
-    }
-
-    // IFloodlightModule
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l =
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IStaticFlowEntryPusherService.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(IStaticFlowEntryPusherService.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(IStorageSourceService.class);
-        l.add(IRestApiService.class);
-        return l;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-        floodlightProvider =
-            context.getServiceImpl(IFloodlightProviderService.class);
-        storageSource =
-            context.getServiceImpl(IStorageSourceService.class);
-        restApi =
-            context.getServiceImpl(IRestApiService.class);
-        haListener = new HAListenerDelegate();
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this);
-        floodlightProvider.addOFSwitchListener(this);
-        floodlightProvider.addHAListener(this.haListener);
-
-        // assumes no switches connected at startup()
-        storageSource.createTable(TABLE_NAME, null);
-        storageSource.setTablePrimaryKeyName(TABLE_NAME, COLUMN_NAME);
-        storageSource.addListener(TABLE_NAME, this);
-        entriesFromStorage = readEntriesFromStorage();
-        entry2dpid = computeEntry2DpidMap(entriesFromStorage);
-        restApi.addRestletRoutable(new StaticFlowEntryWebRoutable());
-    }
-
-    // IStaticFlowEntryPusherService methods
-
-    @Override
-    public void addFlow(String name, OFFlowMod fm, String swDpid) {
-        Map<String, Object> fmMap = StaticFlowEntries.flowModToStorageEntry(fm, swDpid, name);
-        storageSource.insertRowAsync(TABLE_NAME, fmMap);
-    }
-
-    @Override
-    public void deleteFlow(String name) {
-        storageSource.deleteRowAsync(TABLE_NAME, name);
-    }
-
-    @Override
-    public void deleteAllFlows() {
-        for (String entry : entry2dpid.keySet()) {
-            deleteFlow(entry);
-        }
-
-        /*
+implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, IStorageSourceListener, IOFMessageListener {
+	protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryPusher.class);
+	public static final String StaticFlowName = "staticflowentry";
+
+	public static final int STATIC_FLOW_APP_ID = 10;
+	static {
+		AppCookie.registerApp(STATIC_FLOW_APP_ID, StaticFlowName);
+	}
+
+	public static final String TABLE_NAME = "controller_staticflowtableentry";
+	public static final String COLUMN_NAME = "name";
+	public static final String COLUMN_SWITCH = "switch";
+	public static final String COLUMN_ACTIVE = "active";
+	public static final String COLUMN_IDLE_TIMEOUT = "idle_timeout";
+	public static final String COLUMN_HARD_TIMEOUT = "hard_timeout";
+	public static final String COLUMN_PRIORITY = "priority";
+	public static final String COLUMN_COOKIE = "cookie";
+
+	// Common location for Match Strings. Still the same, but relocated.
+	public static final String COLUMN_IN_PORT = MatchUtils.STR_IN_PORT;
+
+	public static final String COLUMN_DL_SRC = MatchUtils.STR_DL_SRC;
+	public static final String COLUMN_DL_DST = MatchUtils.STR_DL_DST;
+	public static final String COLUMN_DL_VLAN = MatchUtils.STR_DL_VLAN;
+	public static final String COLUMN_DL_VLAN_PCP = MatchUtils.STR_DL_VLAN_PCP;
+	public static final String COLUMN_DL_TYPE = MatchUtils.STR_DL_TYPE;
+
+	public static final String COLUMN_NW_TOS = MatchUtils.STR_NW_TOS;
+	public static final String COLUMN_NW_PROTO = MatchUtils.STR_NW_PROTO;
+	public static final String COLUMN_NW_SRC = MatchUtils.STR_NW_SRC; // includes CIDR-style netmask, e.g. "128.8.128.0/24"
+	public static final String COLUMN_NW_DST = MatchUtils.STR_NW_DST;
+
+	public static final String COLUMN_TP_SRC = MatchUtils.STR_TP_SRC;
+	public static final String COLUMN_TP_DST = MatchUtils.STR_TP_DST;
+
+	/* newly added matches for OF1.3 port start here */
+	public static final String COLUMN_ICMP_TYPE = MatchUtils.STR_ICMP_TYPE;
+	public static final String COLUMN_ICMP_CODE = MatchUtils.STR_ICMP_CODE;
+
+	public static final String COLUMN_ARP_OPCODE = MatchUtils.STR_ARP_OPCODE;
+	public static final String COLUMN_ARP_SHA = MatchUtils.STR_ARP_SHA;
+	public static final String COLUMN_ARP_DHA = MatchUtils.STR_ARP_DHA;
+	public static final String COLUMN_ARP_SPA = MatchUtils.STR_ARP_SPA;
+	public static final String COLUMN_ARP_DPA = MatchUtils.STR_ARP_DPA;
+
+	public static final String COLUMN_MPLS_LABEL = MatchUtils.STR_MPLS_LABEL;
+	public static final String COLUMN_MPLS_TC = MatchUtils.STR_MPLS_TC;
+	public static final String COLUMN_MPLS_BOS = MatchUtils.STR_MPLS_BOS;
+
+	public static final String COLUMN_METADATA = MatchUtils.STR_METADATA;
+	public static final String COLUMN_TUNNEL_ID = MatchUtils.STR_TUNNEL_ID;
+
+	public static final String COLUMN_PBB_ISID = MatchUtils.STR_PBB_ISID;
+	/* end newly added matches TODO @Ryan should look into full IPv6 support*/
+
+	public static final String COLUMN_ACTIONS = "actions";
+
+	public static String ColumnNames[] = { COLUMN_NAME, COLUMN_SWITCH,
+		COLUMN_ACTIVE, COLUMN_IDLE_TIMEOUT, COLUMN_HARD_TIMEOUT,
+		COLUMN_PRIORITY, COLUMN_COOKIE, COLUMN_IN_PORT,
+		COLUMN_DL_SRC, COLUMN_DL_DST, COLUMN_DL_VLAN, COLUMN_DL_VLAN_PCP,
+		COLUMN_DL_TYPE, COLUMN_NW_TOS, COLUMN_NW_PROTO, COLUMN_NW_SRC,
+		COLUMN_NW_DST, COLUMN_TP_DST, COLUMN_TP_SRC, 
+		/* newly added matches for OF1.3 port start here */
+		COLUMN_ICMP_TYPE, COLUMN_ICMP_CODE, 
+		COLUMN_ARP_OPCODE, COLUMN_ARP_SHA, COLUMN_ARP_DHA, 
+		COLUMN_ARP_SPA, COLUMN_ARP_DPA,
+		COLUMN_MPLS_LABEL, COLUMN_MPLS_TC, COLUMN_MPLS_BOS, 
+		COLUMN_METADATA, COLUMN_TUNNEL_ID, COLUMN_PBB_ISID,
+		/* end newly added matches */
+		COLUMN_ACTIONS };
+
+
+	protected IFloodlightProviderService floodlightProviderService;
+	protected IOFSwitchService switchService;
+	protected IStorageSourceService storageSourceService;
+	protected IRestApiService restApiService;
+
+	private IHAListener haListener;
+
+	// Map<DPID, Map<Name, FlowMod>>; FlowMod can be null to indicate non-active
+	protected Map<String, Map<String, OFFlowMod>> entriesFromStorage;
+	// Entry Name -> DPID of Switch it's on
+	protected Map<String, String> entry2dpid;
+
+	// Class to sort FlowMod's by priority, from lowest to highest
+	class FlowModSorter implements Comparator<String> {
+		private String dpid;
+		public FlowModSorter(String dpid) {
+			this.dpid = dpid;
+		}
+		@Override
+		public int compare(String o1, String o2) {
+			OFFlowMod f1 = entriesFromStorage.get(dpid).get(o1);
+			OFFlowMod f2 = entriesFromStorage.get(dpid).get(o2);
+			if (f1 == null || f2 == null) // sort active=false flows by key
+				return o1.compareTo(o2);
+			return U16.of(f1.getPriority()).getValue() - U16.of(f2.getPriority()).getValue();
+		}
+	};
+
+	/**
+	 * used for debugging and unittests
+	 * @return the number of static flow entries as cached from storage
+	 */
+	public int countEntries() {
+		int size = 0;
+		if (entriesFromStorage == null)
+			return 0;
+		for (String ofswitch : entriesFromStorage.keySet())
+			size += entriesFromStorage.get(ofswitch).size();
+		return size;
+	}
+
+	public IFloodlightProviderService getFloodlightProvider() {
+		return floodlightProviderService;
+	}
+
+	public void setFloodlightProvider(IFloodlightProviderService floodlightProviderService) {
+		this.floodlightProviderService = floodlightProviderService;
+	}
+
+	public void setStorageSource(IStorageSourceService storageSourceService) {
+		this.storageSourceService = storageSourceService;
+	}
+
+	/**
+	 * Reads from our entriesFromStorage for the specified switch and
+	 * sends the FlowMods down to the controller in <b>sorted</b> order.
+	 *
+	 * Sorted is important to maintain correctness of the switch:
+	 * if a packet would match both a lower and a higher priority
+	 * rule, then we want it to match the higher priority or nothing,
+	 * but never just the lower priority one.  Inserting from high to
+	 * low priority fixes this.
+	 *
+	 * TODO consider adding a "block all" flow mod and then removing it
+	 * while starting up.
+	 *
+	 * @param sw The switch to send entries to
+	 */
+	protected void sendEntriesToSwitch(DatapathId switchId) {
+		IOFSwitch sw = switchService.getSwitch(switchId);
+		if (sw == null)
+			return;
+		String stringId = sw.getId().toString();
+
+		if ((entriesFromStorage != null) && (entriesFromStorage.containsKey(stringId))) {
+			Map<String, OFFlowMod> entries = entriesFromStorage.get(stringId);
+			List<String> sortedList = new ArrayList<String>(entries.keySet());
+			// weird that Collections.sort() returns void
+			Collections.sort( sortedList, new FlowModSorter(stringId));
+			for (String entryName : sortedList) {
+				OFFlowMod flowMod = entries.get(entryName);
+				if (flowMod != null) {
+					if (log.isDebugEnabled()) {
+						log.debug("Pushing static entry {} for {}", stringId, entryName);
+					}
+					writeFlowModToSwitch(sw, flowMod);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Used only for bundle-local indexing
+	 *
+	 * @param map
+	 * @return
+	 */
+
+	protected Map<String, String> computeEntry2DpidMap(
+			Map<String, Map<String, OFFlowMod>> map) {
+		Map<String, String> ret = new ConcurrentHashMap<String, String>();
+		for(String dpid : map.keySet()) {
+			for( String entry: map.get(dpid).keySet())
+				ret.put(entry, dpid);
+		}
+		return ret;
+	}
+
+	/**
+	 * Read entries from storageSource, and store them in a hash
+	 *
+	 * @return
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="failed to access storage: {reason}",
+			explanation="Could not retrieve static flows from the system " +
+					"database",
+					recommendation=LogMessageDoc.CHECK_CONTROLLER)
+	private Map<String, Map<String, OFFlowMod>> readEntriesFromStorage() {
+		Map<String, Map<String, OFFlowMod>> entries = new ConcurrentHashMap<String, Map<String, OFFlowMod>>();
+		try {
+			Map<String, Object> row;
+			// null1=no predicate, null2=no ordering
+			IResultSet resultSet = storageSourceService.executeQuery(TABLE_NAME, ColumnNames, null, null);
+			for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
+				row = it.next().getRow();
+				parseRow(row, entries);
+			}
+		} catch (StorageException e) {
+			log.error("failed to access storage: {}", e.getMessage());
+			// if the table doesn't exist, then wait to populate later via
+			// setStorageSource()
+		}
+		return entries;
+	}
+
+	/**
+	 * Take a single row, turn it into a flowMod, and add it to the
+	 * entries{$dpid}.{$entryName}=FlowMod
+	 *
+	 * IF an entry is in active, mark it with FlowMod = null
+	 *
+	 * @param row
+	 * @param entries
+	 */
+	void parseRow(Map<String, Object> row, Map<String, Map<String, OFFlowMod>> entries) {
+		String switchName = null;
+		String entryName = null;
+
+		StringBuffer matchString = new StringBuffer();
+		OFFlowMod.Builder fmb = null; 
+
+		if (!row.containsKey(COLUMN_SWITCH) || !row.containsKey(COLUMN_NAME)) {
+			log.debug("skipping entry with missing required 'switch' or 'name' entry: {}", row);
+			return;
+		}
+		// most error checking done with ClassCastException
+		try {
+			// first, snag the required entries, for debugging info
+			switchName = (String) row.get(COLUMN_SWITCH);
+			entryName = (String) row.get(COLUMN_NAME);
+			if (!entries.containsKey(switchName)) {
+				entries.put(switchName, new HashMap<String, OFFlowMod>());
+			}
+
+			// get the correct builder for the OF version supported by the switch
+			// TODO @Ryan this should arguably be a FlowAdd, not a FlowModify
+			fmb = OFFactories.getFactory(switchService.getSwitch(DatapathId.of(switchName)).getOFFactory().getVersion()).buildFlowModify();
+
+			StaticFlowEntries.initDefaultFlowMod(fmb, entryName);
+
+			for (String key : row.keySet()) {
+				if (row.get(key) == null)
+					continue;
+				if (key.equals(COLUMN_SWITCH) || key.equals(COLUMN_NAME)
+						|| key.equals("id"))
+					continue; // already handled
+				// explicitly ignore timeouts and wildcards
+				if (key.equals(COLUMN_HARD_TIMEOUT) || key.equals(COLUMN_IDLE_TIMEOUT))
+					continue;
+				if (key.equals(COLUMN_ACTIVE)) {
+					if  (!Boolean.valueOf((String) row.get(COLUMN_ACTIVE))) {
+						log.debug("skipping inactive entry {} for switch {}", entryName, switchName);
+						entries.get(switchName).put(entryName, null);  // mark this an inactive
+						return;
+					}
+				} else if (key.equals(COLUMN_ACTIONS)){
+					ActionUtils.fromString(fmb, (String) row.get(COLUMN_ACTIONS), log);
+				} else if (key.equals(COLUMN_COOKIE)) {
+					fmb.setCookie(StaticFlowEntries.computeEntryCookie(Integer.valueOf((String) row.get(COLUMN_COOKIE)), entryName));
+				} else if (key.equals(COLUMN_PRIORITY)) {
+					fmb.setPriority(U16.t(Integer.valueOf((String) row.get(COLUMN_PRIORITY))));
+				} else { // the rest of the keys are for Match().fromString()
+					if (matchString.length() > 0) {
+						matchString.append(",");
+					}
+					matchString.append(key + "=" + row.get(key).toString());
+				}
+			}
+		} catch (ClassCastException e) {
+			if (entryName != null && switchName != null) {
+				log.warn("Skipping entry {} on switch {} with bad data : " + e.getMessage(), entryName, switchName);
+			} else {
+				log.warn("Skipping entry with bad data: {} :: {} ", e.getMessage(), e.getStackTrace());
+			}
+		}
+
+		String match = matchString.toString();
+
+		try {
+			//TODO @Ryan new fromString() method here. Should verify it especially
+			fmb.setMatch(MatchUtils.fromString(match, fmb.getVersion()));
+		} catch (IllegalArgumentException e) {
+			log.debug("ignoring flow entry {} on switch {} with illegal OFMatch() key: " + match, entryName, switchName);
+			return;
+		}
+
+		entries.get(switchName).put(entryName, fmb.build()); // add the FlowMod message to the table
+	}
+
+	@Override
+	public void switchAdded(DatapathId switchId) {
+		log.debug("Switch {} connected; processing its static entries",
+				switchId.toString());
+		sendEntriesToSwitch(switchId);
+	}
+
+	@Override
+	public void switchRemoved(DatapathId switchId) {
+		// do NOT delete from our internal state; we're tracking the rules,
+		// not the switches
+	}
+
+	@Override
+	public void switchActivated(DatapathId switchId) {
+		// no-op
+	}
+
+	@Override
+	public void switchChanged(DatapathId switchId) {
+		// no-op
+	}
+
+	@Override
+	public void switchPortChanged(DatapathId switchId,
+			OFPortDesc port,
+			PortChangeType type) {
+		// no-op
+	}
+
+
+	@Override
+	public void rowsModified(String tableName, Set<Object> rowKeys) {
+		// This handles both rowInsert() and rowUpdate()
+		log.debug("Modifying Table {}", tableName);
+		HashMap<String, Map<String, OFFlowMod>> entriesToAdd =
+				new HashMap<String, Map<String, OFFlowMod>>();
+		// build up list of what was added
+		for (Object key: rowKeys) {
+			IResultSet resultSet = storageSourceService.getRow(tableName, key);
+			Iterator<IResultSet> it = resultSet.iterator();
+			while (it.hasNext()) {
+				Map<String, Object> row = it.next().getRow();
+				parseRow(row, entriesToAdd);
+			}
+		}
+		// batch updates by switch and blast them out
+		for (String dpid : entriesToAdd.keySet()) {
+			if (!entriesFromStorage.containsKey(dpid))
+				entriesFromStorage.put(dpid, new HashMap<String, OFFlowMod>());
+
+			List<OFMessage> outQueue = new ArrayList<OFMessage>();
+			for (String entry : entriesToAdd.get(dpid).keySet()) {
+				OFFlowMod newFlowMod = entriesToAdd.get(dpid).get(entry);
+				OFFlowMod oldFlowMod = null;
+				String dpidOldFlowMod = entry2dpid.get(entry);
+				if (dpidOldFlowMod != null) {
+					oldFlowMod = entriesFromStorage.get(dpidOldFlowMod).remove(entry);
+				}
+				// pre-existing case. should modify or delete, but not add
+				if (oldFlowMod != null && newFlowMod != null) {
+					// set the new flow mod to modify a pre-existing rule if these fields match
+					if (oldFlowMod.getMatch().equals(newFlowMod.getMatch())
+							&& oldFlowMod.getCookie() == newFlowMod.getCookie()
+							&& oldFlowMod.getPriority() == newFlowMod.getPriority()) {
+						newFlowMod = FlowModUtils.toFlowModifyStrict(newFlowMod);
+						// if they don't match delete the old flow
+					} else {
+						oldFlowMod = FlowModUtils.toFlowDeleteStrict(oldFlowMod);
+						if (dpidOldFlowMod.equals(dpid)) {
+							outQueue.add(oldFlowMod);
+						} else {
+							writeOFMessageToSwitch(DatapathId.of(dpidOldFlowMod), oldFlowMod);
+						}
+					}
+				}
+				// new case. should add a flow, not modify or delete
+				if (newFlowMod != null) {
+					OFFlowAdd addTmp = FlowModUtils.toFlowAdd(newFlowMod);
+					entriesFromStorage.get(dpid).put(entry, addTmp);
+					outQueue.add(addTmp);
+					entry2dpid.put(entry, dpid);
+				} else {
+					entriesFromStorage.get(dpid).remove(entry);
+					entry2dpid.remove(entry);
+				}
+			}
+			writeOFMessagesToSwitch(DatapathId.of(dpid), outQueue);
+		}
+	}
+
+	@Override
+	public void rowsDeleted(String tableName, Set<Object> rowKeys) {
+		if (log.isDebugEnabled()) {
+			log.debug("Deleting from table {}", tableName);
+		}
+
+		for(Object obj : rowKeys) {
+			if (!(obj instanceof String)) {
+				log.debug("Tried to delete non-string key {}; ignoring", obj);
+				continue;
+			}
+			deleteStaticFlowEntry((String) obj);
+		}
+	}
+
+	@LogMessageDoc(level="ERROR",
+			message="inconsistent internal state: no switch has rule {rule}",
+			explanation="Inconsistent internat state discovered while " +
+					"deleting a static flow rule",
+					recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+	private void deleteStaticFlowEntry(String entryName) {
+		String dpid = entry2dpid.remove(entryName);
+
+		if (dpid == null) {
+			// assume state has been cleared by deleteFlowsForSwitch() or
+			// deleteAllFlows()
+			return;
+		}
+
+		if (log.isDebugEnabled()) {
+			log.debug("Sending delete flow mod for flow {} for switch {}", entryName, dpid);
+		}
+
+		// send flow_mod delete
+		OFFlowDeleteStrict flowMod = FlowModUtils.toFlowDeleteStrict(entriesFromStorage.get(dpid).get(entryName));
+
+		if (entriesFromStorage.containsKey(dpid) && entriesFromStorage.get(dpid).containsKey(entryName)) {
+			entriesFromStorage.get(dpid).remove(entryName);
+		} else {
+			log.debug("Tried to delete non-existent entry {} for switch {}", entryName, dpid);
+			return;
+		}
+
+		writeFlowModToSwitch(DatapathId.of(dpid), flowMod);
+		return;
+	}
+
+	/**
+	 * Writes a list of OFMessages to a switch
+	 * @param dpid The datapath ID of the switch to write to
+	 * @param messages The list of OFMessages to write.
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="Tried to write to switch {switch} but got {error}",
+			explanation="An I/O error occured while trying to write a " +
+					"static flow to a switch",
+					recommendation=LogMessageDoc.CHECK_SWITCH)
+	private void writeOFMessagesToSwitch(DatapathId dpid, List<OFMessage> messages) {
+		IOFSwitch ofswitch = switchService.getSwitch(dpid);
+		if (ofswitch != null) {  // is the switch connected
+			if (log.isDebugEnabled()) {
+				log.debug("Sending {} new entries to {}", messages.size(), dpid);
+			}
+			ofswitch.write(messages);
+			ofswitch.flush();
+		}
+	}
+
+	/**
+	 * Writes a single OFMessage to a switch
+	 * @param dpid The datapath ID of the switch to write to
+	 * @param message The OFMessage to write.
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="Tried to write to switch {switch} but got {error}",
+			explanation="An I/O error occured while trying to write a " +
+					"static flow to a switch",
+					recommendation=LogMessageDoc.CHECK_SWITCH)
+	private void writeOFMessageToSwitch(DatapathId dpid, OFMessage message) {
+		IOFSwitch ofswitch = switchService.getSwitch(dpid);
+		if (ofswitch != null) {  // is the switch connected
+			if (log.isDebugEnabled()) {
+				log.debug("Sending 1 new entries to {}", dpid.toString());
+			}
+			ofswitch.write(message);
+			ofswitch.flush();
+		}
+	}
+
+	/**
+	 * Writes an OFFlowMod to a switch. It checks to make sure the switch
+	 * exists before it sends
+	 * @param dpid The data  to write the flow mod to
+	 * @param flowMod The OFFlowMod to write
+	 */
+	private void writeFlowModToSwitch(DatapathId dpid, OFFlowMod flowMod) {
+		IOFSwitch ofSwitch = switchService.getSwitch(dpid);
+		if (ofSwitch == null) {
+			if (log.isDebugEnabled()) {
+				log.debug("Not deleting key {} :: switch {} not connected", dpid.toString());
+			}
+			return;
+		}
+		writeFlowModToSwitch(ofSwitch, flowMod);
+	}
+
+	/**
+	 * Writes an OFFlowMod to a switch
+	 * @param sw The IOFSwitch to write to
+	 * @param flowMod The OFFlowMod to write
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="Tried to write OFFlowMod to {switch} but got {error}",
+			explanation="An I/O error occured while trying to write a " +
+					"static flow to a switch",
+					recommendation=LogMessageDoc.CHECK_SWITCH)
+	private void writeFlowModToSwitch(IOFSwitch sw, OFFlowMod flowMod) {
+		sw.write(flowMod);
+		sw.flush();
+	}
+
+	@Override
+	public String getName() {
+		return StaticFlowName;
+	}
+
+	/**
+	 * Handles a flow removed message from a switch. If the flow was removed
+	 * and we did not explicitly delete it we re-install it. If we explicitly
+	 * removed the flow we stop the processing of the flow removed message.
+	 * @param sw The switch that sent the flow removed message.
+	 * @param msg The flow removed message.
+	 * @param cntx The associated context.
+	 * @return Whether to continue processing this message.
+	 */
+	public Command handleFlowRemoved(IOFSwitch sw, OFFlowRemoved msg, FloodlightContext cntx) {
+		U64 cookie = msg.getCookie();
+		/**
+		 * This is just to sanity check our assumption that static flows
+		 * never expire.
+		 */
+		if (AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) {
+			if (OFFlowRemovedReason.DELETE.equals(msg.getReason()))
+				log.error("Got a FlowRemove message for a infinite " +
+						"timeout flow: {} from switch {}", msg, sw);
+			// Stop the processing chain since we sent the delete.
+			return Command.STOP;
+		}
+
+		return Command.CONTINUE;
+	}
+
+	@Override
+	@LogMessageDoc(level="ERROR",
+	message="Got a FlowRemove message for a infinite " +
+			"timeout flow: {flow} from switch {switch}",
+			explanation="Flows with infinite timeouts should not expire. " +
+					"The switch has expired the flow anyway.",
+					recommendation=LogMessageDoc.REPORT_SWITCH_BUG)
+	public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+		switch (msg.getType()) {
+		case FLOW_REMOVED:
+			return handleFlowRemoved(sw, (OFFlowRemoved) msg, cntx);
+		default:
+			return Command.CONTINUE;
+		}
+	}
+
+	@Override
+	public boolean isCallbackOrderingPrereq(OFType type, String name) {
+		return false;  // no dependency for non-packet in
+	}
+
+	@Override
+	public boolean isCallbackOrderingPostreq(OFType type, String name) {
+		return false;  // no dependency for non-packet in
+	}
+
+	// IFloodlightModule
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		Collection<Class<? extends IFloodlightService>> l =
+				new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(IStaticFlowEntryPusherService.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(IStaticFlowEntryPusherService.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(IOFSwitchService.class);
+		l.add(IStorageSourceService.class);
+		l.add(IRestApiService.class);
+		return l;
+	}
+
+	@Override
+	public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+		floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+		switchService = context.getServiceImpl(IOFSwitchService.class);
+		storageSourceService = context.getServiceImpl(IStorageSourceService.class);
+		restApiService = context.getServiceImpl(IRestApiService.class);
+		haListener = new HAListenerDelegate();
+	} 
+
+	@Override
+	public void startUp(FloodlightModuleContext context) {
+		floodlightProviderService.addOFMessageListener(OFType.FLOW_REMOVED, this);
+		switchService.addOFSwitchListener(this);
+		floodlightProviderService.addHAListener(this.haListener);
+		// assumes no switches connected at startup()
+		storageSourceService.createTable(TABLE_NAME, null);
+		storageSourceService.setTablePrimaryKeyName(TABLE_NAME, COLUMN_NAME);
+		storageSourceService.addListener(TABLE_NAME, this);
+		entriesFromStorage = readEntriesFromStorage();
+		entry2dpid = computeEntry2DpidMap(entriesFromStorage);
+		restApiService.addRestletRoutable(new StaticFlowEntryWebRoutable());
+	}
+
+	// IStaticFlowEntryPusherService methods
+
+	@Override
+	public void addFlow(String name, OFFlowMod fm, DatapathId swDpid) {
+		Map<String, Object> fmMap = StaticFlowEntries.flowModToStorageEntry(fm, swDpid.toString(), name);
+		storageSourceService.insertRowAsync(TABLE_NAME, fmMap);
+	}
+
+	@Override
+	public void deleteFlow(String name) {
+		storageSourceService.deleteRowAsync(TABLE_NAME, name);
+	}
+
+	@Override
+	public void deleteAllFlows() {
+		for (String entry : entry2dpid.keySet()) {
+			deleteFlow(entry);
+		}
+
+		/*
         FIXME: Since the OF spec 1.0 is not clear on how
         to match on cookies. Once all switches come to a
         common implementation we can possibly re-enable this
@@ -724,19 +737,19 @@ public class StaticFlowEntryPusher
 
         // Reset our DB
         storageSource.deleteMatchingRowsAsync(TABLE_NAME, null);
-        */
-    }
+		 */
+	}
 
-    @Override
-    public void deleteFlowsForSwitch(long dpid) {
-        String sDpid = HexString.toHexString(dpid);
+	@Override
+	public void deleteFlowsForSwitch(DatapathId dpid) {
+		String sDpid = dpid.toString();
 
-        for (Entry<String, String> e : entry2dpid.entrySet()) {
-            if (e.getValue().equals(sDpid))
-                deleteFlow(e.getKey());
-        }
+		for (Entry<String, String> e : entry2dpid.entrySet()) {
+			if (e.getValue().equals(sDpid))
+				deleteFlow(e.getKey());
+		}
 
-        /*
+		/*
         FIXME: Since the OF spec 1.0 is not clear on how
         to match on cookies. Once all switches come to a
         common implementation we can possibly re-enable this
@@ -756,17 +769,17 @@ public class StaticFlowEntryPusher
         } else {
             log.warn("Map of storage entries for switch {} was null", sDpid);
         }
-        */
-    }
-
-    /**
-     * Deletes all flows installed by static flow pusher on a given switch.
-     * We send a delete flow mod with the static flow pusher app ID in the cookie.
-     * Since OF1.0 doesn't support masking based on the cookie we have to
-     * disable having flow specific cookies.
-     * @param dpid The DPID of the switch to clear all it's flows.
-     */
-    /*
+		 */
+	}
+
+	/**
+	 * Deletes all flows installed by static flow pusher on a given switch.
+	 * We send a delete flow mod with the static flow pusher app ID in the cookie.
+	 * Since OF1.0 doesn't support masking based on the cookie we have to
+	 * disable having flow specific cookies.
+	 * @param dpid The DPID of the switch to clear all it's flows.
+	 */
+	/*
     FIXME: Since the OF spec 1.0 is not clear on how
     to match on cookies. Once all switches come to a
     common implementation we can possibly re-enable this
@@ -799,54 +812,58 @@ public class StaticFlowEntryPusher
             return;
         }
     }
-    */
-
-    @Override
-    public Map<String, Map<String, OFFlowMod>> getFlows() {
-        return entriesFromStorage;
-    }
-
-    @Override
-    public Map<String, OFFlowMod> getFlows(String dpid) {
-        return entriesFromStorage.get(dpid);
-    }
-
-    // IHAListener
-
-    private class HAListenerDelegate implements IHAListener {
-        @Override
-        public void transitionToMaster() {
-            log.debug("Re-reading static flows from storage due " +
-                    "to HA change from SLAVE->MASTER");
-            entriesFromStorage = readEntriesFromStorage();
-            entry2dpid = computeEntry2DpidMap(entriesFromStorage);
-        }
-
-        @Override
-        public void controllerNodeIPsChanged(
-                Map<String, String> curControllerNodeIPs,
-                Map<String, String> addedControllerNodeIPs,
-                Map<String, String> removedControllerNodeIPs) {
-            // ignore
-        }
-
-        @Override
-        public String getName() {
-            return StaticFlowEntryPusher.this.getName();
-        }
-
-        @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 Map<String, Map<String, OFFlowMod>> getFlows() {
+		return entriesFromStorage;
+	}
+
+	@Override
+	public Map<String, OFFlowMod> getFlows(DatapathId dpid) {
+		return entriesFromStorage.get(dpid.toString());
+	}
+
+	// IHAListener
+
+	private class HAListenerDelegate implements IHAListener {
+		@Override
+		public void transitionToActive() {
+			log.debug("Re-reading static flows from storage due " +
+					"to HA change from STANDBY->ACTIVE");
+			entriesFromStorage = readEntriesFromStorage();
+			entry2dpid = computeEntry2DpidMap(entriesFromStorage);
+		}
+
+		@Override
+		public void controllerNodeIPsChanged(
+				Map<String, String> curControllerNodeIPs,
+				Map<String, String> addedControllerNodeIPs,
+				Map<String, String> removedControllerNodeIPs) {
+			// ignore
+		}
+
+		@Override
+		public String getName() {
+			return StaticFlowEntryPusher.this.getName();
+		}
+
+		@Override
+		public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
+				String name) {
+			return false;
+		}
+
+		@Override
+		public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
+				String name) {
+			return false;
+		}
+
+		@Override
+		public void transitionToStandby() {	
+			log.debug("Controller is now in STANDBY role. Clearing static flow entries from store.");
+			deleteAllFlows();
+		}
+	}
 }
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/web/ClearStaticFlowEntriesResource.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/ClearStaticFlowEntriesResource.java
index 8705282bc358af59e8660e89d906226a65cb21d0..ced2ff535ec20970fb962c4536a85794d2f34dc5 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/web/ClearStaticFlowEntriesResource.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/web/ClearStaticFlowEntriesResource.java
@@ -19,7 +19,7 @@ package net.floodlightcontroller.staticflowentry.web;
 import net.floodlightcontroller.core.web.ControllerSwitchesResource;
 import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
 import org.restlet.data.Status;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
@@ -43,7 +43,7 @@ public class ClearStaticFlowEntriesResource extends ServerResource {
             sfpService.deleteAllFlows();
         } else {
             try {
-                sfpService.deleteFlowsForSwitch(HexString.toLong(param));
+                sfpService.deleteFlowsForSwitch(DatapathId.of(param));
             } catch (NumberFormatException e){
                 setStatus(Status.CLIENT_ERROR_BAD_REQUEST, 
                           ControllerSwitchesResource.DPID_ERROR);
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java
index b552381f7dbf4d1909a7a2cdf262dd99a61ead45..d9ec69c1eba4f379fb8d02a18ba42f24a29e6118 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java
@@ -22,7 +22,8 @@ import java.util.Map;
 import net.floodlightcontroller.core.web.ControllerSwitchesResource;
 import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;
 
-import org.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.types.DatapathId;
 import org.restlet.data.Status;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
@@ -46,14 +47,12 @@ public class ListStaticFlowEntriesResource extends ServerResource {
             return sfpService.getFlows();
         } else {
             try {
-                Map<String, Map<String, OFFlowMod>> retMap = 
-                        new HashMap<String, Map<String, OFFlowMod>>();
-                retMap.put(param, sfpService.getFlows(param));
+                Map<String, Map<String, OFFlowMod>> retMap = new HashMap<String, Map<String, OFFlowMod>>();
+                retMap.put(param, sfpService.getFlows(DatapathId.of(param)));
                 return retMap;
                 
             } catch (NumberFormatException e){
-                setStatus(Status.CLIENT_ERROR_BAD_REQUEST, 
-                          ControllerSwitchesResource.DPID_ERROR);
+                setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ControllerSwitchesResource.DPID_ERROR);
             }
         }
         return null;
diff --git a/src/main/java/net/floodlightcontroller/storage/AbstractStorageSource.java b/src/main/java/net/floodlightcontroller/storage/AbstractStorageSource.java
index 3033e99e4fd44eb799045b38f7b947ceddcf3c7b..911c1a12dcc31d06bced558ffbcc87b694eb6474 100644
--- a/src/main/java/net/floodlightcontroller/storage/AbstractStorageSource.java
+++ b/src/main/java/net/floodlightcontroller/storage/AbstractStorageSource.java
@@ -36,10 +36,8 @@ 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.counter.ICounter;
-import net.floodlightcontroller.counter.CounterStore;
-import net.floodlightcontroller.counter.ICounterStoreService;
-import net.floodlightcontroller.counter.CounterValue.CounterType;
+import net.floodlightcontroller.debugcounter.IDebugCounter;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.storage.web.StorageWebRoutable;
 
@@ -67,7 +65,7 @@ public abstract class AbstractStorageSource
     protected final static String STORAGE_DELETE_COUNTER_NAME = "StorageDelete";
     
     protected Set<String> allTableNames = new CopyOnWriteArraySet<String>();
-    protected ICounterStoreService counterStore;
+    protected IDebugCounterService debugCounterService;
     protected ExecutorService executorService = defaultExecutorService;
     protected IStorageExceptionHandler exceptionHandler;
 
@@ -146,25 +144,26 @@ public abstract class AbstractStorageSource
         return allTableNames;
     }
     
-    public void setCounterStore(CounterStore counterStore) {
-        this.counterStore = counterStore;
+    public void setDebugCounterService(IDebugCounterService dcs) {
+        debugCounterService = dcs;
     }
     
     protected void updateCounters(String baseName, String tableName) {
-        if (counterStore != null) {
+        /*if (debugCounterService != null) {
             String counterName;
             if (tableName != null) {
                 updateCounters(baseName, null);
-                counterName = baseName + CounterStore.TitleDelimitor + tableName;
+                counterName = baseName + "__" + tableName; //TODO @Ryan __ was CounterStore.Title
             } else {
                 counterName = baseName;
             }
-            ICounter counter = counterStore.getCounter(counterName);
+            TODO @Ryan not sure what to do about this counter. It seems different than debug counters.
+             * IDebugCounter counter = debugCounterService.getCounter(counterName);
             if (counter == null) {
                 counter = counterStore.createCounter(counterName, CounterType.LONG);
             }
             counter.increment();
-        }
+        }*/
     }
     
     @Override
@@ -518,7 +517,7 @@ public abstract class AbstractStorageSource
         Collection<Class<? extends IFloodlightService>> l = 
                 new ArrayList<Class<? extends IFloodlightService>>();
         l.add(IRestApiService.class);
-        l.add(ICounterStoreService.class);
+        l.add(IDebugCounterService.class);
         return l;
     }
 
@@ -527,8 +526,8 @@ public abstract class AbstractStorageSource
             throws FloodlightModuleException {
         restApi =
            context.getServiceImpl(IRestApiService.class);
-        counterStore =
-            context.getServiceImpl(ICounterStoreService.class);
+        debugCounterService =
+            context.getServiceImpl(IDebugCounterService.class);
     }
 
     @Override
diff --git a/src/main/java/net/floodlightcontroller/testmodule/TestModule.java b/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
new file mode 100644
index 0000000000000000000000000000000000000000..886a33750b3d0fb37b766c2b3eea2f1e59917405
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
@@ -0,0 +1,190 @@
+package net.floodlightcontroller.testmodule;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFOxmClass;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFSetConfig;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
+import org.projectfloodlight.openflow.types.ArpOpcode;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.ICMPv4Code;
+import org.projectfloodlight.openflow.types.ICMPv4Type;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IpDscp;
+import org.projectfloodlight.openflow.types.IpEcn;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFMetadata;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFValueType;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U8;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.VlanVid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.floodlightcontroller.core.IOFSwitchListener;
+import net.floodlightcontroller.core.PortChangeType;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
+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.staticflowentry.IStaticFlowEntryPusherService;
+
+public class TestModule implements IFloodlightModule, IOFSwitchListener {
+
+	private static IStaticFlowEntryPusherService sfps;
+	private static IOFSwitchService switchService;
+	private static Logger log;
+	
+	@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(IStaticFlowEntryPusherService.class);
+		l.add(IOFSwitchService.class);
+		return l;
+	}
+
+	@Override
+	public void init(FloodlightModuleContext context)
+			throws FloodlightModuleException {
+		sfps = context.getServiceImpl(IStaticFlowEntryPusherService.class);
+		switchService = context.getServiceImpl(IOFSwitchService.class);
+		switchService.addOFSwitchListener(this);
+		log = LoggerFactory.getLogger(TestModule.class);
+		if (sfps == null) {
+			log.error("Static Flow Pusher Service not found!");
+		}
+	}
+
+	@Override
+	public void startUp(FloodlightModuleContext context)
+			throws FloodlightModuleException {
+		
+
+	}
+
+	@Override
+	public void switchAdded(DatapathId switchId) {
+		OFFactory factory = switchService.getSwitch(switchId).getOFFactory();
+		OFFlowAdd.Builder fmb = factory.buildFlowAdd();
+		List<OFAction> actions = new ArrayList<OFAction>();
+        Match.Builder mb = factory.buildMatch();
+        
+		/*try {
+			Thread.sleep(3000);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}*/
+        
+        //TODO @Ryan set a bunch of matches. Test for an OF1.0 and OF1.3 switch. See what happens if they are incorrectly applied.
+        /* L2 and ICMP TESTS mb.setExact(MatchField.ETH_TYPE, EthType.IPv4);
+        mb.setExact(MatchField.ETH_SRC, MacAddress.BROADCAST);
+        mb.setExact(MatchField.ETH_DST, MacAddress.BROADCAST);
+        mb.setExact(MatchField.IPV4_SRC, IPv4Address.of("127.1.1.1"));
+        mb.setExact(MatchField.IPV4_DST, IPv4Address.of("128.2.2.2"));
+        mb.setExact(MatchField.IP_PROTO, IpProtocol.ICMP);
+        mb.setExact(MatchField.ICMPV4_CODE, ICMPv4Code.of((short)1));
+        mb.setExact(MatchField.ICMPV4_TYPE, ICMPv4Type.ECHO); */
+        
+        /* ARP TESTS mb.setExact(MatchField.ETH_TYPE, EthType.ARP);
+        mb.setExact(MatchField.ARP_OP, ArpOpcode.REQUEST);
+        mb.setExact(MatchField.ARP_SHA, MacAddress.BROADCAST);
+        mb.setExact(MatchField.ARP_SPA, IPv4Address.of("130.127.39.241"));
+        mb.setExact(MatchField.ARP_THA, MacAddress.BROADCAST);
+        mb.setExact(MatchField.ARP_TPA, IPv4Address.of("130.127.39.241")); */
+        
+        /* TP, IP OPT, VLAN TESTS */ mb.setExact(MatchField.ETH_TYPE, EthType.IPv4);
+        mb.setExact(MatchField.VLAN_PCP, VlanPcp.of((byte) 1)); // might as well test these now too
+        mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(512));
+        mb.setExact(MatchField.MPLS_LABEL, U32.of(32));
+        mb.setExact(MatchField.MPLS_TC, U8.of((short)64));
+        mb.setExact(MatchField.IP_ECN, IpEcn.ECN_10); // and these
+        mb.setExact(MatchField.IP_DSCP, IpDscp.DSCP_16);
+        mb.setExact(MatchField.IP_PROTO, IpProtocol.UDP); // with tcp, udp, sctp
+        mb.setExact(MatchField.UDP_SRC, TransportPort.of(22));
+        mb.setExact(MatchField.UDP_DST, TransportPort.of(80)); 
+        
+        /* MPLS TESTS mb.setExact(MatchField.ETH_TYPE, EthType.MPLS_MULTICAST);
+        mb.setExact(MatchField.MPLS_LABEL, U32.of(18));
+        mb.setExact(MatchField.MPLS_TC, U8.of((short)4));*/
+        
+        /* METADATA TEST 
+        mb.setExact(MatchField.METADATA, OFMetadata.ofRaw(1)); */
+
+        
+        //TODO @Ryan set a bunch of actions. "" "" """ """"""
+        OFActionOutput.Builder actionBuilder = factory.actions().buildOutput();
+        actions.add(factory.actions().output(OFPort.of(1), Integer.MAX_VALUE));
+        actions.add(factory.actions().setField(factory.oxms().ethSrc(MacAddress.BROADCAST)));
+        actions.add(factory.actions().setField(factory.oxms().ethDst(MacAddress.BROADCAST)));
+        actions.add(factory.actions().setField(factory.oxms().ipv4Src(IPv4Address.of("127.0.1.2"))));
+        actions.add(factory.actions().setField(factory.oxms().ipv4Src(IPv4Address.of("128.0.3.4"))));
+
+
+        fmb.setActions(actions);
+        fmb.setMatch(mb.build());
+		        
+		sfps.addFlow("test-flow", fmb.build(), switchId);
+		//sfps.deleteFlow("test-flow");
+		
+	}
+
+	@Override
+	public void switchRemoved(DatapathId switchId) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public void switchActivated(DatapathId switchId) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public void switchPortChanged(DatapathId switchId, OFPortDesc port,
+			PortChangeType type) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public void switchChanged(DatapathId switchId) {
+		// TODO Auto-generated method stub
+		
+	}
+
+}
diff --git a/src/main/java/net/floodlightcontroller/topology/Cluster.java b/src/main/java/net/floodlightcontroller/topology/Cluster.java
index eb1489fb1a99a5c1b6efcacb8c8f74f885cd4616..914740f10246698c95c7cf0085cb09465c79a709 100644
--- a/src/main/java/net/floodlightcontroller/topology/Cluster.java
+++ b/src/main/java/net/floodlightcontroller/topology/Cluster.java
@@ -23,57 +23,51 @@ import java.util.Set;
 
 import net.floodlightcontroller.routing.Link;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
 
 public class Cluster {
-    protected long id; // the lowest id of the nodes
-    protected Map<Long, Set<Link>> links; // set of links connected to a node.
+    protected DatapathId id; // the lowest id of the nodes
+    protected Map<DatapathId, Set<Link>> links; // set of links connected to a node.
 
     public Cluster() {
-        id = Long.MAX_VALUE;
-        links = new HashMap<Long, Set<Link>>();
+        id = DatapathId.NONE;
+        links = new HashMap<DatapathId, Set<Link>>();
     }
 
-    public long getId() {
+    public DatapathId getId() {
         return id;
     }
 
-    public void setId(long id) {
+    public void setId(DatapathId id) {
         this.id = id;
     }
 
-    public Map<Long, Set<Link>> getLinks() {
+    public Map<DatapathId, Set<Link>> getLinks() {
         return links;
     }
 
-    public Set<Long> getNodes() {
+    public Set<DatapathId> getNodes() {
         return links.keySet();
     }
 
-    void add(long n) {
+    void add(DatapathId n) {
         if (links.containsKey(n) == false) {
             links.put(n, new HashSet<Link>());
-            if (n < id) id = n;
+            if (n.getLong() < id.getLong()) id = n;
         }
     }
 
     void addLink(Link l) {
-        if (links.containsKey(l.getSrc()) == false) {
-            links.put(l.getSrc(), new HashSet<Link>());
-            if (l.getSrc() < id) id = l.getSrc();
-        }
+        add(l.getSrc());
         links.get(l.getSrc()).add(l);
 
-        if (links.containsKey(l.getDst()) == false) {
-            links.put(l.getDst(), new HashSet<Link>());
-            if (l.getDst() < id) id = l.getDst();
-        }
+        add(l.getDst());
         links.get(l.getDst()).add(l);
      }
 
     @Override 
     public int hashCode() {
-        return (int) (id + id >>>32);
+        return (int) (id.getLong() + id.getLong() >>>32);
     }
 
     @Override
@@ -90,6 +84,6 @@ public class Cluster {
     }
     
     public String toString() {
-        return "[Cluster id=" + HexString.toHexString(id) + ", " + links.keySet() + "]";
+        return "[Cluster id=" + id.toString() + ", " + links.keySet() + "]";
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java
index d518b80d21320095b9baaa3f5223768c414a414a..d6bd177550852501cded815cc2132abc9dc868b0 100644
--- a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java
+++ b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java
@@ -19,192 +19,195 @@ 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(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);
+	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);
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java b/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java
index 8c5645143ac0edc54df86582d9b83273bd30ed56..8df5bcb83e8b8ed11d2dac7cdbf7556d82ce8192 100644
--- a/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java
+++ b/src/main/java/net/floodlightcontroller/topology/NodePortTuple.java
@@ -21,7 +21,9 @@ import net.floodlightcontroller.core.web.serializers.UShortSerializer;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import org.openflow.util.HexString;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
 
 /**
  * A NodePortTuple is similar to a SwitchPortTuple
@@ -31,51 +33,46 @@ import org.openflow.util.HexString;
  */
 
 public class NodePortTuple implements Comparable<NodePortTuple> {
-    protected long nodeId; // switch DPID
-    protected short portId; // switch port id
+    protected DatapathId nodeId; // switch DPID
+    protected OFPort portId; // switch port id
 
     /**
      * Creates a NodePortTuple
      * @param nodeId The DPID of the switch
      * @param portId The port of the switch
      */
-    public NodePortTuple(long nodeId, short portId) {
+    public NodePortTuple(DatapathId nodeId, OFPort 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 long getNodeId() {
+    public DatapathId getNodeId() {
         return nodeId;
     }
-    public void setNodeId(long nodeId) {
+    public void setNodeId(DatapathId nodeId) {
         this.nodeId = nodeId;
     }
     @JsonProperty("port")
     @JsonSerialize(using=UShortSerializer.class)
-    public short getPortId() {
+    public OFPort getPortId() {
         return portId;
     }
-    public void setPortId(short portId) {
+    public void setPortId(OFPort portId) {
         this.portId = portId;
     }
     
     public String toString() {
-        return "[id=" + HexString.toHexString(nodeId) + ", port=" + new Short(portId) + "]";
+        return "[id=" + nodeId.toString() + ", port=" + portId.toString() + "]";
     }
 
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + (int) (nodeId ^ (nodeId >>> 32));
-        result = prime * result + portId;
+        result = prime * result + (int) (nodeId.getLong() ^ (nodeId.getLong() >>> 32));
+        result = prime * result + portId.getPortNumber();
         return result;
     }
 
@@ -102,7 +99,7 @@ public class NodePortTuple implements Comparable<NodePortTuple> {
      * @return
      */
     public String toKeyString() {
-        return (HexString.toHexString(nodeId)+ "|" + (portId & 0xffff));
+        return (nodeId.toString()+ "|" + portId.toString());
     }
 
     @Override
@@ -111,14 +108,14 @@ public class NodePortTuple implements Comparable<NodePortTuple> {
         final int EQUAL = 0;
         final int AFTER = 1;
 
-        if (this.getNodeId() < obj.getNodeId())
+        if (this.getNodeId().getLong() < obj.getNodeId().getLong())
             return BEFORE;
-        if (this.getNodeId() > obj.getNodeId())
+        if (this.getNodeId().getLong() > obj.getNodeId().getLong())
             return AFTER;
 
-        if (this.getPortId() < obj.getPortId())
+        if (this.getPortId().getPortNumber() < obj.getPortId().getPortNumber())
             return BEFORE;
-        if (this.getPortId() > obj.getPortId())
+        if (this.getPortId().getPortNumber() > obj.getPortId().getPortNumber())
             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 a143d45e73e6bff892766999926487fb6fcb2f03..57d27231d07e02d3fb16688599eba9fe94b354db 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
@@ -25,7 +25,9 @@ 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.projectfloodlight.openflow.types.U64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -59,7 +61,7 @@ public class TopologyInstance {
 
     protected static Logger log = LoggerFactory.getLogger(TopologyInstance.class);
 
-    protected Map<Long, Set<Short>> switchPorts; // Set of ports for each switch
+    protected Map<DatapathId, Set<OFPort>> 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.
@@ -69,17 +71,17 @@ public class TopologyInstance {
     /** Set of links that are blocked. */
     protected Set<Link> blockedLinks;
 
-    protected Set<Long> switches;
+    protected Set<DatapathId> switches;
     protected Set<NodePortTuple> broadcastDomainPorts;
     protected Set<NodePortTuple> tunnelPorts;
 
     protected Set<Cluster> clusters;  // set of openflow domains
-    protected Map<Long, Cluster> switchClusterMap; // switch to OF domain map
+    protected Map<DatapathId, Cluster> switchClusterMap; // switch to OF domain map
 
     // States for routing
-    protected Map<Long, BroadcastTree> destinationRootedTrees;
-    protected Map<Long, Set<NodePortTuple>> clusterBroadcastNodePorts;
-    protected Map<Long, BroadcastTree> clusterBroadcastTrees;
+    protected Map<DatapathId, BroadcastTree> destinationRootedTrees;
+    protected Map<DatapathId, Set<NodePortTuple>> clusterBroadcastNodePorts;
+    protected Map<DatapathId, BroadcastTree> clusterBroadcastTrees;
 
     protected class PathCacheLoader extends CacheLoader<RouteId, Route> {
         TopologyInstance ti;
@@ -99,8 +101,8 @@ public class TopologyInstance {
     protected LoadingCache<RouteId, Route> pathcache;
 
     public TopologyInstance() {
-        this.switches = new HashSet<Long>();
-        this.switchPorts = new HashMap<Long, Set<Short>>();
+        this.switches = new HashSet<DatapathId>();
+        this.switchPorts = new HashMap<DatapathId, Set<OFPort>>();
         this.switchPortLinks = new HashMap<NodePortTuple, Set<Link>>();
         this.broadcastDomainPorts = new HashSet<NodePortTuple>();
         this.tunnelPorts = new HashSet<NodePortTuple>();
@@ -108,12 +110,12 @@ public class TopologyInstance {
         this.blockedLinks = new HashSet<Link>();
     }
 
-    public TopologyInstance(Map<Long, Set<Short>> switchPorts,
+    public TopologyInstance(Map<DatapathId, Set<OFPort>> switchPorts,
                             Map<NodePortTuple, Set<Link>> switchPortLinks,
                             Set<NodePortTuple> broadcastDomainPorts)
     {
-        this.switches = new HashSet<Long>(switchPorts.keySet());
-        this.switchPorts = new HashMap<Long, Set<Short>>(switchPorts);
+        this.switches = new HashSet<DatapathId>(switchPorts.keySet());
+        this.switchPorts = new HashMap<DatapathId, Set<OFPort>>(switchPorts);
         this.switchPortLinks = new HashMap<NodePortTuple,
                 Set<Link>>(switchPortLinks);
         this.broadcastDomainPorts = new HashSet<NodePortTuple>(broadcastDomainPorts);
@@ -122,19 +124,19 @@ public class TopologyInstance {
         this.blockedLinks = new HashSet<Link>();
 
         clusters = new HashSet<Cluster>();
-        switchClusterMap = new HashMap<Long, Cluster>();
+        switchClusterMap = new HashMap<DatapathId, Cluster>();
     }
-    public TopologyInstance(Map<Long, Set<Short>> switchPorts,
+    public TopologyInstance(Map<DatapathId, Set<OFPort>> switchPorts,
                             Set<NodePortTuple> blockedPorts,
                             Map<NodePortTuple, Set<Link>> switchPortLinks,
                             Set<NodePortTuple> broadcastDomainPorts,
                             Set<NodePortTuple> tunnelPorts){
 
         // copy these structures
-        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.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.blockedPorts = new HashSet<NodePortTuple>(blockedPorts);
@@ -148,10 +150,10 @@ public class TopologyInstance {
 
         blockedLinks = new HashSet<Link>();
         clusters = new HashSet<Cluster>();
-        switchClusterMap = new HashMap<Long, Cluster>();
-        destinationRootedTrees = new HashMap<Long, BroadcastTree>();
-        clusterBroadcastTrees = new HashMap<Long, BroadcastTree>();
-        clusterBroadcastNodePorts = new HashMap<Long, Set<NodePortTuple>>();
+        switchClusterMap = new HashMap<DatapathId, Cluster>();
+        destinationRootedTrees = new HashMap<DatapathId, BroadcastTree>();
+        clusterBroadcastTrees = new HashMap<DatapathId, BroadcastTree>();
+        clusterBroadcastNodePorts = new HashMap<DatapathId, Set<NodePortTuple>>();
 
         pathcache = CacheBuilder.newBuilder().concurrencyLevel(4)
                     .maximumSize(1000L)
@@ -204,9 +206,9 @@ public class TopologyInstance {
     }
 
     protected void addLinksToOpenflowDomains() {
-        for(long s: switches) {
+        for(DatapathId s: switches) {
             if (switchPorts.get(s) == null) continue;
-            for (short p: switchPorts.get(s)) {
+            for (OFPort p: switchPorts.get(s)) {
                 NodePortTuple np = new NodePortTuple(s, p);
                 if (switchPortLinks.get(np) == null) continue;
                 if (isBroadcastDomainPort(np)) continue;
@@ -242,17 +244,17 @@ public class TopologyInstance {
             explanation="The internal state of the topology module is corrupt",
             recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
     public void identifyOpenflowDomains() {
-        Map<Long, ClusterDFS> dfsList = new HashMap<Long, ClusterDFS>();
+        Map<DatapathId, ClusterDFS> dfsList = new HashMap<DatapathId, ClusterDFS>();
 
         if (switches == null) return;
 
-        for (Long key: switches) {
+        for (DatapathId key: switches) {
             ClusterDFS cdfs = new ClusterDFS();
             dfsList.put(key, cdfs);
         }
-        Set<Long> currSet = new HashSet<Long>();
+        Set<DatapathId> currSet = new HashSet<DatapathId>();
 
-        for (Long sw: switches) {
+        for (DatapathId sw: switches) {
             ClusterDFS cdfs = dfsList.get(sw);
             if (cdfs == null) {
                 log.error("No DFS object for switch {} found.", sw);
@@ -291,15 +293,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, long currSw,
-                              Map<Long, ClusterDFS> dfsList, Set <Long> currSet) {
+    private long dfsTraverse (long parentIndex, long currIndex, DatapathId currSw,
+                              Map<DatapathId, ClusterDFS> dfsList, Set <DatapathId> currSet) {
 
         //Get the DFS object corresponding to the current switch
         ClusterDFS currDFS = dfsList.get(currSw);
         // Get all the links corresponding to this switch
 
-        Set<Long> nodesInMyCluster = new HashSet<Long>();
-        Set<Long> myCurrSet = new HashSet<Long>();
+        Set<DatapathId> nodesInMyCluster = new HashSet<DatapathId>();
+        Set<DatapathId> myCurrSet = new HashSet<DatapathId>();
 
         //Assign the DFS object with right values.
         currDFS.setVisited(true);
@@ -309,14 +311,14 @@ public class TopologyInstance {
 
         // Traverse the graph through every outgoing link.
         if (switchPorts.get(currSw) != null){
-            for(Short p: switchPorts.get(currSw)) {
+            for(OFPort p: switchPorts.get(currSw)) {
                 Set<Link> lset = switchPortLinks.get(new NodePortTuple(currSw, p));
                 if (lset == null) continue;
                 for(Link l:lset) {
-                    long dstSw = l.getDst();
+                	DatapathId dstSw = l.getDst();
 
                     // ignore incoming links.
-                    if (dstSw == currSw) continue;
+                    if (dstSw.equals(currSw)) continue;
 
                     // ignore if the destination is already added to
                     // another cluster
@@ -368,7 +370,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(long sw: currSet){
+            for(DatapathId sw: currSet){
                 sc.add(sw);
                 switchClusterMap.put(sw, sc);
             }
@@ -425,8 +427,8 @@ public class TopologyInstance {
     }
 
     protected class NodeDist implements Comparable<NodeDist> {
-        private final Long node;
-        public Long getNode() {
+        private final DatapathId node;
+        public DatapathId getNode() {
             return node;
         }
 
@@ -435,7 +437,7 @@ public class TopologyInstance {
             return dist;
         }
 
-        public NodeDist(Long node, int dist) {
+        public NodeDist(DatapathId node, int dist) {
             this.node = node;
             this.dist = dist;
         }
@@ -443,7 +445,7 @@ public class TopologyInstance {
         @Override
         public int compareTo(NodeDist o) {
             if (o.dist == this.dist) {
-                return (int)(this.node - o.node);
+                return (int)(this.node.getLong() - o.node.getLong());
             }
             return this.dist - o.dist;
         }
@@ -478,34 +480,34 @@ public class TopologyInstance {
         }
     }
 
-    protected BroadcastTree dijkstra(Cluster c, Long root,
+    protected BroadcastTree dijkstra(Cluster c, DatapathId root,
                                      Map<Link, Integer> linkCost,
                                      boolean isDstRooted) {
-        HashMap<Long, Link> nexthoplinks = new HashMap<Long, Link>();
+        HashMap<DatapathId, Link> nexthoplinks = new HashMap<DatapathId, Link>();
         //HashMap<Long, Long> nexthopnodes = new HashMap<Long, Long>();
-        HashMap<Long, Integer> cost = new HashMap<Long, Integer>();
+        HashMap<DatapathId, Integer> cost = new HashMap<DatapathId, Integer>();
         int w;
 
-        for (Long node: c.links.keySet()) {
+        for (DatapathId node: c.links.keySet()) {
             nexthoplinks.put(node, null);
             //nexthopnodes.put(node, null);
             cost.put(node, MAX_PATH_WEIGHT);
         }
 
-        HashMap<Long, Boolean> seen = new HashMap<Long, Boolean>();
+        HashMap<DatapathId, Boolean> seen = new HashMap<DatapathId, 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();
-            Long cnode = n.getNode();
+            DatapathId 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)) {
-                Long neighbor;
+            	DatapathId neighbor;
 
                 if (isDstRooted == true) neighbor = link.getSrc();
                 else neighbor = link.getDst();
@@ -554,7 +556,7 @@ public class TopologyInstance {
         }
 
         for(Cluster c: clusters) {
-            for (Long node : c.links.keySet()) {
+            for (DatapathId node : c.links.keySet()) {
                 BroadcastTree tree = dijkstra(c, node, linkCost, true);
                 destinationRootedTrees.put(node, tree);
             }
@@ -581,9 +583,9 @@ public class TopologyInstance {
             //log.info("Broadcast Tree {}", tree);
 
             Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
-            Map<Long, Link> links = tree.getLinks();
+            Map<DatapathId, Link> links = tree.getLinks();
             if (links == null) continue;
-            for(long nodeId: links.keySet()) {
+            for(DatapathId nodeId: links.keySet()) {
                 Link l = links.get(nodeId);
                 if (l == null) continue;
                 NodePortTuple npt1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
@@ -597,17 +599,15 @@ public class TopologyInstance {
 
     protected Route buildroute(RouteId id) {
         NodePortTuple npt;
-        long srcId = id.getSrc();
-        long dstId = id.getDst();
+        DatapathId srcId = id.getSrc();
+        DatapathId dstId = id.getDst();
 
-        LinkedList<NodePortTuple> switchPorts =
-                new LinkedList<NodePortTuple>();
+        LinkedList<NodePortTuple> switchPorts = new LinkedList<NodePortTuple>();
 
         if (destinationRootedTrees == null) return null;
         if (destinationRootedTrees.get(dstId) == null) return null;
 
-        Map<Long, Link> nexthoplinks =
-                destinationRootedTrees.get(dstId).getLinks();
+        Map<DatapathId, Link> nexthoplinks = destinationRootedTrees.get(dstId).getLinks();
 
         if (!switches.contains(srcId) || !switches.contains(dstId)) {
             // This is a switch that is not connected to any other switch
@@ -618,7 +618,7 @@ public class TopologyInstance {
             // The only possible non-null path for this case is
             // if srcId equals dstId --- and that too is an 'empty' path []
 
-        } else if ((nexthoplinks!=null) && (nexthoplinks.get(srcId)!=null)) {
+        } else if ((nexthoplinks!=null) && (nexthoplinks.get(srcId) != null)) {
             while (srcId != dstId) {
                 Link l = nexthoplinks.get(srcId);
 
@@ -632,15 +632,16 @@ public class TopologyInstance {
         // else, no path exists, and path equals null
 
         Route result = null;
-        if (switchPorts != null && !switchPorts.isEmpty())
+        if (switchPorts != null && !switchPorts.isEmpty()) {
             result = new Route(id, switchPorts);
+        }
         if (log.isTraceEnabled()) {
             log.trace("buildroute: {}", result);
         }
         return result;
     }
 
-    protected int getCost(long srcId, long dstId) {
+    protected int getCost(DatapathId srcId, DatapathId dstId) {
         BroadcastTree bt = destinationRootedTrees.get(dstId);
         if (bt == null) return -1;
         return (bt.getCost(srcId));
@@ -655,7 +656,7 @@ public class TopologyInstance {
     }
 
     // IRoutingEngineService interfaces
-    protected boolean routeExists(long srcId, long dstId) {
+    protected boolean routeExists(DatapathId srcId, DatapathId dstId) {
         BroadcastTree bt = destinationRootedTrees.get(dstId);
         if (bt == null) return false;
         Link link = bt.getLinks().get(srcId);
@@ -663,19 +664,19 @@ public class TopologyInstance {
         return true;
     }
 
-    protected Route getRoute(ServiceChain sc, long srcId, short srcPort,
-                             long dstId, short dstPort, long cookie) {
+    protected Route getRoute(ServiceChain sc, DatapathId srcId, OFPort srcPort,
+    		DatapathId dstId, OFPort dstPort, U64 cookie) {
 
 
         // Return null the route source and desitnation are the
         // same switchports.
-        if (srcId == dstId && srcPort == dstPort)
+        if (srcId.equals(dstId) && srcPort.equals(dstPort))
             return null;
 
         List<NodePortTuple> nptList;
         NodePortTuple npt;
-        Route r = getRoute(srcId, dstId, 0);
-        if (r == null && srcId != dstId) return null;
+        Route r = getRoute(srcId, dstId, U64.of(0));
+        if (r == null && !srcId.equals(dstId)) return null;
 
         if (r != null) {
             nptList= new ArrayList<NodePortTuple>(r.getPath());
@@ -695,9 +696,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(long srcId, long dstId, long cookie) {
+    protected Route getRoute(DatapathId srcId, DatapathId dstId, U64 cookie) {
         // Return null route if srcId equals dstId
-        if (srcId == dstId) return null;
+        if (srcId.equals(dstId)) return null;
 
 
         RouteId id = new RouteId(srcId, dstId);
@@ -725,54 +726,54 @@ public class TopologyInstance {
     //  ITopologyService interface method helpers.
     //
 
-    protected boolean isInternalToOpenflowDomain(long switchid, short port) {
+    protected boolean isInternalToOpenflowDomain(DatapathId switchid, OFPort port) {
         return !isAttachmentPointPort(switchid, port);
     }
 
-    public boolean isAttachmentPointPort(long switchid, short port) {
+    public boolean isAttachmentPointPort(DatapathId switchid, OFPort port) {
         NodePortTuple npt = new NodePortTuple(switchid, port);
         if (switchPortLinks.containsKey(npt)) return false;
         return true;
     }
 
-    protected long getOpenflowDomainId(long switchId) {
+    protected DatapathId getOpenflowDomainId(DatapathId switchId) {
         Cluster c = switchClusterMap.get(switchId);
         if (c == null) return switchId;
         return c.getId();
     }
 
-    protected long getL2DomainId(long switchId) {
+    protected DatapathId getL2DomainId(DatapathId switchId) {
         return getOpenflowDomainId(switchId);
     }
 
-    protected Set<Long> getSwitchesInOpenflowDomain(long switchId) {
+    protected Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId 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<Long> nodes = new HashSet<Long>();
+            Set<DatapathId> nodes = new HashSet<DatapathId>();
             nodes.add(switchId);
             return nodes;
         }
         return (c.getNodes());
     }
 
-    protected boolean inSameOpenflowDomain(long switch1, long switch2) {
+    protected boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2) {
         Cluster c1 = switchClusterMap.get(switch1);
         Cluster c2 = switchClusterMap.get(switch2);
         if (c1 != null && c2 != null)
-            return (c1.getId() == c2.getId());
-        return (switch1 == switch2);
+            return (c1.getId().equals(c2.getId()));
+        return (switch1.equals(switch2));
     }
 
-    public boolean isAllowed(long sw, short portId) {
+    public boolean isAllowed(DatapathId sw, OFPort portId) {
         return true;
     }
 
     protected boolean
-    isIncomingBroadcastAllowedOnSwitchPort(long sw, short portId) {
+    isIncomingBroadcastAllowedOnSwitchPort(DatapathId sw, OFPort portId) {
         if (isInternalToOpenflowDomain(sw, portId)) {
-            long clusterId = getOpenflowDomainId(sw);
+        	DatapathId clusterId = getOpenflowDomainId(sw);
             NodePortTuple npt = new NodePortTuple(sw, portId);
             if (clusterBroadcastNodePorts.get(clusterId).contains(npt))
                 return true;
@@ -781,52 +782,52 @@ public class TopologyInstance {
         return true;
     }
 
-    public boolean isConsistent(long oldSw, short oldPort, long newSw,
-                                short newPort) {
+    public boolean isConsistent(DatapathId oldSw, OFPort oldPort, DatapathId newSw,
+                                OFPort newPort) {
         if (isInternalToOpenflowDomain(newSw, newPort)) return true;
-        return (oldSw == newSw && oldPort == newPort);
+        return (oldSw.equals(newSw) && oldPort.equals(newPort));
     }
 
     protected Set<NodePortTuple>
-    getBroadcastNodePortsInCluster(long sw) {
-        long clusterId = getOpenflowDomainId(sw);
+    getBroadcastNodePortsInCluster(DatapathId sw) {
+    	DatapathId clusterId = getOpenflowDomainId(sw);
         return clusterBroadcastNodePorts.get(clusterId);
     }
 
-    public boolean inSameBroadcastDomain(long s1, short p1, long s2, short p2) {
+    public boolean inSameBroadcastDomain(DatapathId s1, OFPort p1, DatapathId s2, OFPort p2) {
         return false;
     }
 
-    public boolean inSameL2Domain(long switch1, long switch2) {
+    public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2) {
         return inSameOpenflowDomain(switch1, switch2);
     }
 
-    public NodePortTuple getOutgoingSwitchPort(long src, short srcPort,
-                                               long dst, short dstPort) {
+    public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
+    		DatapathId dst, OFPort dstPort) {
         // Use this function to redirect traffic if needed.
         return new NodePortTuple(dst, dstPort);
     }
 
-    public NodePortTuple getIncomingSwitchPort(long src, short srcPort,
-                                               long dst, short dstPort) {
+    public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
+    		DatapathId dst, OFPort dstPort) {
         // Use this function to reinject traffic from a
         // different port if needed.
         return new NodePortTuple(src, srcPort);
     }
 
-    public Set<Long> getSwitches() {
+    public Set<DatapathId> getSwitches() {
         return switches;
     }
 
-    public Set<Short> getPortsWithLinks(long sw) {
+    public Set<OFPort> getPortsWithLinks(DatapathId sw) {
         return switchPorts.get(sw);
     }
 
-    public Set<Short> getBroadcastPorts(long targetSw, long src, short srcPort) {
-        Set<Short> result = new HashSet<Short>();
-        long clusterId = getOpenflowDomainId(targetSw);
+    public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort) {
+        Set<OFPort> result = new HashSet<OFPort>();
+        DatapathId clusterId = getOpenflowDomainId(targetSw);
         for(NodePortTuple npt: clusterBroadcastNodePorts.get(clusterId)) {
-            if (npt.getNodeId() == targetSw) {
+            if (npt.getNodeId().equals(targetSw)) {
                 result.add(npt.getPortId());
             }
         }
@@ -834,15 +835,13 @@ public class TopologyInstance {
     }
 
     public NodePortTuple
-    getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst,
-                                    short dstPort) {
-        // TODO Auto-generated method stub
+    getAllowedOutgoingBroadcastPort(DatapathId src, OFPort srcPort, DatapathId dst,
+                                    OFPort dstPort) {
         return null;
     }
 
     public NodePortTuple
-    getAllowedIncomingBroadcastPort(long src, short srcPort) {
-        // TODO Auto-generated method stub
+    getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort) {
         return null;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
index 25b91464a1dd7aa8213e4987a0d0bf77abc6d39a..605dc65f6e4435bfc77947504f09402024edb7a6 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
@@ -16,7 +16,6 @@
 
 package net.floodlightcontroller.topology;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -33,31 +32,27 @@ 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;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.util.SingletonTask;
-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.debugcounter.NullDebugCounter;
 import net.floodlightcontroller.debugevent.IDebugEventService;
-import net.floodlightcontroller.debugevent.IEventUpdater;
-import net.floodlightcontroller.debugevent.NullDebugEvent;
+import net.floodlightcontroller.debugevent.IEventCategory;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
 import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
-import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.floodlightcontroller.packet.BSN;
@@ -70,13 +65,17 @@ import net.floodlightcontroller.routing.Route;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.topology.web.TopologyWebRoutable;
 
-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.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.OFVersion;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -86,1465 +85,1451 @@ import org.slf4j.LoggerFactory;
  * through the topology.
  */
 @LogMessageCategory("Network Topology")
-public class TopologyManager implements
-        IFloodlightModule, ITopologyService,
-        IRoutingService, ILinkDiscoveryListener,
-        IOFMessageListener {
-
-    protected static Logger log = LoggerFactory.getLogger(TopologyManager.class);
-
-    public static final String MODULE_NAME = "topology";
-
-    public static final String CONTEXT_TUNNEL_ENABLED =
-            "com.bigswitch.floodlight.topologymanager.tunnelEnabled";
-
-    /**
-     * Role of the controller.
-     */
-    private Role role;
-
-    /**
-     * Set of ports for each switch
-     */
-    protected Map<Long, Set<Short>> switchPorts;
-
-    /**
-     * Set of links organized by node port tuple
-     */
-    protected Map<NodePortTuple, Set<Link>> switchPortLinks;
-
-    /**
-     * Set of direct links
-     */
-    protected Map<NodePortTuple, Set<Link>> directLinks;
-
-    /**
-     * set of links that are broadcast domain links.
-     */
-    protected Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks;
-
-    /**
-     * set of tunnel links
-     */
-    protected Set<NodePortTuple> tunnelPorts;
-
-    protected ILinkDiscoveryService linkDiscovery;
-    protected IThreadPoolService threadPool;
-    protected IFloodlightProviderService floodlightProvider;
-    protected IRestApiService restApi;
-    protected IDebugCounterService debugCounters;
-
-    // Modules that listen to our updates
-    protected ArrayList<ITopologyListener> topologyAware;
-
-    protected BlockingQueue<LDUpdate> ldUpdates;
-
-    // These must be accessed using getCurrentInstance(), not directly
-    protected TopologyInstance currentInstance;
-    protected TopologyInstance currentInstanceWithoutTunnels;
-
-    protected SingletonTask newInstanceTask;
-    private Date lastUpdateTime;
-
-    /**
-     * Flag that indicates if links (direct/tunnel/multihop links) were
-     * updated as part of LDUpdate.
-     */
-    protected boolean linksUpdated;
-    /**
-     * Flag that indicates if direct or tunnel links were updated as
-     * part of LDUpdate.
-     */
-    protected boolean dtLinksUpdated;
-
-    /** Flag that indicates if tunnel ports were updated or not
-     */
-    protected boolean tunnelPortsUpdated;
-
-    protected int TOPOLOGY_COMPUTE_INTERVAL_MS = 500;
-
-    private IHAListener haListener;
-
-    /**
-     *  Debug Counters
-     */
-    protected static final String PACKAGE = TopologyManager.class.getPackage().getName();
-    protected IDebugCounter ctrIncoming;
-
-    /**
-     * Debug Events
-     */
-    protected IDebugEventService debugEvents;
-
-    /*
-     * Topology Event Updater
-     */
-    protected IEventUpdater<TopologyEvent> evTopology;
-
-    /**
-     * Topology Information exposed for a Topology related event - used inside
-     * the BigTopologyEvent class
-     */
-    protected class TopologyEventInfo {
-        private final int numOpenflowClustersWithTunnels;
-        private final int numOpenflowClustersWithoutTunnels;
-        private final Map<Long, List<NodePortTuple>> externalPortsMap;
-        private final int numTunnelPorts;
-        public TopologyEventInfo(int numOpenflowClustersWithTunnels,
-                                 int numOpenflowClustersWithoutTunnels,
-                                 Map<Long, List<NodePortTuple>> externalPortsMap,
-                                 int numTunnelPorts) {
-            super();
-            this.numOpenflowClustersWithTunnels = numOpenflowClustersWithTunnels;
-            this.numOpenflowClustersWithoutTunnels = numOpenflowClustersWithoutTunnels;
-            this.externalPortsMap = externalPortsMap;
-            this.numTunnelPorts = numTunnelPorts;
-        }
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder();
-            builder.append("# Openflow Clusters:");
-            builder.append(" { With Tunnels: ");
-            builder.append(numOpenflowClustersWithTunnels);
-            builder.append(" Without Tunnels: ");
-            builder.append(numOpenflowClustersWithoutTunnels);
-            builder.append(" }");
-            builder.append(", # External Clusters: ");
-            int numExternalClusters = externalPortsMap.size();
-            builder.append(numExternalClusters);
-            if (numExternalClusters > 0) {
-                builder.append(" { ");
-                int count = 0;
-                for (Long extCluster : externalPortsMap.keySet()) {
-                    builder.append("#" + extCluster + ":Ext Ports: ");
-                    builder.append(externalPortsMap.get(extCluster).size());
-                    if (++count < numExternalClusters) {
-                        builder.append(", ");
-                    } else {
-                        builder.append(" ");
-                    }
-                }
-                builder.append("}");
-            }
-            builder.append(", # Tunnel Ports: ");
-            builder.append(numTunnelPorts);
-            return builder.toString();
-        }
-    }
-
-    /**
-     * Topology Event class to track topology related events
-     */
-    protected class TopologyEvent {
-        @EventColumn(name = "Reason", description = EventFieldType.STRING)
-        private final String reason;
-        @EventColumn(name = "Topology Summary")
-        private final TopologyEventInfo topologyInfo;
-        public TopologyEvent(String reason,
-                TopologyEventInfo topologyInfo) {
-            super();
-            this.reason = reason;
-            this.topologyInfo = topologyInfo;
-        }
-    }
-
-   //  Getter/Setter methods
-    /**
-     * Get the time interval for the period topology updates, if any.
-     * The time returned is in milliseconds.
-     * @return
-     */
-    public int getTopologyComputeInterval() {
-        return TOPOLOGY_COMPUTE_INTERVAL_MS;
-    }
-
-    /**
-     * Set the time interval for the period topology updates, if any.
-     * The time is in milliseconds.
-     * @return
-     */
-    public void setTopologyComputeInterval(int time_ms) {
-        TOPOLOGY_COMPUTE_INTERVAL_MS = time_ms;
-    }
-
-    /**
-     * Thread for recomputing topology.  The thread is always running,
-     * however the function applyUpdates() has a blocking call.
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Error in topology instance task thread",
-            explanation="An unknown error occured in the topology " +
-            		"discovery module.",
-            recommendation=LogMessageDoc.CHECK_CONTROLLER)
-    protected class UpdateTopologyWorker implements Runnable {
-        @Override
-        public void run() {
-            try {
-                if (ldUpdates.peek() != null)
-                    updateTopology();
-                handleMiscellaneousPeriodicEvents();
-            }
-            catch (Exception e) {
-                log.error("Error in topology instance task thread", e);
-            } finally {
-                if (floodlightProvider.getRole() != Role.SLAVE)
-                    newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
-                                           TimeUnit.MILLISECONDS);
-            }
-        }
-    }
-
-    // To be used for adding any periodic events that's required by topology.
-    protected void handleMiscellaneousPeriodicEvents() {
-        return;
-    }
-
-    public boolean updateTopology() {
-        boolean newInstanceFlag;
-        linksUpdated = false;
-        dtLinksUpdated = false;
-        tunnelPortsUpdated = false;
-        List<LDUpdate> appliedUpdates = applyUpdates();
-        newInstanceFlag = createNewInstance("link-discovery-updates");
-        lastUpdateTime = new Date();
-        informListeners(appliedUpdates);
-        return newInstanceFlag;
-    }
-
-    // **********************
-    // ILinkDiscoveryListener
-    // **********************
-    @Override
-    public void linkDiscoveryUpdate(List<LDUpdate> updateList) {
-        if (log.isTraceEnabled()) {
-            log.trace("Queuing update: {}", updateList);
-        }
-        ldUpdates.addAll(updateList);
-    }
-
-    @Override
-    public void linkDiscoveryUpdate(LDUpdate update) {
-        if (log.isTraceEnabled()) {
-            log.trace("Queuing update: {}", update);
-        }
-        ldUpdates.add(update);
-    }
-
-    // ****************
-    // ITopologyService
-    // ****************
-
-    //
-    // ITopologyService interface methods
-    //
-    @Override
-    public Date getLastUpdateTime() {
-        return lastUpdateTime;
-    }
-
-    @Override
-    public void addListener(ITopologyListener listener) {
-        topologyAware.add(listener);
-    }
-
-    @Override
-    public boolean isAttachmentPointPort(long switchid, short port) {
-        return isAttachmentPointPort(switchid, port, true);
-    }
-
-    @Override
-    public boolean isAttachmentPointPort(long switchid, short port,
-                                         boolean tunnelEnabled) {
-
-        // If the switch port is 'tun-bsn' port, it is not
-        // an attachment point port, irrespective of whether
-        // a link is found through it or not.
-        if (linkDiscovery.isTunnelPort(switchid, port))
-            return false;
-
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-
-        // if the port is not attachment point port according to
-        // topology instance, then return false
-        if (ti.isAttachmentPointPort(switchid, port) == false)
-                return false;
-
-        // Check whether the port is a physical port. We should not learn
-        // attachment points on "special" ports.
-        if ((port & 0xff00) == 0xff00 && port != (short)0xfffe) return false;
-
-        // Make sure that the port is enabled.
-        IOFSwitch sw = floodlightProvider.getSwitch(switchid);
-        if (sw == null) return false;
-        return (sw.portEnabled(port));
-    }
-
-    @Override
-    public long getOpenflowDomainId(long switchId) {
-        return getOpenflowDomainId(switchId, true);
-    }
-
-    @Override
-    public long getOpenflowDomainId(long switchId, boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.getOpenflowDomainId(switchId);
-    }
-
-    @Override
-    public long getL2DomainId(long switchId) {
-        return getL2DomainId(switchId, true);
-    }
-
-    @Override
-    public long getL2DomainId(long switchId, boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.getL2DomainId(switchId);
-    }
-
-    @Override
-    public boolean inSameOpenflowDomain(long switch1, long switch2) {
-        return inSameOpenflowDomain(switch1, switch2, true);
-    }
-
-    @Override
-    public boolean inSameOpenflowDomain(long switch1, long switch2,
-                                        boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.inSameOpenflowDomain(switch1, switch2);
-    }
-
-    @Override
-    public boolean isAllowed(long sw, short portId) {
-        return isAllowed(sw, portId, true);
-    }
-
-    @Override
-    public boolean isAllowed(long sw, short portId, boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.isAllowed(sw, portId);
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    @Override
-    public boolean isIncomingBroadcastAllowed(long sw, short portId) {
-        return isIncomingBroadcastAllowed(sw, portId, true);
-    }
-
-    @Override
-    public boolean isIncomingBroadcastAllowed(long sw, short portId,
-                                              boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.isIncomingBroadcastAllowedOnSwitchPort(sw, portId);
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    /** Get all the ports connected to the switch */
-    @Override
-    public Set<Short> getPortsWithLinks(long sw) {
-        return getPortsWithLinks(sw, true);
-    }
-
-    /** Get all the ports connected to the switch */
-    @Override
-    public Set<Short> getPortsWithLinks(long sw, boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.getPortsWithLinks(sw);
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    /** Get all the ports on the target switch (targetSw) on which a
-     * broadcast packet must be sent from a host whose attachment point
-     * is on switch port (src, srcPort).
-     */
-    @Override
-    public Set<Short> getBroadcastPorts(long targetSw,
-                                        long src, short srcPort) {
-        return getBroadcastPorts(targetSw, src, srcPort, true);
-    }
-
-    /** Get all the ports on the target switch (targetSw) on which a
-     * broadcast packet must be sent from a host whose attachment point
-     * is on switch port (src, srcPort).
-     */
-    @Override
-    public Set<Short> getBroadcastPorts(long targetSw,
-                                        long src, short srcPort,
-                                        boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.getBroadcastPorts(targetSw, src, srcPort);
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    @Override
-    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(long src, short srcPort,
-                                               long dst, short dstPort,
-                                               boolean tunnelEnabled) {
-        // Use this function to redirect traffic if needed.
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.getOutgoingSwitchPort(src, srcPort,
-                                                     dst, dstPort);
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    @Override
-    public NodePortTuple getIncomingSwitchPort(long src, short srcPort,
-                                               long dst, short dstPort) {
-        return getIncomingSwitchPort(src, srcPort, dst, dstPort, true);
-    }
-
-    @Override
-    public NodePortTuple getIncomingSwitchPort(long src, short srcPort,
-                                               long dst, short dstPort,
-                                               boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.getIncomingSwitchPort(src, srcPort,
-                                                     dst, dstPort);
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    /**
-     * Checks if the two switchports belong to the same broadcast domain.
-     */
-    @Override
-    public boolean isInSameBroadcastDomain(long s1, short p1, long s2,
-                                           short p2) {
-        return isInSameBroadcastDomain(s1, p1, s2, p2, true);
-
-    }
-
-    @Override
-    public boolean isInSameBroadcastDomain(long s1, short p1,
-                                           long s2, short p2,
-                                           boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.inSameBroadcastDomain(s1, p1, s2, p2);
-
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    /**
-     * Checks if the switchport is a broadcast domain port or not.
-     */
-    @Override
-    public boolean isBroadcastDomainPort(long sw, short port) {
-        return isBroadcastDomainPort(sw, port, true);
-    }
-
-    @Override
-    public boolean isBroadcastDomainPort(long sw, short port,
-                                         boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.isBroadcastDomainPort(new NodePortTuple(sw, port));
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    /**
-     * Checks if the new attachment point port is consistent with the
-     * old attachment point port.
-     */
-    @Override
-    public boolean isConsistent(long oldSw, short oldPort,
-                                long newSw, short newPort) {
-        return isConsistent(oldSw, oldPort,
-                                            newSw, newPort, true);
-    }
-
-    @Override
-    public boolean isConsistent(long oldSw, short oldPort,
-                                long newSw, short newPort,
-                                boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.isConsistent(oldSw, oldPort, newSw, newPort);
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    /**
-     * Checks if the two switches are in the same Layer 2 domain.
-     */
-    @Override
-    public boolean inSameL2Domain(long switch1, long switch2) {
-        return inSameL2Domain(switch1, switch2, true);
-    }
-
-    @Override
-    public boolean inSameL2Domain(long switch1, long switch2,
-                                  boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.inSameL2Domain(switch1, switch2);
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    @Override
-    public NodePortTuple getAllowedOutgoingBroadcastPort(long src,
-                                                         short srcPort,
-                                                         long dst,
-                                                         short dstPort) {
-        return getAllowedOutgoingBroadcastPort(src, srcPort,
-                                               dst, dstPort, true);
-    }
-
-    @Override
-    public NodePortTuple getAllowedOutgoingBroadcastPort(long src,
-                                                         short srcPort,
-                                                         long dst,
-                                                         short dstPort,
-                                                         boolean tunnelEnabled){
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.getAllowedOutgoingBroadcastPort(src, srcPort,
-                                                  dst, dstPort);
-    }
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    @Override
-    public NodePortTuple
-    getAllowedIncomingBroadcastPort(long src, short srcPort) {
-        return getAllowedIncomingBroadcastPort(src,srcPort, true);
-    }
-
-    @Override
-    public NodePortTuple
-    getAllowedIncomingBroadcastPort(long src, short srcPort,
-                                    boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.getAllowedIncomingBroadcastPort(src,srcPort);
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-    @Override
-    public Set<Long> getSwitchesInOpenflowDomain(long switchDPID) {
-        return getSwitchesInOpenflowDomain(switchDPID, true);
-    }
-
-    @Override
-    public Set<Long> getSwitchesInOpenflowDomain(long switchDPID,
-                                                 boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.getSwitchesInOpenflowDomain(switchDPID);
-    }
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public Set<NodePortTuple> getBroadcastDomainPorts() {
-        return portBroadcastDomainLinks.keySet();
-    }
-
-    @Override
-    public Set<NodePortTuple> getTunnelPorts() {
-        return tunnelPorts;
-    }
-
-    @Override
-    public Set<NodePortTuple> getBlockedPorts() {
-        Set<NodePortTuple> bp;
-        Set<NodePortTuple> blockedPorts =
-                new HashSet<NodePortTuple>();
-
-        // As we might have two topologies, simply get the union of
-        // both of them and send it.
-        bp = getCurrentInstance(true).getBlockedPorts();
-        if (bp != null)
-            blockedPorts.addAll(bp);
-
-        bp = getCurrentInstance(false).getBlockedPorts();
-        if (bp != null)
-            blockedPorts.addAll(bp);
-
-        return blockedPorts;
-    }
-    ////////////////////////////////////////////////////////////////////////
-    ////////////////////////////////////////////////////////////////////////
-
-    // ***************
-    // IRoutingService
-    // ***************
-
-    @Override
-    public Route getRoute(long src, long dst, long cookie) {
-        return getRoute(src, dst, cookie, true);
-    }
-
-    @Override
-    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(long src, short srcPort, long dst, short dstPort, long cookie) {
-        return getRoute(src, srcPort, dst, dstPort, cookie, true);
-    }
-
-    @Override
-    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(long src, long dst) {
-        return routeExists(src, dst, true);
-    }
-
-    @Override
-    public boolean routeExists(long src, long dst, boolean tunnelEnabled) {
-        TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-        return ti.routeExists(src, dst);
-    }
-
-    @Override
-    public ArrayList<Route> getRoutes(long srcDpid, long dstDpid,
-                                      boolean tunnelEnabled) {
-        // Floodlight supports single path routing now
-
-        // return single path now
-        ArrayList<Route> result=new ArrayList<Route>();
-        result.add(getRoute(srcDpid, dstDpid, 0, tunnelEnabled));
-        return result;
-    }
-
-    // ******************
-    // IOFMessageListener
-    // ******************
-
-    @Override
-    public String getName() {
-        return MODULE_NAME;
-    }
-
-    @Override
-    public boolean isCallbackOrderingPrereq(OFType type, String name) {
-        return "linkdiscovery".equals(name);
-    }
-
-    @Override
-    public boolean isCallbackOrderingPostreq(OFType type, String name) {
-        return false;
-    }
-
-    @Override
-    public Command receive(IOFSwitch sw, OFMessage msg,
-                           FloodlightContext cntx) {
-        switch (msg.getType()) {
-            case PACKET_IN:
-                ctrIncoming.updateCounterNoFlush();
-                return this.processPacketInMessage(sw,
-                                                   (OFPacketIn) msg, cntx);
-            default:
-                break;
-        }
-
-        return Command.CONTINUE;
-    }
-
-    // ***************
-    // IHAListener
-    // ***************
-
-    private class HAListenerDelegate implements IHAListener {
-        @Override
-        public void transitionToMaster() {
-            role = Role.MASTER;
-            log.debug("Re-computing topology due " +
-                    "to HA change from SLAVE->MASTER");
-            newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
-                                       TimeUnit.MILLISECONDS);
-        }
-
-        @Override
-        public void controllerNodeIPsChanged(
-                                             Map<String, String> curControllerNodeIPs,
-                                             Map<String, String> addedControllerNodeIPs,
-                                             Map<String, String> removedControllerNodeIPs) {
-            // no-op
-        }
-
-        @Override
-        public String getName() {
-            return TopologyManager.this.getName();
-        }
-
-        @Override
-        public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
-                                                String name) {
-            return "linkdiscovery".equals(name) ||
-                    "tunnelmanager".equals(name);
-        }
-
-        @Override
-        public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
-                                                 String name) {
-            // TODO Auto-generated method stub
-            return false;
-        }
-    }
-
-    // *****************
-    // IFloodlightModule
-    // *****************
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l =
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(ITopologyService.class);
-        l.add(IRoutingService.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(ITopologyService.class, this);
-        m.put(IRoutingService.class, this);
-        return m;
-    }
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>>
-            getModuleDependencies() {
-        Collection<Class<? extends IFloodlightService>> l =
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(ILinkDiscoveryService.class);
-        l.add(IThreadPoolService.class);
-        l.add(IFloodlightProviderService.class);
-        l.add(ICounterStoreService.class);
-        l.add(IRestApiService.class);
-        return l;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context)
-            throws FloodlightModuleException {
-        linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
-        threadPool = context.getServiceImpl(IThreadPoolService.class);
-        floodlightProvider =
-                context.getServiceImpl(IFloodlightProviderService.class);
-        restApi = context.getServiceImpl(IRestApiService.class);
-        debugCounters = context.getServiceImpl(IDebugCounterService.class);
-        debugEvents = context.getServiceImpl(IDebugEventService.class);
-
-        switchPorts = new HashMap<Long,Set<Short>>();
-        switchPortLinks = new HashMap<NodePortTuple, Set<Link>>();
-        directLinks = new HashMap<NodePortTuple, Set<Link>>();
-        portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>();
-        tunnelPorts = new HashSet<NodePortTuple>();
-        topologyAware = new ArrayList<ITopologyListener>();
-        ldUpdates = new LinkedBlockingQueue<LDUpdate>();
-        haListener = new HAListenerDelegate();
-        registerTopologyDebugCounters();
-        registerTopologyDebugEvents();
-    }
-
-    protected void registerTopologyDebugEvents() throws FloodlightModuleException {
-        if (debugEvents == null) {
-            debugEvents = new NullDebugEvent();
-        }
-        try {
-            evTopology =
-                debugEvents.registerEvent(PACKAGE, "topologyevent",
-                                          "Topology Computation",
-                                          EventType.ALWAYS_LOG,
-                                          TopologyEvent.class, 100);
-        } catch (MaxEventsRegistered e) {
-            throw new FloodlightModuleException("Max events registered", e);
-        }
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        clearCurrentTopology();
-        // Initialize role to floodlight provider role.
-        this.role = floodlightProvider.getRole();
-
-        ScheduledExecutorService ses = threadPool.getScheduledExecutor();
-        newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker());
-
-        if (role != Role.SLAVE)
-            newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
-                                   TimeUnit.MILLISECONDS);
-
-        linkDiscovery.addListener(this);
-        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-        floodlightProvider.addHAListener(this.haListener);
-        addRestletRoutable();
-    }
-
-    private void registerTopologyDebugCounters() throws FloodlightModuleException {
-        if (debugCounters == null) {
-            log.error("Debug Counter Service not found.");
-            debugCounters = new NullDebugCounter();
-        }
-        try {
-            ctrIncoming = debugCounters.registerCounter(PACKAGE, "incoming",
-                "All incoming packets seen by this module",
-                CounterType.ALWAYS_COUNT);
-        } catch (CounterException e) {
-            throw new FloodlightModuleException(e.getMessage());
-        }
-    }
-
-    protected void addRestletRoutable() {
-        restApi.addRestletRoutable(new TopologyWebRoutable());
-    }
-
-    // ****************
-    // Internal methods
-    // ****************
-    /**
-     * If the packet-in switch port is disabled for all data traffic, then
-     * the packet will be dropped.  Otherwise, the packet will follow the
-     * normal processing chain.
-     * @param sw
-     * @param pi
-     * @param cntx
-     * @return
-     */
-    protected Command dropFilter(long sw, OFPacketIn pi,
-                                             FloodlightContext cntx) {
-        Command result = Command.CONTINUE;
-        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, port);
-                result = Command.STOP;
-            }
-        }
-        return result;
-    }
-
-    /**
-     * TODO This method must be moved to a layer below forwarding
-     * so that anyone can use it.
-     * @param packetData
-     * @param sw
-     * @param ports
-     * @param cntx
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Failed to clear all flows on switch {switch}",
-            explanation="An I/O error occured while trying send " +
-            		"topology discovery packet",
-            recommendation=LogMessageDoc.CHECK_SWITCH)
-    public void doMultiActionPacketOut(byte[] packetData, IOFSwitch sw,
-                                       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);
-
-        List<OFAction> actions = new ArrayList<OFAction>();
-        for(short p: ports) {
-            actions.add(new OFActionOutput(p, (short) 0));
-        }
-
-        // set actions
-        po.setActions(actions);
-        // set action length
-        po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH *
-                ports.size()));
-        // set buffer-id to BUFFER_ID_NONE
-        po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
-        // set in-port to OFPP_NONE
-        po.setInPort(OFPort.OFPP_NONE.getValue());
-
-        // set packet data
-        po.setPacketData(packetData);
-
-        // compute and set packet length.
-        short poLength = (short)(OFPacketOut.MINIMUM_LENGTH +
-                po.getActionsLength() +
-                packetData.length);
-
-        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, po});
-            }
-            sw.write(po, cntx);
-
-        } catch (IOException e) {
-            log.error("Failure writing packet out", e);
-        }
-    }
-
-    /**
-     * Get the set of ports to eliminate for sending out BDDP.  The method
-     * returns all the ports that are suppressed for link discovery on the
-     * switch.
-     * packets.
-     * @param sid
-     * @return
-     */
-    protected Set<Short> getPortsToEliminateForBDDP(long sid) {
-        Set<NodePortTuple> suppressedNptList = linkDiscovery.getSuppressLLDPsInfo();
-        if (suppressedNptList == null) return null;
-
-        Set<Short> resultPorts = new HashSet<Short>();
-        for(NodePortTuple npt: suppressedNptList) {
-            if (npt.getNodeId() == sid) {
-                resultPorts.add(npt.getPortId());
-            }
-        }
-
-        return resultPorts;
-    }
-
-    /**
-     * The BDDP packets are forwarded out of all the ports out of an
-     * openflowdomain.  Get all the switches in the same openflow
-     * domain as the sw (disabling tunnels).  Then get all the
-     * external switch ports and send these packets out.
-     * @param sw
-     * @param pi
-     * @param cntx
-     */
-    protected void doFloodBDDP(long pinSwitch, OFPacketIn pi,
-                               FloodlightContext cntx) {
-
-        TopologyInstance ti = getCurrentInstance(false);
-
-        Set<Long> switches = ti.getSwitchesInOpenflowDomain(pinSwitch);
-
-        if (switches == null)
-        {
-            // indicates no links are connected to the switches
-            switches = new HashSet<Long>();
-            switches.add(pinSwitch);
-        }
-
-        for(long sid: switches) {
-            IOFSwitch sw = floodlightProvider.getSwitch(sid);
-            if (sw == null) continue;
-            Collection<Short> enabledPorts = sw.getEnabledPortNumbers();
-            if (enabledPorts == null)
-                continue;
-            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<Short> portsKnownToTopo = ti.getPortsWithLinks(sid);
-
-            if (portsKnownToTopo != null) {
-                for(short p: portsKnownToTopo) {
-                    NodePortTuple npt =
-                            new NodePortTuple(sid, p);
-                    if (ti.isBroadcastDomainPort(npt) == false) {
-                        ports.remove(p);
-                    }
-                }
-            }
-
-            Set<Short> portsToEliminate = getPortsToEliminateForBDDP(sid);
-            if (portsToEliminate != null) {
-                ports.removeAll(portsToEliminate);
-            }
-
-            // remove the incoming switch port
-            if (pinSwitch == sid) {
-                ports.remove(pi.getInPort());
-            }
-
-            // we have all the switch ports to which we need to broadcast.
-            doMultiActionPacketOut(pi.getPacketData(), sw, ports, cntx);
-        }
-
-    }
-
-    protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi,
-                                             FloodlightContext cntx) {
-
-        // get the packet-in switch.
-        Ethernet eth =
-                IFloodlightProviderService.bcStore.
-                get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-
-        if (eth.getPayload() instanceof BSN) {
-            BSN bsn = (BSN) eth.getPayload();
-            if (bsn == null) return Command.STOP;
-            if (bsn.getPayload() == null) return Command.STOP;
-
-            // It could be a packet other than BSN LLDP, therefore
-            // continue with the regular processing.
-            if (bsn.getPayload() instanceof LLDP == false)
-                return Command.CONTINUE;
-
-            doFloodBDDP(sw.getId(), pi, cntx);
-            return Command.STOP;
-        } else {
-            return dropFilter(sw.getId(), pi, cntx);
-        }
-    }
-
-    /**
-     * Updates concerning switch disconnect and port down are not processed.
-     * LinkDiscoveryManager is expected to process those messages and send
-     * multiple link removed messages.  However, all the updates from
-     * LinkDiscoveryManager would be propagated to the listeners of topology.
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Error reading link discovery update.",
-            explanation="Unable to process link discovery update",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    public List<LDUpdate> applyUpdates() {
-        List<LDUpdate> appliedUpdates = new ArrayList<LDUpdate>();
-        LDUpdate update = null;
-        while (ldUpdates.peek() != null) {
-            try {
-                update = ldUpdates.take();
-            } catch (Exception e) {
-                log.error("Error reading link discovery update.", e);
-            }
-            if (log.isTraceEnabled()) {
-                log.trace("Applying update: {}", update);
-            }
-
-            switch (update.getOperation()) {
-            case LINK_UPDATED:
-                addOrUpdateLink(update.getSrc(), update.getSrcPort(),
-                        update.getDst(), update.getDstPort(),
-                        update.getType());
-                break;
-            case LINK_REMOVED:
-                removeLink(update.getSrc(), update.getSrcPort(),
-                        update.getDst(), update.getDstPort());
-                break;
-            case SWITCH_UPDATED:
-                addOrUpdateSwitch(update.getSrc());
-                break;
-            case SWITCH_REMOVED:
-                removeSwitch(update.getSrc());
-                break;
-            case TUNNEL_PORT_ADDED:
-                addTunnelPort(update.getSrc(), update.getSrcPort());
-                break;
-            case TUNNEL_PORT_REMOVED:
-                removeTunnelPort(update.getSrc(), update.getSrcPort());
-                break;
-            case PORT_UP: case PORT_DOWN:
-                break;
-            }
-            // Add to the list of applied updates.
-            appliedUpdates.add(update);
-        }
-        return (Collections.unmodifiableList(appliedUpdates));
-    }
-
-    protected void addOrUpdateSwitch(long sw) {
-        // nothing to do here for the time being.
-        return;
-    }
-
-    public void addTunnelPort(long sw, short port) {
-        NodePortTuple npt = new NodePortTuple(sw, port);
-        tunnelPorts.add(npt);
-        tunnelPortsUpdated = true;
-    }
-
-    public void removeTunnelPort(long sw, short port) {
-        NodePortTuple npt = new NodePortTuple(sw, port);
-        tunnelPorts.remove(npt);
-        tunnelPortsUpdated = true;
-    }
-
-    public boolean createNewInstance() {
-        return createNewInstance("internal");
-    }
-
-    /**
-     * This function computes a new topology instance.
-     * It ignores links connected to all broadcast domain ports
-     * and tunnel ports. The method returns if a new instance of
-     * topology was created or not.
-     */
-    protected boolean createNewInstance(String reason) {
-        Set<NodePortTuple> blockedPorts = new HashSet<NodePortTuple>();
-
-        if (!linksUpdated) return false;
-
-        Map<NodePortTuple, Set<Link>> openflowLinks;
-        openflowLinks =
-                new HashMap<NodePortTuple, Set<Link>>();
-        Set<NodePortTuple> nptList = switchPortLinks.keySet();
-
-        if (nptList != null) {
-            for(NodePortTuple npt: nptList) {
-                Set<Link> linkSet = switchPortLinks.get(npt);
-                if (linkSet == null) continue;
-                openflowLinks.put(npt, new HashSet<Link>(linkSet));
-            }
-        }
-
-        // Identify all broadcast domain ports.
-        // Mark any port that has inconsistent set of links
-        // as broadcast domain ports as well.
-        Set<NodePortTuple> broadcastDomainPorts =
-                identifyBroadcastDomainPorts();
-
-        // Remove all links incident on broadcast domain ports.
-        for(NodePortTuple npt: broadcastDomainPorts) {
-            if (switchPortLinks.get(npt) == null) continue;
-            for(Link link: switchPortLinks.get(npt)) {
-                removeLinkFromStructure(openflowLinks, link);
-            }
-        }
-
-        // Remove all tunnel links.
-        for(NodePortTuple npt: tunnelPorts) {
-            if (switchPortLinks.get(npt) == null) continue;
-            for(Link link: switchPortLinks.get(npt)) {
-                removeLinkFromStructure(openflowLinks, link);
-            }
-        }
-
-        TopologyInstance nt = new TopologyInstance(switchPorts,
-                                                   blockedPorts,
-                                                   openflowLinks,
-                                                   broadcastDomainPorts,
-                                                   tunnelPorts);
-        nt.compute();
-        // We set the instances with and without tunnels to be identical.
-        // If needed, we may compute them differently.
-        currentInstance = nt;
-        currentInstanceWithoutTunnels = nt;
-
-        TopologyEventInfo topologyInfo =
-                new TopologyEventInfo(0, nt.getClusters().size(),
-                                      new HashMap<Long, List<NodePortTuple>>(),
-                                      0);
-        evTopology.updateEventWithFlush(new TopologyEvent(reason,
-                                                          topologyInfo));
-        return true;
-    }
-
-    /**
-     *  We expect every switch port to have at most two links.  Both these
-     *  links must be unidirectional links connecting to the same switch port.
-     *  If not, we will mark this as a broadcast domain port.
-     */
-    protected Set<NodePortTuple> identifyBroadcastDomainPorts() {
-
-        Set<NodePortTuple> broadcastDomainPorts =
-                new HashSet<NodePortTuple>();
-        broadcastDomainPorts.addAll(this.portBroadcastDomainLinks.keySet());
-
-        Set<NodePortTuple> additionalNpt =
-                new HashSet<NodePortTuple>();
-
-        // Copy switchPortLinks
-        Map<NodePortTuple, Set<Link>> spLinks =
-                new HashMap<NodePortTuple, Set<Link>>();
-        for(NodePortTuple npt: switchPortLinks.keySet()) {
-            spLinks.put(npt, new HashSet<Link>(switchPortLinks.get(npt)));
-        }
-
-        for(NodePortTuple npt: spLinks.keySet()) {
-            Set<Link> links = spLinks.get(npt);
-            boolean bdPort = false;
-            ArrayList<Link> linkArray = new ArrayList<Link>();
-            if (links.size() > 2) {
-                bdPort = true;
-            } else if (links.size() == 2) {
-                for(Link l: links) {
-                    linkArray.add(l);
-                }
-                // now, there should be two links in [0] and [1].
-                Link l1 = linkArray.get(0);
-                Link l2 = linkArray.get(1);
-
-                // check if these two are symmetric.
-                if (l1.getSrc() != l2.getDst() ||
-                        l1.getSrcPort() != l2.getDstPort() ||
-                        l1.getDst() != l2.getSrc() ||
-                        l1.getDstPort() != l2.getSrcPort()) {
-                    bdPort = true;
-                }
-            }
-
-            if (bdPort && (broadcastDomainPorts.contains(npt) == false)) {
-                additionalNpt.add(npt);
-            }
-        }
-
-        if (additionalNpt.size() > 0) {
-            log.warn("The following switch ports have multiple " +
-                    "links incident on them, so these ports will be treated " +
-                    " as braodcast domain ports. {}", additionalNpt);
-
-            broadcastDomainPorts.addAll(additionalNpt);
-        }
-        return broadcastDomainPorts;
-    }
-
-
-
-    public void informListeners(List<LDUpdate> linkUpdates) {
-
-        if (role != null && role != Role.MASTER)
-            return;
-
-        for(int i=0; i<topologyAware.size(); ++i) {
-            ITopologyListener listener = topologyAware.get(i);
-            listener.topologyChanged(linkUpdates);
-        }
-    }
-
-    public void addSwitch(long sid) {
-        if (switchPorts.containsKey(sid) == false) {
-            switchPorts.put(sid, new HashSet<Short>());
-        }
-    }
-
-    private void addPortToSwitch(long s, short p) {
-        addSwitch(s);
-        switchPorts.get(s).add(p);
-    }
-
-    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;
-
-        // Check if any tunnel ports need to be removed.
-        for(NodePortTuple npt: tunnelPorts) {
-            if (npt.getNodeId() == sid) {
-                removeTunnelPort(npt.getNodeId(), npt.getPortId());
-            }
-        }
-
-        Set<Link> linksToRemove = new HashSet<Link>();
-        for(Short p: switchPorts.get(sid)) {
-            NodePortTuple n1 = new NodePortTuple(sid, p);
-            linksToRemove.addAll(switchPortLinks.get(n1));
-        }
-
-        if (linksToRemove.isEmpty()) return;
-
-        for(Link link: linksToRemove) {
-            removeLink(link);
-        }
-    }
-
-    /**
-     * Add the given link to the data structure.  Returns true if a link was
-     * added.
-     * @param s
-     * @param l
-     * @return
-     */
-    private boolean addLinkToStructure(Map<NodePortTuple,
-                                       Set<Link>> s, Link l) {
-        boolean result1 = false, result2 = false;
-
-        NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
-        NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort());
-
-        if (s.get(n1) == null) {
-            s.put(n1, new HashSet<Link>());
-        }
-        if (s.get(n2) == null) {
-            s.put(n2, new HashSet<Link>());
-        }
-        result1 = s.get(n1).add(l);
-        result2 = s.get(n2).add(l);
-
-        return (result1 || result2);
-    }
-
-    /**
-     * Delete the given link from the data strucure.  Returns true if the
-     * link was deleted.
-     * @param s
-     * @param l
-     * @return
-     */
-    private boolean removeLinkFromStructure(Map<NodePortTuple,
-                                            Set<Link>> s, Link l) {
-
-        boolean result1 = false, result2 = false;
-        NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
-        NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort());
-
-        if (s.get(n1) != null) {
-            result1 = s.get(n1).remove(l);
-            if (s.get(n1).isEmpty()) s.remove(n1);
-        }
-        if (s.get(n2) != null) {
-            result2 = s.get(n2).remove(l);
-            if (s.get(n2).isEmpty()) s.remove(n2);
-        }
-        return result1 || result2;
-    }
-
-    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(long srcId, short srcPort, long dstId,
-                                short dstPort, LinkType type) {
-        Link link = new Link(srcId, srcPort, dstId, dstPort);
-
-        if (type.equals(LinkType.MULTIHOP_LINK)) {
-            addPortToSwitch(srcId, srcPort);
-            addPortToSwitch(dstId, dstPort);
-            addLinkToStructure(switchPortLinks, link);
-
-            addLinkToStructure(portBroadcastDomainLinks, link);
-            dtLinksUpdated = removeLinkFromStructure(directLinks, link);
-            linksUpdated = true;
-        } else if (type.equals(LinkType.DIRECT_LINK)) {
-            addPortToSwitch(srcId, srcPort);
-            addPortToSwitch(dstId, dstPort);
-            addLinkToStructure(switchPortLinks, link);
-
-            addLinkToStructure(directLinks, link);
-            removeLinkFromStructure(portBroadcastDomainLinks, link);
-            dtLinksUpdated = true;
-            linksUpdated = true;
-        } else if (type.equals(LinkType.TUNNEL)) {
-            addOrUpdateTunnelLink(srcId, srcPort, dstId, dstPort);
-        }
-    }
-
-    public void removeLink(Link link)  {
-        linksUpdated = true;
-        dtLinksUpdated = removeLinkFromStructure(directLinks, link);
-        removeLinkFromStructure(portBroadcastDomainLinks, link);
-        removeLinkFromStructure(switchPortLinks, link);
-
-        NodePortTuple srcNpt =
-                new NodePortTuple(link.getSrc(), link.getSrcPort());
-        NodePortTuple dstNpt =
-                new NodePortTuple(link.getDst(), link.getDstPort());
-
-        // Remove switch ports if there are no links through those switch ports
-        if (switchPortLinks.get(srcNpt) == null) {
-            if (switchPorts.get(srcNpt.getNodeId()) != null)
-                switchPorts.get(srcNpt.getNodeId()).remove(srcNpt.getPortId());
-        }
-        if (switchPortLinks.get(dstNpt) == null) {
-            if (switchPorts.get(dstNpt.getNodeId()) != null)
-                switchPorts.get(dstNpt.getNodeId()).remove(dstNpt.getPortId());
-        }
-
-        // Remove the node if no ports are present
-        if (switchPorts.get(srcNpt.getNodeId())!=null &&
-                switchPorts.get(srcNpt.getNodeId()).isEmpty()) {
-            switchPorts.remove(srcNpt.getNodeId());
-        }
-        if (switchPorts.get(dstNpt.getNodeId())!=null &&
-                switchPorts.get(dstNpt.getNodeId()).isEmpty()) {
-            switchPorts.remove(dstNpt.getNodeId());
-        }
-    }
-
-    public void removeLink(long srcId, short srcPort,
-                           long dstId, short dstPort) {
-        Link link = new Link(srcId, srcPort, dstId, dstPort);
-        removeLink(link);
-    }
-
-    public void clear() {
-        switchPorts.clear();
-        tunnelPorts.clear();
-        switchPortLinks.clear();
-        portBroadcastDomainLinks.clear();
-        directLinks.clear();
-    }
-
-    /**
-    * Clears the current topology. Note that this does NOT
-    * send out updates.
-    */
-    public void clearCurrentTopology() {
-        this.clear();
-        linksUpdated = true;
-        dtLinksUpdated = true;
-        tunnelPortsUpdated = true;
-        createNewInstance("startup");
-        lastUpdateTime = new Date();
-    }
-
-    /**
-     * Getters.  No Setters.
-     */
-    public Map<Long, Set<Short>> getSwitchPorts() {
-        return switchPorts;
-    }
-
-    public Map<NodePortTuple, Set<Link>> getSwitchPortLinks() {
-        return switchPortLinks;
-    }
-
-    public Map<NodePortTuple, Set<Link>> getPortBroadcastDomainLinks() {
-        return portBroadcastDomainLinks;
-    }
-
-    public TopologyInstance getCurrentInstance(boolean tunnelEnabled) {
-        if (tunnelEnabled)
-            return currentInstance;
-        else return this.currentInstanceWithoutTunnels;
-    }
-
-    public TopologyInstance getCurrentInstance() {
-        return this.getCurrentInstance(true);
-    }
-
-    /**
-     *  Switch methods
-     */
-    @Override
-    public Set<Short> getPorts(long sw) {
-        IOFSwitch iofSwitch = floodlightProvider.getSwitch(sw);
-        if (iofSwitch == null) return Collections.emptySet();
-
-        Collection<Short> ofpList = iofSwitch.getEnabledPortNumbers();
-        if (ofpList == null) return Collections.emptySet();
-
-        Set<Short> ports = new HashSet<Short>(ofpList);
-        Set<Short> qPorts = linkDiscovery.getQuarantinedPorts(sw);
-        if (qPorts != null)
-            ports.removeAll(qPorts);
-
-        return ports;
-    }
+public class TopologyManager implements IFloodlightModule, ITopologyService, IRoutingService, ILinkDiscoveryListener, IOFMessageListener {
+
+	protected static Logger log = LoggerFactory.getLogger(TopologyManager.class);
+
+	public static final String MODULE_NAME = "topology";
+
+	public static final String CONTEXT_TUNNEL_ENABLED =
+			"com.bigswitch.floodlight.topologymanager.tunnelEnabled";
+
+	/**
+	 * Role of the controller.
+	 */
+	private HARole role;
+
+	/**
+	 * Set of ports for each switch
+	 */
+	protected Map<DatapathId, Set<OFPort>> switchPorts;
+
+	/**
+	 * Set of links organized by node port tuple
+	 */
+	protected Map<NodePortTuple, Set<Link>> switchPortLinks;
+
+	/**
+	 * Set of direct links
+	 */
+	protected Map<NodePortTuple, Set<Link>> directLinks;
+
+	/**
+	 * set of links that are broadcast domain links.
+	 */
+	protected Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks;
+
+	/**
+	 * set of tunnel links
+	 */
+	protected Set<NodePortTuple> tunnelPorts;
+
+	protected ILinkDiscoveryService linkDiscoveryService;
+	protected IThreadPoolService threadPoolService;
+	protected IFloodlightProviderService floodlightProviderService;
+	protected IOFSwitchService switchService;
+	protected IRestApiService restApiService;
+	protected IDebugCounterService debugCounterService;
+
+	// Modules that listen to our updates
+	protected ArrayList<ITopologyListener> topologyAware;
+
+	protected BlockingQueue<LDUpdate> ldUpdates;
+
+	// These must be accessed using getCurrentInstance(), not directly
+	protected TopologyInstance currentInstance;
+	protected TopologyInstance currentInstanceWithoutTunnels;
+
+	protected SingletonTask newInstanceTask;
+	private Date lastUpdateTime;
+
+	/**
+	 * Flag that indicates if links (direct/tunnel/multihop links) were
+	 * updated as part of LDUpdate.
+	 */
+	protected boolean linksUpdated;
+	/**
+	 * Flag that indicates if direct or tunnel links were updated as
+	 * part of LDUpdate.
+	 */
+	protected boolean dtLinksUpdated;
+
+	/** Flag that indicates if tunnel ports were updated or not
+	 */
+	protected boolean tunnelPortsUpdated;
+
+	protected int TOPOLOGY_COMPUTE_INTERVAL_MS = 500;
+
+	private IHAListener haListener;
+
+	/**
+	 *  Debug Counters
+	 */
+	protected static final String PACKAGE = TopologyManager.class.getPackage().getName();
+	protected IDebugCounter ctrIncoming;
+
+	/**
+	 * Debug Events
+	 */
+	protected IDebugEventService debugEventService;
+
+	/*
+	 * Topology Event Updater
+	 */
+	protected IEventCategory<TopologyEvent> eventCategory;
+
+	/**
+	 * Topology Information exposed for a Topology related event - used inside
+	 * the BigTopologyEvent class
+	 */
+	protected class TopologyEventInfo {
+		private final int numOpenflowClustersWithTunnels;
+		private final int numOpenflowClustersWithoutTunnels;
+		private final Map<DatapathId, List<NodePortTuple>> externalPortsMap;
+		private final int numTunnelPorts;
+		public TopologyEventInfo(int numOpenflowClustersWithTunnels,
+				int numOpenflowClustersWithoutTunnels,
+				Map<DatapathId, List<NodePortTuple>> externalPortsMap,
+				int numTunnelPorts) {
+			super();
+			this.numOpenflowClustersWithTunnels = numOpenflowClustersWithTunnels;
+			this.numOpenflowClustersWithoutTunnels = numOpenflowClustersWithoutTunnels;
+			this.externalPortsMap = externalPortsMap;
+			this.numTunnelPorts = numTunnelPorts;
+		}
+		@Override
+		public String toString() {
+			StringBuilder builder = new StringBuilder();
+			builder.append("# Openflow Clusters:");
+			builder.append(" { With Tunnels: ");
+			builder.append(numOpenflowClustersWithTunnels);
+			builder.append(" Without Tunnels: ");
+			builder.append(numOpenflowClustersWithoutTunnels);
+			builder.append(" }");
+			builder.append(", # External Clusters: ");
+			int numExternalClusters = externalPortsMap.size();
+			builder.append(numExternalClusters);
+			if (numExternalClusters > 0) {
+				builder.append(" { ");
+				int count = 0;
+				for (DatapathId extCluster : externalPortsMap.keySet()) {
+					builder.append("#" + extCluster + ":Ext Ports: ");
+					builder.append(externalPortsMap.get(extCluster).size());
+					if (++count < numExternalClusters) {
+						builder.append(", ");
+					} else {
+						builder.append(" ");
+					}
+				}
+				builder.append("}");
+			}
+			builder.append(", # Tunnel Ports: ");
+			builder.append(numTunnelPorts);
+			return builder.toString();
+		}
+	}
+
+	/**
+	 * Topology Event class to track topology related events
+	 */
+	protected class TopologyEvent {
+		@EventColumn(name = "Reason", description = EventFieldType.STRING)
+		private final String reason;
+		@EventColumn(name = "Topology Summary")
+		private final TopologyEventInfo topologyInfo;
+		public TopologyEvent(String reason,
+				TopologyEventInfo topologyInfo) {
+			super();
+			this.reason = reason;
+			this.topologyInfo = topologyInfo;
+		}
+	}
+
+	//  Getter/Setter methods
+	/**
+	 * Get the time interval for the period topology updates, if any.
+	 * The time returned is in milliseconds.
+	 * @return
+	 */
+	public int getTopologyComputeInterval() {
+		return TOPOLOGY_COMPUTE_INTERVAL_MS;
+	}
+
+	/**
+	 * Set the time interval for the period topology updates, if any.
+	 * The time is in milliseconds.
+	 * @return
+	 */
+	public void setTopologyComputeInterval(int time_ms) {
+		TOPOLOGY_COMPUTE_INTERVAL_MS = time_ms;
+	}
+
+	/**
+	 * Thread for recomputing topology.  The thread is always running,
+	 * however the function applyUpdates() has a blocking call.
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="Error in topology instance task thread",
+			explanation="An unknown error occured in the topology " +
+					"discovery module.",
+					recommendation=LogMessageDoc.CHECK_CONTROLLER)
+	protected class UpdateTopologyWorker implements Runnable {
+		@Override
+		public void run() {
+			try {
+				if (ldUpdates.peek() != null)
+					updateTopology();
+				handleMiscellaneousPeriodicEvents();
+			}
+			catch (Exception e) {
+				log.error("Error in topology instance task thread", e);
+			} finally {
+				if (floodlightProviderService.getRole() != HARole.STANDBY)
+					newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
+							TimeUnit.MILLISECONDS);
+			}
+		}
+	}
+
+	// To be used for adding any periodic events that's required by topology.
+	protected void handleMiscellaneousPeriodicEvents() {
+		return;
+	}
+
+	public boolean updateTopology() {
+		boolean newInstanceFlag;
+		linksUpdated = false;
+		dtLinksUpdated = false;
+		tunnelPortsUpdated = false;
+		List<LDUpdate> appliedUpdates = applyUpdates();
+		newInstanceFlag = createNewInstance("link-discovery-updates");
+		lastUpdateTime = new Date();
+		informListeners(appliedUpdates);
+		return newInstanceFlag;
+	}
+
+	// **********************
+	// ILinkDiscoveryListener
+	// **********************
+	@Override
+	public void linkDiscoveryUpdate(List<LDUpdate> updateList) {
+		if (log.isTraceEnabled()) {
+			log.trace("Queuing update: {}", updateList);
+		}
+		ldUpdates.addAll(updateList);
+	}
+
+	@Override
+	public void linkDiscoveryUpdate(LDUpdate update) {
+		if (log.isTraceEnabled()) {
+			log.trace("Queuing update: {}", update);
+		}
+		ldUpdates.add(update);
+	}
+
+	// ****************
+	// ITopologyService
+	// ****************
+
+	//
+	// ITopologyService interface methods
+	//
+	@Override
+	public Date getLastUpdateTime() {
+		return lastUpdateTime;
+	}
+
+	@Override
+	public void addListener(ITopologyListener listener) {
+		topologyAware.add(listener);
+	}
+
+	@Override
+	public boolean isAttachmentPointPort(DatapathId switchid, OFPort port) {
+		return isAttachmentPointPort(switchid, port, true);
+	}
+
+	@Override
+	public boolean isAttachmentPointPort(DatapathId switchid, OFPort port, boolean tunnelEnabled) {
+
+		// If the switch port is 'tun-bsn' port, it is not
+		// an attachment point port, irrespective of whether
+		// a link is found through it or not.
+		if (linkDiscoveryService.isTunnelPort(switchid, port))
+			return false;
+
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+
+		// if the port is not attachment point port according to
+		// topology instance, then return false
+		if (ti.isAttachmentPointPort(switchid, port) == false)
+			return false;
+
+		// 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;
+
+		// Make sure that the port is enabled.
+		IOFSwitch sw = switchService.getActiveSwitch(switchid);
+		if (sw == null) return false;
+		return (sw.portEnabled(port));
+	}
+
+	@Override
+	public DatapathId getOpenflowDomainId(DatapathId switchId) {
+		return getOpenflowDomainId(switchId, true);
+	}
+
+	@Override
+	public DatapathId getOpenflowDomainId(DatapathId switchId, boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getOpenflowDomainId(switchId);
+	}
+
+	@Override
+	public DatapathId getL2DomainId(DatapathId switchId) {
+		return getL2DomainId(switchId, true);
+	}
+
+	@Override
+	public DatapathId getL2DomainId(DatapathId switchId, boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getL2DomainId(switchId);
+	}
+
+	@Override
+	public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2) {
+		return inSameOpenflowDomain(switch1, switch2, true);
+	}
+
+	@Override
+	public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.inSameOpenflowDomain(switch1, switch2);
+	}
+
+	@Override
+	public boolean isAllowed(DatapathId sw, OFPort portId) {
+		return isAllowed(sw, portId, true);
+	}
+
+	@Override
+	public boolean isAllowed(DatapathId sw, OFPort portId, boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.isAllowed(sw, portId);
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	@Override
+	public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId) {
+		return isIncomingBroadcastAllowed(sw, portId, true);
+	}
+
+	@Override
+	public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.isIncomingBroadcastAllowedOnSwitchPort(sw, portId);
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	/** Get all the ports connected to the switch */
+	@Override
+	public Set<OFPort> getPortsWithLinks(DatapathId sw) {
+		return getPortsWithLinks(sw, true);
+	}
+
+	/** Get all the ports connected to the switch */
+	@Override
+	public Set<OFPort> getPortsWithLinks(DatapathId sw, boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getPortsWithLinks(sw);
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	/** Get all the ports on the target switch (targetSw) on which a
+	 * broadcast packet must be sent from a host whose attachment point
+	 * is on switch port (src, srcPort).
+	 */
+	@Override
+	public Set<OFPort> getBroadcastPorts(DatapathId targetSw,
+			DatapathId src, OFPort srcPort) {
+		return getBroadcastPorts(targetSw, src, srcPort, true);
+	}
+
+	/** Get all the ports on the target switch (targetSw) on which a
+	 * broadcast packet must be sent from a host whose attachment point
+	 * is on switch port (src, srcPort).
+	 */
+	@Override
+	public Set<OFPort> getBroadcastPorts(DatapathId targetSw,
+			DatapathId src, OFPort srcPort,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getBroadcastPorts(targetSw, src, srcPort);
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	@Override
+	public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
+			DatapathId dst, OFPort 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,
+			boolean tunnelEnabled) {
+		// Use this function to redirect traffic if needed.
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getOutgoingSwitchPort(src, srcPort,
+				dst, dstPort);
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	@Override
+	public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
+			DatapathId dst, OFPort dstPort) {
+		return getIncomingSwitchPort(src, srcPort, dst, dstPort, true);
+	}
+
+	@Override
+	public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
+			DatapathId dst, OFPort dstPort,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getIncomingSwitchPort(src, srcPort,
+				dst, dstPort);
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	/**
+	 * Checks if the two switchports belong to the same broadcast domain.
+	 */
+	@Override
+	public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1, DatapathId s2,
+			OFPort p2) {
+		return isInSameBroadcastDomain(s1, p1, s2, p2, true);
+
+	}
+
+	@Override
+	public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1,
+			DatapathId s2, OFPort p2,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.inSameBroadcastDomain(s1, p1, s2, p2);
+
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	/**
+	 * Checks if the switchport is a broadcast domain port or not.
+	 */
+	@Override
+	public boolean isBroadcastDomainPort(DatapathId sw, OFPort port) {
+		return isBroadcastDomainPort(sw, port, true);
+	}
+
+	@Override
+	public boolean isBroadcastDomainPort(DatapathId sw, OFPort port,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.isBroadcastDomainPort(new NodePortTuple(sw, port));
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	/**
+	 * Checks if the new attachment point port is consistent with the
+	 * old attachment point port.
+	 */
+	@Override
+	public boolean isConsistent(DatapathId oldSw, OFPort oldPort,
+			DatapathId newSw, OFPort newPort) {
+		return isConsistent(oldSw, oldPort,
+				newSw, newPort, true);
+	}
+
+	@Override
+	public boolean isConsistent(DatapathId oldSw, OFPort oldPort,
+			DatapathId newSw, OFPort newPort,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.isConsistent(oldSw, oldPort, newSw, newPort);
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	/**
+	 * Checks if the two switches are in the same Layer 2 domain.
+	 */
+	@Override
+	public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2) {
+		return inSameL2Domain(switch1, switch2, true);
+	}
+
+	@Override
+	public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.inSameL2Domain(switch1, switch2);
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	@Override
+	public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src,
+			OFPort srcPort,
+			DatapathId dst,
+			OFPort dstPort) {
+		return getAllowedOutgoingBroadcastPort(src, srcPort,
+				dst, dstPort, true);
+	}
+
+	@Override
+	public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src,
+			OFPort srcPort,
+			DatapathId dst,
+			OFPort dstPort,
+			boolean tunnelEnabled){
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getAllowedOutgoingBroadcastPort(src, srcPort,
+				dst, dstPort);
+	}
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	@Override
+	public NodePortTuple
+	getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort) {
+		return getAllowedIncomingBroadcastPort(src,srcPort, true);
+	}
+
+	@Override
+	public NodePortTuple
+	getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getAllowedIncomingBroadcastPort(src,srcPort);
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+	@Override
+	public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID) {
+		return getSwitchesInOpenflowDomain(switchDPID, true);
+	}
+
+	@Override
+	public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getSwitchesInOpenflowDomain(switchDPID);
+	}
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+
+	@Override
+	public Set<NodePortTuple> getBroadcastDomainPorts() {
+		return portBroadcastDomainLinks.keySet();
+	}
+
+	@Override
+	public Set<NodePortTuple> getTunnelPorts() {
+		return tunnelPorts;
+	}
+
+	@Override
+	public Set<NodePortTuple> getBlockedPorts() {
+		Set<NodePortTuple> bp;
+		Set<NodePortTuple> blockedPorts =
+				new HashSet<NodePortTuple>();
+
+		// As we might have two topologies, simply get the union of
+		// both of them and send it.
+		bp = getCurrentInstance(true).getBlockedPorts();
+		if (bp != null)
+			blockedPorts.addAll(bp);
+
+		bp = getCurrentInstance(false).getBlockedPorts();
+		if (bp != null)
+			blockedPorts.addAll(bp);
+
+		return blockedPorts;
+	}
+	////////////////////////////////////////////////////////////////////////
+	////////////////////////////////////////////////////////////////////////
+
+	// ***************
+	// IRoutingService
+	// ***************
+
+	@Override
+	public Route getRoute(DatapathId src, DatapathId dst, U64 cookie) {
+		return getRoute(src, dst, cookie, true);
+	}
+
+	@Override
+	public Route getRoute(DatapathId src, DatapathId dst, U64 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, U64 cookie) {
+		return getRoute(src, srcPort, dst, dstPort, cookie, true);
+	}
+
+	@Override
+	public Route getRoute(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort, U64 cookie,
+			boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.getRoute(null, src, srcPort, dst, dstPort, cookie);
+	}
+
+	@Override
+	public boolean routeExists(DatapathId src, DatapathId dst) {
+		return routeExists(src, dst, true);
+	}
+
+	@Override
+	public boolean routeExists(DatapathId src, DatapathId dst, boolean tunnelEnabled) {
+		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
+		return ti.routeExists(src, dst);
+	}
+
+	@Override
+	public ArrayList<Route> getRoutes(DatapathId srcDpid, DatapathId dstDpid,
+			boolean tunnelEnabled) {
+		// Floodlight supports single path routing now
+
+		// return single path now
+		ArrayList<Route> result=new ArrayList<Route>();
+		result.add(getRoute(srcDpid, dstDpid, U64.of(0), tunnelEnabled));
+		return result;
+	}
+
+	// ******************
+	// IOFMessageListener
+	// ******************
+
+	@Override
+	public String getName() {
+		return MODULE_NAME;
+	}
+
+	@Override
+	public boolean isCallbackOrderingPrereq(OFType type, String name) {
+		return "linkdiscovery".equals(name);
+	}
+
+	@Override
+	public boolean isCallbackOrderingPostreq(OFType type, String name) {
+		return false;
+	}
+
+	@Override
+	public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+		switch (msg.getType()) {
+		case PACKET_IN:
+			ctrIncoming.increment();
+			return this.processPacketInMessage(sw, (OFPacketIn) msg, cntx);
+		default:
+			break;
+		}
+
+		return Command.CONTINUE;
+	}
+
+	// ***************
+	// IHAListener
+	// ***************
+
+	private class HAListenerDelegate implements IHAListener {
+		@Override
+		public void transitionToActive() {
+			role = HARole.ACTIVE;
+			log.debug("Re-computing topology due " +
+					"to HA change from STANDBY->ACTIVE");
+			newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
+					TimeUnit.MILLISECONDS);
+		}
+
+		@Override
+		public void controllerNodeIPsChanged(
+				Map<String, String> curControllerNodeIPs,
+				Map<String, String> addedControllerNodeIPs,
+				Map<String, String> removedControllerNodeIPs) {
+			// no-op
+		}
+
+		@Override
+		public String getName() {
+			return TopologyManager.this.getName();
+		}
+
+		@Override
+		public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
+				String name) {
+			return "linkdiscovery".equals(name) ||
+					"tunnelmanager".equals(name);
+		}
+
+		@Override
+		public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
+				String name) {
+			// TODO Auto-generated method stub
+			return false;
+		}
+
+		@Override
+		public void transitionToStandby() {
+			// TODO Auto-generated method stub
+
+		}
+	}
+
+	// *****************
+	// IFloodlightModule
+	// *****************
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		Collection<Class<? extends IFloodlightService>> l =
+				new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(ITopologyService.class);
+		l.add(IRoutingService.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(ITopologyService.class, this);
+		m.put(IRoutingService.class, this);
+		return m;
+	}
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>>
+	getModuleDependencies() {
+		Collection<Class<? extends IFloodlightService>> l =
+				new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(ILinkDiscoveryService.class);
+		l.add(IThreadPoolService.class);
+		l.add(IFloodlightProviderService.class);
+		l.add(IOFSwitchService.class);
+		l.add(IDebugCounterService.class);
+		l.add(IDebugEventService.class);
+		l.add(IRestApiService.class);
+		return l;
+	}
+
+	@Override
+	public void init(FloodlightModuleContext context)
+			throws FloodlightModuleException {
+		linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
+		threadPoolService = context.getServiceImpl(IThreadPoolService.class);
+		floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+		switchService = context.getServiceImpl(IOFSwitchService.class);
+		restApiService = context.getServiceImpl(IRestApiService.class);
+		debugCounterService = context.getServiceImpl(IDebugCounterService.class);
+		debugEventService = context.getServiceImpl(IDebugEventService.class);
+
+		switchPorts = new HashMap<DatapathId, Set<OFPort>>();
+		switchPortLinks = new HashMap<NodePortTuple, Set<Link>>();
+		directLinks = new HashMap<NodePortTuple, Set<Link>>();
+		portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>();
+		tunnelPorts = new HashSet<NodePortTuple>();
+		topologyAware = new ArrayList<ITopologyListener>();
+		ldUpdates = new LinkedBlockingQueue<LDUpdate>();
+		haListener = new HAListenerDelegate();
+		registerTopologyDebugCounters();
+		registerTopologyDebugEvents();
+	}
+
+	protected void registerTopologyDebugEvents() throws FloodlightModuleException {
+		if (debugEventService == null) {
+			log.error("debugEventService should not be null. Has IDebugEventService been loaded previously?");
+		}
+		eventCategory = debugEventService.buildEvent(TopologyEvent.class)
+				.setModuleName(PACKAGE)
+				.setEventName("topologyevent")
+				.setEventDescription("Topology Computation")
+				.setEventType(EventType.ALWAYS_LOG)
+				.setBufferCapacity(100)
+				.register();
+	}
+
+	@Override
+	public void startUp(FloodlightModuleContext context) {
+		clearCurrentTopology();
+		// Initialize role to floodlight provider role.
+		this.role = floodlightProviderService.getRole();
+
+		ScheduledExecutorService ses = threadPoolService.getScheduledExecutor();
+		newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker());
+
+		if (role != HARole.STANDBY)
+			newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
+					TimeUnit.MILLISECONDS);
+
+		linkDiscoveryService.addListener(this);
+		floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
+		floodlightProviderService.addHAListener(this.haListener);
+		addRestletRoutable();
+	}
+
+	private void registerTopologyDebugCounters() throws FloodlightModuleException {
+		if (debugCounterService == null) {
+			log.error("debugCounterService should not be null. Has IDebugEventService been loaded previously?");
+		}
+		debugCounterService.registerModule(PACKAGE);
+		ctrIncoming = debugCounterService.registerCounter(
+				PACKAGE, "incoming",
+				"All incoming packets seen by this module");
+	}
+
+	protected void addRestletRoutable() {
+		restApiService.addRestletRoutable(new TopologyWebRoutable());
+	}
+
+	// ****************
+	// Internal methods
+	// ****************
+	/**
+	 * If the packet-in switch port is disabled for all data traffic, then
+	 * the packet will be dropped.  Otherwise, the packet will follow the
+	 * normal processing chain.
+	 * @param sw
+	 * @param pi
+	 * @param cntx
+	 * @return
+	 */
+	protected Command dropFilter(DatapathId sw, OFPacketIn pi,
+			FloodlightContext cntx) {
+		Command result = Command.CONTINUE;
+		OFPort port = (pi.getVersion().compareTo(OFVersion.OF_13) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
+
+		// 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());
+				result = Command.STOP;
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * TODO This method must be moved to a layer below forwarding
+	 * so that anyone can use it.
+	 * @param packetData
+	 * @param sw
+	 * @param ports
+	 * @param cntx
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="Failed to clear all flows on switch {switch}",
+			explanation="An I/O error occured while trying send " +
+					"topology discovery packet",
+					recommendation=LogMessageDoc.CHECK_SWITCH)
+	public void doMultiActionPacketOut(byte[] packetData, IOFSwitch sw,
+			Set<OFPort> 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();
+		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));
+		}
+
+		// set actions
+		pob.setActions(actions);
+		// set action length
+		//po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * ports.size()));
+		// set buffer-id to BUFFER_ID_NONE
+		pob.setBufferId(OFBufferId.NO_BUFFER);
+		// set in-port to OFPP_NONE
+		pob.setInPort(OFPort.ZERO);
+
+		// set packet data
+		pob.setData(packetData);
+
+		// compute and set packet length.
+		//short poLength = (short)(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + packetData.length);
+
+		//po.setLength(poLength);
+
+		//ctrIncoming.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()});
+		}
+		sw.write(pob.build(), LogicalOFMessageCategory.MAIN);
+	}
+
+	/**
+	 * Get the set of ports to eliminate for sending out BDDP.  The method
+	 * returns all the ports that are suppressed for link discovery on the
+	 * switch.
+	 * packets.
+	 * @param sid
+	 * @return
+	 */
+	protected Set<OFPort> getPortsToEliminateForBDDP(DatapathId sid) {
+		Set<NodePortTuple> suppressedNptList = linkDiscoveryService.getSuppressLLDPsInfo();
+		if (suppressedNptList == null) return null;
+
+		Set<OFPort> resultPorts = new HashSet<OFPort>();
+		for(NodePortTuple npt: suppressedNptList) {
+			if (npt.getNodeId() == sid) {
+				resultPorts.add(npt.getPortId());
+			}
+		}
+
+		return resultPorts;
+	}
+
+	/**
+	 * The BDDP packets are forwarded out of all the ports out of an
+	 * openflowdomain.  Get all the switches in the same openflow
+	 * domain as the sw (disabling tunnels).  Then get all the
+	 * external switch ports and send these packets out.
+	 * @param sw
+	 * @param pi
+	 * @param cntx
+	 */
+	protected void doFloodBDDP(DatapathId pinSwitch, OFPacketIn pi,
+			FloodlightContext cntx) {
+
+		TopologyInstance ti = getCurrentInstance(false);
+
+		Set<DatapathId> switches = ti.getSwitchesInOpenflowDomain(pinSwitch);
+
+		if (switches == null)
+		{
+			// indicates no links are connected to the switches
+			switches = new HashSet<DatapathId>();
+			switches.add(pinSwitch);
+		}
+
+		for(DatapathId sid: switches) {
+			IOFSwitch sw = switchService.getSwitch(sid);
+			if (sw == null) continue;
+			Collection<OFPort> enabledPorts = sw.getEnabledPortNumbers();
+			if (enabledPorts == null)
+				continue;
+			Set<OFPort> ports = new HashSet<OFPort>();
+			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);
+
+			if (portsKnownToTopo != null) {
+				for(OFPort p: portsKnownToTopo) {
+					NodePortTuple npt =
+							new NodePortTuple(sid, p);
+					if (ti.isBroadcastDomainPort(npt) == false) {
+						ports.remove(p);
+					}
+				}
+			}
+
+			Set<OFPort> portsToEliminate = getPortsToEliminateForBDDP(sid);
+			if (portsToEliminate != null) {
+				ports.removeAll(portsToEliminate);
+			}
+
+			// remove the incoming switch port
+			if (pinSwitch == sid) {
+				ports.remove(pi.getInPort());
+			}
+
+			// we have all the switch ports to which we need to broadcast.
+			doMultiActionPacketOut(pi.getData(), sw, ports, cntx);
+		}
+
+	}
+
+	protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
+		// get the packet-in switch.
+		Ethernet eth =
+				IFloodlightProviderService.bcStore.
+				get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+
+		if (eth.getPayload() instanceof BSN) {
+			BSN bsn = (BSN) eth.getPayload();
+			if (bsn == null) return Command.STOP;
+			if (bsn.getPayload() == null) return Command.STOP;
+
+			// It could be a packet other than BSN LLDP, therefore
+			// continue with the regular processing.
+			if (bsn.getPayload() instanceof LLDP == false)
+				return Command.CONTINUE;
+
+			doFloodBDDP(sw.getId(), pi, cntx);
+			return Command.STOP;
+		} else {
+			return dropFilter(sw.getId(), pi, cntx);
+		}
+	}
+
+	/**
+	 * Updates concerning switch disconnect and port down are not processed.
+	 * LinkDiscoveryManager is expected to process those messages and send
+	 * multiple link removed messages.  However, all the updates from
+	 * LinkDiscoveryManager would be propagated to the listeners of topology.
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="Error reading link discovery update.",
+			explanation="Unable to process link discovery update",
+			recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+	public List<LDUpdate> applyUpdates() {
+		List<LDUpdate> appliedUpdates = new ArrayList<LDUpdate>();
+		LDUpdate update = null;
+		while (ldUpdates.peek() != null) {
+			try {
+				update = ldUpdates.take();
+			} catch (Exception e) {
+				log.error("Error reading link discovery update.", e);
+			}
+			if (log.isTraceEnabled()) {
+				log.trace("Applying update: {}", update);
+			}
+
+			switch (update.getOperation()) {
+			case LINK_UPDATED:
+				addOrUpdateLink(update.getSrc(), update.getSrcPort(),
+						update.getDst(), update.getDstPort(),
+						update.getType());
+				break;
+			case LINK_REMOVED:
+				removeLink(update.getSrc(), update.getSrcPort(),
+						update.getDst(), update.getDstPort());
+				break;
+			case SWITCH_UPDATED:
+				addOrUpdateSwitch(update.getSrc());
+				break;
+			case SWITCH_REMOVED:
+				removeSwitch(update.getSrc());
+				break;
+			case TUNNEL_PORT_ADDED:
+				addTunnelPort(update.getSrc(), update.getSrcPort());
+				break;
+			case TUNNEL_PORT_REMOVED:
+				removeTunnelPort(update.getSrc(), update.getSrcPort());
+				break;
+			case PORT_UP: case PORT_DOWN:
+				break;
+			}
+			// Add to the list of applied updates.
+			appliedUpdates.add(update);
+		}
+		return (Collections.unmodifiableList(appliedUpdates));
+	}
+
+	protected void addOrUpdateSwitch(DatapathId sw) {
+		// nothing to do here for the time being.
+		return;
+	}
+
+	public void addTunnelPort(DatapathId sw, OFPort port) {
+		NodePortTuple npt = new NodePortTuple(sw, port);
+		tunnelPorts.add(npt);
+		tunnelPortsUpdated = true;
+	}
+
+	public void removeTunnelPort(DatapathId sw, OFPort port) {
+		NodePortTuple npt = new NodePortTuple(sw, port);
+		tunnelPorts.remove(npt);
+		tunnelPortsUpdated = true;
+	}
+
+	public boolean createNewInstance() {
+		return createNewInstance("internal");
+	}
+
+	/**
+	 * This function computes a new topology instance.
+	 * It ignores links connected to all broadcast domain ports
+	 * and tunnel ports. The method returns if a new instance of
+	 * topology was created or not.
+	 */
+	protected boolean createNewInstance(String reason) {
+		Set<NodePortTuple> blockedPorts = new HashSet<NodePortTuple>();
+
+		if (!linksUpdated) return false;
+
+		Map<NodePortTuple, Set<Link>> openflowLinks;
+		openflowLinks =
+				new HashMap<NodePortTuple, Set<Link>>();
+		Set<NodePortTuple> nptList = switchPortLinks.keySet();
+
+		if (nptList != null) {
+			for(NodePortTuple npt: nptList) {
+				Set<Link> linkSet = switchPortLinks.get(npt);
+				if (linkSet == null) continue;
+				openflowLinks.put(npt, new HashSet<Link>(linkSet));
+			}
+		}
+
+		// Identify all broadcast domain ports.
+		// Mark any port that has inconsistent set of links
+		// as broadcast domain ports as well.
+		Set<NodePortTuple> broadcastDomainPorts =
+				identifyBroadcastDomainPorts();
+
+		// Remove all links incident on broadcast domain ports.
+		for(NodePortTuple npt: broadcastDomainPorts) {
+			if (switchPortLinks.get(npt) == null) continue;
+			for(Link link: switchPortLinks.get(npt)) {
+				removeLinkFromStructure(openflowLinks, link);
+			}
+		}
+
+		// Remove all tunnel links.
+		for(NodePortTuple npt: tunnelPorts) {
+			if (switchPortLinks.get(npt) == null) continue;
+			for(Link link: switchPortLinks.get(npt)) {
+				removeLinkFromStructure(openflowLinks, link);
+			}
+		}
+
+		TopologyInstance nt = new TopologyInstance(switchPorts,
+				blockedPorts,
+				openflowLinks,
+				broadcastDomainPorts,
+				tunnelPorts);
+		nt.compute();
+		// We set the instances with and without tunnels to be identical.
+		// If needed, we may compute them differently.
+		currentInstance = nt;
+		currentInstanceWithoutTunnels = nt;
+
+		TopologyEventInfo topologyInfo =
+				new TopologyEventInfo(0, nt.getClusters().size(),
+						new HashMap<DatapathId, List<NodePortTuple>>(),
+						0);
+		eventCategory.newEventWithFlush(new TopologyEvent(reason, topologyInfo));
+		return true;
+	}
+
+	/**
+	 *  We expect every switch port to have at most two links.  Both these
+	 *  links must be unidirectional links connecting to the same switch port.
+	 *  If not, we will mark this as a broadcast domain port.
+	 */
+	protected Set<NodePortTuple> identifyBroadcastDomainPorts() {
+
+		Set<NodePortTuple> broadcastDomainPorts =
+				new HashSet<NodePortTuple>();
+		broadcastDomainPorts.addAll(this.portBroadcastDomainLinks.keySet());
+
+		Set<NodePortTuple> additionalNpt =
+				new HashSet<NodePortTuple>();
+
+		// Copy switchPortLinks
+		Map<NodePortTuple, Set<Link>> spLinks =
+				new HashMap<NodePortTuple, Set<Link>>();
+		for(NodePortTuple npt: switchPortLinks.keySet()) {
+			spLinks.put(npt, new HashSet<Link>(switchPortLinks.get(npt)));
+		}
+
+		for(NodePortTuple npt: spLinks.keySet()) {
+			Set<Link> links = spLinks.get(npt);
+			boolean bdPort = false;
+			ArrayList<Link> linkArray = new ArrayList<Link>();
+			if (links.size() > 2) {
+				bdPort = true;
+			} else if (links.size() == 2) {
+				for(Link l: links) {
+					linkArray.add(l);
+				}
+				// now, there should be two links in [0] and [1].
+				Link l1 = linkArray.get(0);
+				Link l2 = linkArray.get(1);
+
+				// check if these two are symmetric.
+				if (l1.getSrc() != l2.getDst() ||
+						l1.getSrcPort() != l2.getDstPort() ||
+						l1.getDst() != l2.getSrc() ||
+						l1.getDstPort() != l2.getSrcPort()) {
+					bdPort = true;
+				}
+			}
+
+			if (bdPort && (broadcastDomainPorts.contains(npt) == false)) {
+				additionalNpt.add(npt);
+			}
+		}
+
+		if (additionalNpt.size() > 0) {
+			log.warn("The following switch ports have multiple " +
+					"links incident on them, so these ports will be treated " +
+					" as braodcast domain ports. {}", additionalNpt);
+
+			broadcastDomainPorts.addAll(additionalNpt);
+		}
+		return broadcastDomainPorts;
+	}
+
+
+
+	public void informListeners(List<LDUpdate> linkUpdates) {
+
+		if (role != null && role != HARole.ACTIVE)
+			return;
+
+		for(int i=0; i < topologyAware.size(); ++i) {
+			ITopologyListener listener = topologyAware.get(i);
+			listener.topologyChanged(linkUpdates);
+		}
+	}
+
+	public void addSwitch(DatapathId sid) {
+		if (switchPorts.containsKey(sid) == false) {
+			switchPorts.put(sid, new HashSet<OFPort>());
+		}
+	}
+
+	private void addPortToSwitch(DatapathId s, OFPort p) {
+		addSwitch(s);
+		switchPorts.get(s).add(p);
+	}
+
+	public void removeSwitch(DatapathId sid) {
+		// Delete all the links in the switch, switch and all
+		// associated data should be deleted.
+		if (switchPorts.containsKey(sid) == false) return;
+
+		// Check if any tunnel ports need to be removed.
+		for(NodePortTuple npt: tunnelPorts) {
+			if (npt.getNodeId() == sid) {
+				removeTunnelPort(npt.getNodeId(), npt.getPortId());
+			}
+		}
+
+		Set<Link> linksToRemove = new HashSet<Link>();
+		for(OFPort p: switchPorts.get(sid)) {
+			NodePortTuple n1 = new NodePortTuple(sid, p);
+			linksToRemove.addAll(switchPortLinks.get(n1));
+		}
+
+		if (linksToRemove.isEmpty()) return;
+
+		for(Link link: linksToRemove) {
+			removeLink(link);
+		}
+	}
+
+	/**
+	 * Add the given link to the data structure.  Returns true if a link was
+	 * added.
+	 * @param s
+	 * @param l
+	 * @return
+	 */
+	private boolean addLinkToStructure(Map<NodePortTuple,
+			Set<Link>> s, Link l) {
+		boolean result1 = false, result2 = false;
+
+		NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
+		NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort());
+
+		if (s.get(n1) == null) {
+			s.put(n1, new HashSet<Link>());
+		}
+		if (s.get(n2) == null) {
+			s.put(n2, new HashSet<Link>());
+		}
+		result1 = s.get(n1).add(l);
+		result2 = s.get(n2).add(l);
+
+		return (result1 || result2);
+	}
+
+	/**
+	 * Delete the given link from the data strucure.  Returns true if the
+	 * link was deleted.
+	 * @param s
+	 * @param l
+	 * @return
+	 */
+	private boolean removeLinkFromStructure(Map<NodePortTuple,
+			Set<Link>> s, Link l) {
+
+		boolean result1 = false, result2 = false;
+		NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
+		NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort());
+
+		if (s.get(n1) != null) {
+			result1 = s.get(n1).remove(l);
+			if (s.get(n1).isEmpty()) s.remove(n1);
+		}
+		if (s.get(n2) != null) {
+			result2 = s.get(n2).remove(l);
+			if (s.get(n2).isEmpty()) s.remove(n2);
+		}
+		return result1 || result2;
+	}
+
+	protected void addOrUpdateTunnelLink(DatapathId srcId, OFPort srcPort, DatapathId dstId,
+			OFPort 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) {
+		Link link = new Link(srcId, srcPort, dstId, dstPort);
+
+		if (type.equals(LinkType.MULTIHOP_LINK)) {
+			addPortToSwitch(srcId, srcPort);
+			addPortToSwitch(dstId, dstPort);
+			addLinkToStructure(switchPortLinks, link);
+
+			addLinkToStructure(portBroadcastDomainLinks, link);
+			dtLinksUpdated = removeLinkFromStructure(directLinks, link);
+			linksUpdated = true;
+		} else if (type.equals(LinkType.DIRECT_LINK)) {
+			addPortToSwitch(srcId, srcPort);
+			addPortToSwitch(dstId, dstPort);
+			addLinkToStructure(switchPortLinks, link);
+
+			addLinkToStructure(directLinks, link);
+			removeLinkFromStructure(portBroadcastDomainLinks, link);
+			dtLinksUpdated = true;
+			linksUpdated = true;
+		} else if (type.equals(LinkType.TUNNEL)) {
+			addOrUpdateTunnelLink(srcId, srcPort, dstId, dstPort);
+		}
+	}
+
+	public void removeLink(Link link)  {
+		linksUpdated = true;
+		dtLinksUpdated = removeLinkFromStructure(directLinks, link);
+		removeLinkFromStructure(portBroadcastDomainLinks, link);
+		removeLinkFromStructure(switchPortLinks, link);
+
+		NodePortTuple srcNpt =
+				new NodePortTuple(link.getSrc(), link.getSrcPort());
+		NodePortTuple dstNpt =
+				new NodePortTuple(link.getDst(), link.getDstPort());
+
+		// Remove switch ports if there are no links through those switch ports
+		if (switchPortLinks.get(srcNpt) == null) {
+			if (switchPorts.get(srcNpt.getNodeId()) != null)
+				switchPorts.get(srcNpt.getNodeId()).remove(srcNpt.getPortId());
+		}
+		if (switchPortLinks.get(dstNpt) == null) {
+			if (switchPorts.get(dstNpt.getNodeId()) != null)
+				switchPorts.get(dstNpt.getNodeId()).remove(dstNpt.getPortId());
+		}
+
+		// Remove the node if no ports are present
+		if (switchPorts.get(srcNpt.getNodeId())!=null &&
+				switchPorts.get(srcNpt.getNodeId()).isEmpty()) {
+			switchPorts.remove(srcNpt.getNodeId());
+		}
+		if (switchPorts.get(dstNpt.getNodeId())!=null &&
+				switchPorts.get(dstNpt.getNodeId()).isEmpty()) {
+			switchPorts.remove(dstNpt.getNodeId());
+		}
+	}
+
+	public void removeLink(DatapathId srcId, OFPort srcPort,
+			DatapathId dstId, OFPort dstPort) {
+		Link link = new Link(srcId, srcPort, dstId, dstPort);
+		removeLink(link);
+	}
+
+	public void clear() {
+		switchPorts.clear();
+		tunnelPorts.clear();
+		switchPortLinks.clear();
+		portBroadcastDomainLinks.clear();
+		directLinks.clear();
+	}
+
+	/**
+	 * Clears the current topology. Note that this does NOT
+	 * send out updates.
+	 */
+	public void clearCurrentTopology() {
+		this.clear();
+		linksUpdated = true;
+		dtLinksUpdated = true;
+		tunnelPortsUpdated = true;
+		createNewInstance("startup");
+		lastUpdateTime = new Date();
+	}
+
+	/**
+	 * Getters.  No Setters.
+	 */
+	public Map<DatapathId, Set<OFPort>> getSwitchPorts() {
+		return switchPorts;
+	}
+
+	public Map<NodePortTuple, Set<Link>> getSwitchPortLinks() {
+		return switchPortLinks;
+	}
+
+	public Map<NodePortTuple, Set<Link>> getPortBroadcastDomainLinks() {
+		return portBroadcastDomainLinks;
+	}
+
+	public TopologyInstance getCurrentInstance(boolean tunnelEnabled) {
+		if (tunnelEnabled)
+			return currentInstance;
+		else return this.currentInstanceWithoutTunnels;
+	}
+
+	public TopologyInstance getCurrentInstance() {
+		return this.getCurrentInstance(true);
+	}
+
+	/**
+	 *  Switch methods
+	 */
+	@Override
+	public Set<OFPort> getPorts(DatapathId sw) {
+		IOFSwitch iofSwitch = switchService.getSwitch(sw);
+		if (iofSwitch == null) return Collections.emptySet();
+
+		Collection<OFPort> ofpList = iofSwitch.getEnabledPortNumbers();
+		if (ofpList == null) return Collections.emptySet();
+
+		Set<OFPort> ports = new HashSet<OFPort>(ofpList);
+		Set<OFPort> qPorts = linkDiscoveryService.getQuarantinedPorts(sw);
+		if (qPorts != null)
+			ports.removeAll(qPorts);
+
+		return ports;
+	}
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java b/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java
index af1467a2d5544d47290ce879191455ab7263be2d..fe2e699a72661dde0f1dfb896f9b54a467d6ec92 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java
@@ -20,10 +20,12 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
-import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.topology.NodePortTuple;
 
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 
@@ -32,24 +34,24 @@ public class EnabledPortsResource extends ServerResource {
     public List<NodePortTuple> retrieve() {
         List<NodePortTuple> result = new ArrayList<NodePortTuple>();
 
-        IFloodlightProviderService floodlightProvider =
-                (IFloodlightProviderService)getContext().getAttributes().
-                get(IFloodlightProviderService.class.getCanonicalName());
+        IOFSwitchService switchService =
+                (IOFSwitchService) getContext().getAttributes().
+                get(IOFSwitchService.class.getCanonicalName());
 
-        ITopologyService topology=
-                (ITopologyService)getContext().getAttributes().
+        ITopologyService topologyService =
+                (ITopologyService) getContext().getAttributes().
                 get(ITopologyService.class.getCanonicalName());
 
-        if (floodlightProvider == null || topology == null)
+        if (switchService == null || topologyService == null)
             return result;
 
-        Set<Long> switches = floodlightProvider.getAllSwitchDpids();
+        Set<DatapathId> switches = switchService.getAllSwitchDpids();
         if (switches == null) return result;
 
-        for(long sw: switches) {
-            Set<Short> ports = topology.getPorts(sw);
+        for(DatapathId sw: switches) {
+            Set<OFPort> ports = topologyService.getPorts(sw);
             if (ports == null) continue;
-            for(short p: ports) {
+            for(OFPort p: ports) {
                 result.add(new NodePortTuple(sw, p));
             }
         }
diff --git a/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java b/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java
index b6bfe8d6615831bf2599febb19529271addf7ea1..ceddc37599d7b46d8171b5df3ea454ba8da77586 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java
@@ -22,7 +22,9 @@ import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.Route;
 import net.floodlightcontroller.topology.NodePortTuple;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
@@ -45,15 +47,15 @@ public class RouteResource extends ServerResource {
 
         log.debug( srcDpid + "--" + srcPort + "--" + dstDpid + "--" + dstPort);
 
-        long longSrcDpid = HexString.toLong(srcDpid);
-        short shortSrcPort = Short.parseShort(srcPort);
-        long longDstDpid = HexString.toLong(dstDpid);
-        short shortDstPort = Short.parseShort(dstPort);
+        DatapathId longSrcDpid = DatapathId.of(srcDpid);
+        OFPort shortSrcPort = OFPort.of(Integer.parseInt(srcPort));
+        DatapathId longDstDpid = DatapathId.of(dstDpid);
+        OFPort shortDstPort = OFPort.of(Integer.parseInt(dstPort));
         
-        Route result = routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort, 0);
+        Route result = routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort, U64.of(0));
         
-        if (result!=null) {
-            return routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort, 0).getPath();
+        if (result != null) {
+            return routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort, U64.of(0)).getPath();
         }
         else {
             log.debug("ERROR! no route found");
diff --git a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java b/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java
index 6ba1704967f6b9351fa0b4ea261f618966e23e60..ba6df10094a633498a70f924f6fbdb59996d7cc2 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java
@@ -22,10 +22,10 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.topology.ITopologyService;
 
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.types.DatapathId;
 import org.restlet.data.Form;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
@@ -36,11 +36,11 @@ import org.restlet.resource.ServerResource;
 public class SwitchClustersResource extends ServerResource {
     @Get("json")
     public Map<String, List<String>> retrieve() {
-        IFloodlightProviderService floodlightProvider =
-                (IFloodlightProviderService)getContext().getAttributes().
-                    get(IFloodlightProviderService.class.getCanonicalName());
-        ITopologyService topology =
-                (ITopologyService)getContext().getAttributes().
+        IOFSwitchService switchService =
+                (IOFSwitchService) getContext().getAttributes().
+                    get(IOFSwitchService.class.getCanonicalName());
+        ITopologyService topologyService =
+                (ITopologyService) getContext().getAttributes().
                     get(ITopologyService.class.getCanonicalName());
 
         Form form = getQuery();
@@ -51,18 +51,18 @@ public class SwitchClustersResource extends ServerResource {
         }
 
         Map<String, List<String>> switchClusterMap = new HashMap<String, List<String>>();
-        for (Long dpid: floodlightProvider.getAllSwitchDpids()) {
-            Long clusterDpid =
+        for (DatapathId dpid: switchService.getAllSwitchDpids()) {
+            DatapathId clusterDpid =
                     (openflowDomain
-                     ? topology.getOpenflowDomainId(dpid)
-                     :topology.getL2DomainId(dpid));
-            List<String> switchesInCluster = switchClusterMap.get(HexString.toHexString(clusterDpid));
+                     ? topologyService.getOpenflowDomainId(dpid)
+                     :topologyService.getL2DomainId(dpid));
+            List<String> switchesInCluster = switchClusterMap.get(clusterDpid.toString());
             if (switchesInCluster != null) {
-                switchesInCluster.add(HexString.toHexString(dpid));
+                switchesInCluster.add(dpid.toString());
             } else {
                 List<String> l = new ArrayList<String>();
-                l.add(HexString.toHexString(dpid));
-                switchClusterMap.put(HexString.toHexString(clusterDpid), l);
+                l.add(dpid.toString());
+                switchClusterMap.put(clusterDpid.toString(), l);
             }
         }
         return switchClusterMap;
diff --git a/src/main/java/net/floodlightcontroller/util/ActionUtils.java b/src/main/java/net/floodlightcontroller/util/ActionUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd6962531b5fbf42f3fd148b9bce5b6118e4b8bb
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/ActionUtils.java
@@ -0,0 +1,549 @@
+package net.floodlightcontroller.util;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionEnqueue;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwTos;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetTpDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetTpSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid;
+import org.projectfloodlight.openflow.protocol.action.OFActionStripVlan;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.VlanVid;
+import org.slf4j.Logger;
+
+/**
+ * OFAction helper functions. Use with any OpenFlowJ-Loxi Action.
+ * 
+ * Includes string methods refactored from StaticFlowEntryPusher
+ *
+ * @author Ryan Izard <ryan.izard@bigswitch.com, rizard@g.clemson.edu>
+ */
+public class ActionUtils {
+	public static final String STR_OUTPUT = "output";
+	public static final String STR_ENQUEUE = "enqueue";
+	public static final String STR_VLAN_STRIP = "strip_vlan";
+	public static final String STR_VLAN_POP = "pop_vlan";
+	public static final String STR_VLAN_PUSH = "push_vlan";
+	public static final String STR_VLAN_SET_PCP = "set_vlan_priority";
+	public static final String STR_VLAN_SET_VID = "set_vlan_id";
+	public static final String STR_QUEUE_SET = "set_queue";
+	public static final String STR_DL_SRC_SET = "set_src_mac";
+	public static final String STR_DL_DST_SET = "set_dst_mac";
+	public static final String STR_NW_SRC_SET = "set_src_ip";
+	public static final String STR_NW_DST_SET = "set_dst_ip";
+	public static final String STR_NW_ECN_SET = "set_nw_ecn";
+	public static final String STR_NW_TOS_SET = "set_tos_bits";
+	public static final String STR_NW_TTL_SET = "set_ip_ttl";
+	public static final String STR_NW_TTL_DEC = "dec_ip_ttl";
+	public static final String STR_MPLS_LABEL_SET = "set_mpls_label";
+	public static final String STR_MPLS_TC_SET = "set_mpls_tc";
+	public static final String STR_MPLS_TTL_SET = "set_mpls_ttl";
+	public static final String STR_MPLS_TTL_DEC = "dec_mpls_ttl";
+	public static final String STR_MPLS_PUSH = "push_mpls";
+	public static final String STR_MPLS_POP = "pop_mpls";
+	public static final String STR_TP_SRC_SET = "set_src_port";
+	public static final String STR_TP_DST_SET = "set_dst_port";
+	public static final String STR_TTL_IN_COPY = "copy_ttl_in";
+	public static final String STR_TTL_OUT_COPY = "copy_ttl_out";
+	public static final String STR_PBB_PUSH = "push_pbb";
+	public static final String STR_PBB_POP = "pop_pbb";
+	public static final String STR_EXPERIMENTER = "experimenter";
+	public static final String STR_GROUP = "group";
+	public static final String STR_FIELD_SET = "set_field";
+
+	/**
+     * Returns a String representation of all the OpenFlow actions.
+     * @param actions A list of OFActions to encode into one string
+     * @return A dpctl-style string of the actions
+     */
+    @LogMessageDoc(level="ERROR",
+            message="Could not decode action {action}",
+            explanation="A static flow entry contained an invalid action",
+            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+    public static String actionsToString(List<OFAction> actions, Logger log) {
+        StringBuilder sb = new StringBuilder();
+        for (OFAction a : actions) {
+            if (sb.length() > 0) {
+                sb.append(',');
+            }
+            switch(a.getType()) {
+                case OUTPUT:
+                    sb.append(STR_OUTPUT + "=" + ((OFActionOutput)a).getPort().toString());
+                    break;
+                case ENQUEUE:
+                    long queue = ((OFActionEnqueue)a).getQueueId();
+                    OFPort port = ((OFActionEnqueue)a).getPort();
+                    sb.append(STR_ENQUEUE + "=" + Integer.toString(port.getPortNumber()) + ":0x" + String.format("%02x", queue));
+                    break;
+                case STRIP_VLAN:
+                    sb.append(STR_VLAN_STRIP);
+                    break;
+                case SET_VLAN_VID:
+                    sb.append(STR_VLAN_SET_VID + "=" + 
+                        ((OFActionSetVlanVid)a).getVlanVid().toString());
+                    break;
+                case SET_VLAN_PCP:
+                    sb.append(STR_VLAN_SET_PCP + "=" +
+                        Byte.toString(((OFActionSetVlanPcp)a).getVlanPcp().getValue()));
+                    break;
+                case SET_DL_SRC:
+                    sb.append(STR_DL_SRC_SET + "=" + 
+                        ((OFActionSetDlSrc)a).getDlAddr().toString());
+                    break;
+                case SET_DL_DST:
+                    sb.append(STR_DL_DST_SET + "=" + 
+                        ((OFActionSetDlDst)a).getDlAddr().toString());
+                    break;
+                case SET_NW_TOS:
+                    sb.append(STR_NW_TOS_SET + "=" +
+                        Short.toString(((OFActionSetNwTos)a).getNwTos()));
+                    break;
+                case SET_NW_SRC:
+                    sb.append(STR_NW_SRC_SET + "=" +
+                        ((OFActionSetNwSrc)a).getNwAddr().toString());
+                    break;
+                case SET_NW_DST:
+                    sb.append(STR_NW_DST_SET + "=" +
+                        ((OFActionSetNwDst)a).getNwAddr().toString());
+                    break;
+                case SET_TP_SRC:
+                    sb.append(STR_TP_SRC_SET + "=" +
+                        ((OFActionSetTpSrc)a).getTpPort().toString());
+                    break;
+                case SET_TP_DST:
+                    sb.append(STR_TP_DST_SET + "=" +
+                        ((OFActionSetTpDst)a).getTpPort().toString());
+                    break;
+                default:
+                    log.error("Could not decode action: {}", a);
+                    break;
+            }
+                
+        }
+        return sb.toString();
+    }
+	
+	/**
+	 * Parses OFFlowMod actions from strings.
+	 * @param fmb The OFFlowMod.Builder to set the actions for
+	 * @param bigString The string containing all the actions
+	 * @param log A logger to log for errors.
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="Unexpected action '{action}', '{subaction}'",
+			explanation="A static flow entry contained an invalid action",
+			recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+	public static void fromString(OFFlowMod.Builder fmb, String bigString, Logger log) {
+		List<OFAction> actions = new LinkedList<OFAction>();
+		if (bigString != null) {
+			bigString = bigString.toLowerCase();
+			for (String actionToDecode : bigString.split(",")) {
+				String action = actionToDecode.split("[=:]")[0];
+				OFAction a = null;
+
+				if (action.equals(STR_OUTPUT)) {
+					a = decode_output(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_ENQUEUE)) {
+					a = decode_enqueue(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_VLAN_STRIP)) {
+					a = decode_strip_vlan(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_VLAN_SET_VID)) {
+					a = decode_set_vlan_id(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_VLAN_SET_PCP)) {
+					a = decode_set_vlan_priority(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_DL_SRC_SET)) {
+					a = decode_set_src_mac(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_DL_DST_SET)) {
+					a = decode_set_dst_mac(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_NW_TOS_SET)) {
+					a = decode_set_tos_bits(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_NW_SRC_SET)) {
+					a = decode_set_src_ip(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_NW_DST_SET)) {
+					a = decode_set_dst_ip(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_TP_SRC_SET)) {
+					a = decode_set_src_port(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_TP_DST_SET)) {
+					a = decode_set_dst_port(actionToDecode, fmb.getVersion(), log);
+				}
+				else {
+					log.error("Unexpected action '{}', '{}'", action, actionToDecode);
+				}
+
+				if (a != null) {
+					actions.add(a);
+				}
+			}
+		}
+		log.debug("action {}", actions);
+
+		fmb.setActions(actions);
+		return;
+	} 
+
+	@LogMessageDoc(level="ERROR",
+			message="Invalid subaction: '{subaction}'",
+			explanation="A static flow entry contained an invalid subaction",
+			recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+	private static OFActionOutput decode_output(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_OUTPUT + 
+				"=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(actionToDecode);
+		if (n.matches()) {
+			OFActionOutput.Builder ab = OFFactories.getFactory(version).actions().buildOutput();
+			OFPort port = OFPort.ANY;
+			if (n.group(1) != null) {
+				try {
+					port = OFPort.of(get_short(n.group(1)));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid port in: '{}' (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+			else if (n.group(2) != null)
+				port = OFPort.ALL;
+			else if (n.group(3) != null)
+				port = OFPort.CONTROLLER;
+			else if (n.group(4) != null)
+				port = OFPort.LOCAL;
+			else if (n.group(5) != null)
+				port = OFPort.IN_PORT;
+			else if (n.group(6) != null)
+				port = OFPort.NORMAL;
+			else if (n.group(7) != null)
+				port = OFPort.FLOOD;
+			ab.setPort(port);
+			log.debug("action {}", ab.build());
+			return ab.build();
+		}
+		else {
+			log.error("Invalid subaction: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionEnqueue decode_enqueue(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_ENQUEUE + "=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(actionToDecode);
+		if (n.matches()) {
+			OFPort port = OFPort.of(0);
+			if (n.group(1) != null) {
+				try {
+					port = OFPort.of(get_short(n.group(1)));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid port-num in: '{}' (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+
+			int queueid = 0;
+			if (n.group(2) != null) {
+				try {
+					queueid = get_int(n.group(2));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid queue-id in: '{}' (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+			OFActionEnqueue.Builder ab = OFFactories.getFactory(version).actions().buildEnqueue();
+			ab.setPort(port);
+			ab.setQueueId(queueid);
+			log.debug("action {}", ab.build());
+			return ab.build();
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionStripVlan decode_strip_vlan(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_VLAN_STRIP).matcher(actionToDecode);
+		if (n.matches()) {
+			OFActionStripVlan a = OFFactories.getFactory(version).actions().stripVlan();
+			log.debug("action {}", a);
+			return a;
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionSetVlanVid decode_set_vlan_id(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_VLAN_SET_VID + "=((?:0x)?\\d+)").matcher(actionToDecode);
+		if (n.matches()) {            
+			if (n.group(1) != null) {
+				try {
+					VlanVid vlanid = VlanVid.ofVlan(get_short(n.group(1)));
+					OFActionSetVlanVid.Builder ab = OFFactories.getFactory(version).actions().buildSetVlanVid();
+					ab.setVlanVid(vlanid);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid VLAN in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}          
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetVlanPcp decode_set_vlan_priority(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_VLAN_SET_PCP + "=((?:0x)?\\d+)").matcher(actionToDecode); 
+		if (n.matches()) {            
+			if (n.group(1) != null) {
+				try {
+					VlanPcp prior = VlanPcp.of(get_byte(n.group(1)));
+					OFActionSetVlanPcp.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetVlanPcp();
+					ab.setVlanPcp(prior);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid VLAN priority in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetDlSrc decode_set_src_mac(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_DL_SRC_SET +
+				"=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(actionToDecode); 
+		if (n.matches()) {
+			MacAddress macaddr = MacAddress.of(get_mac_addr(n, actionToDecode, log));
+			if (macaddr != null) {
+				OFActionSetDlSrc.Builder ab = OFFactories.getFactory(version).actions().buildSetDlSrc();
+				ab.setDlAddr(macaddr);
+				log.debug("action {}", ab.build());
+				return ab.build();
+			}            
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetDlDst decode_set_dst_mac(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_DL_DST_SET +
+				"=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(actionToDecode);
+		if (n.matches()) {
+			MacAddress macaddr = MacAddress.of(get_mac_addr(n, actionToDecode, log));            
+			if (macaddr != null) {
+				OFActionSetDlDst.Builder ab = OFFactories.getFactory(version).actions().buildSetDlDst();
+				ab.setDlAddr(macaddr);
+				log.debug("action {}", ab.build());
+				return ab.build();
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetNwTos decode_set_tos_bits(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_NW_TOS_SET + "=((?:0x)?\\d+)").matcher(actionToDecode); 
+		if (n.matches()) {
+			if (n.group(1) != null) {
+				try {
+					byte tosbits = get_byte(n.group(1));
+					OFActionSetNwTos.Builder ab = OFFactories.getFactory(version).actions().buildSetNwTos();
+					ab.setNwTos(tosbits);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid dst-port in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetNwSrc decode_set_src_ip(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_NW_SRC_SET + "=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(actionToDecode);
+		if (n.matches()) {
+			IPv4Address ipaddr = IPv4Address.of(get_ip_addr(n, actionToDecode, log));
+			OFActionSetNwSrc.Builder ab = OFFactories.getFactory(version).actions().buildSetNwSrc();
+			ab.setNwAddr(ipaddr);
+			log.debug("action {}", ab.build());
+			return ab.build();
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionSetNwDst decode_set_dst_ip(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_NW_DST_SET + "=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(actionToDecode);
+		if (n.matches()) {
+			IPv4Address ipaddr = IPv4Address.of(get_ip_addr(n, actionToDecode, log));
+			OFActionSetNwDst.Builder ab = OFFactories.getFactory(version).actions().buildSetNwDst();
+			ab.setNwAddr(ipaddr);
+			log.debug("action {}", ab.build());
+			return ab.build();
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionSetTpSrc decode_set_src_port(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_TP_SRC_SET + "=((?:0x)?\\d+)").matcher(actionToDecode); 
+		if (n.matches()) {
+			if (n.group(1) != null) {
+				try {
+					TransportPort portnum = TransportPort.of(get_short(n.group(1)));
+					OFActionSetTpSrc.Builder ab = OFFactories.getFactory(version).actions().buildSetTpSrc();
+					ab.setTpPort(portnum);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				} 
+				catch (NumberFormatException e) {
+					log.debug("Invalid src-port in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFAction decode_set_dst_port(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_TP_DST_SET + "=((?:0x)?\\d+)").matcher(actionToDecode);
+		if (n.matches()) {
+			if (n.group(1) != null) {
+				try {
+					TransportPort portnum = TransportPort.of(get_short(n.group(1)));
+					OFActionSetTpDst.Builder ab = OFFactories.getFactory(version).actions().buildSetTpDst();
+					ab.setTpPort(portnum);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid dst-port in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static byte[] get_mac_addr(Matcher n, String actionToDecode, Logger log) {
+		byte[] macaddr = new byte[6];     
+		for (int i=0; i<6; i++) {
+			if (n.group(i+1) != null) {
+				try {
+					macaddr[i] = get_byte("0x" + n.group(i+1));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid src-mac in: '{}' (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+			else { 
+				log.debug("Invalid src-mac in: '{}' (null, error ignored)", actionToDecode);
+				return null;
+			}
+		}  
+		return macaddr;
+	}
+
+	private static int get_ip_addr(Matcher n, String actionToDecode, Logger log) {
+		int ipaddr = 0;
+		for (int i=0; i<4; i++) {
+			if (n.group(i+1) != null) {
+				try {
+					ipaddr = ipaddr<<8;
+					ipaddr = ipaddr | get_int(n.group(i+1));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid src-ip in: '{}' (error ignored)", actionToDecode);
+					return 0;
+				}
+			}
+			else {
+				log.debug("Invalid src-ip in: '{}' (null, error ignored)", actionToDecode);
+				return 0;
+			}
+		}
+		return ipaddr;
+	}
+
+	// Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
+	private static int get_int(String str) {
+		return Integer.decode(str);
+	}
+
+	// Parse short as decimal, hex (start with 0x or #) or octal (starts with 0)
+	private static short get_short(String str) {
+		return (short)(int)Integer.decode(str);
+	}
+
+	// Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0)
+	private static byte get_byte(String str) {
+		return Integer.decode(str).byteValue();
+	}
+
+}
diff --git a/src/main/java/net/floodlightcontroller/util/FlowModUtils.java b/src/main/java/net/floodlightcontroller/util/FlowModUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..94ddeeb6eccd79bba2b8d3ddbcee8a952e338aea
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/FlowModUtils.java
@@ -0,0 +1,133 @@
+package net.floodlightcontroller.util;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowDelete;
+import org.projectfloodlight.openflow.protocol.OFFlowDeleteStrict;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowModify;
+import org.projectfloodlight.openflow.protocol.OFFlowModifyStrict;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+/**
+ * Convert an OFFlowMod to a specific OFFlowMod-OFFlowModCommand.
+ * These function as setCommand(OFFlowModCommand) methods for an OFFlowMod.
+ * Used initially in the static flow pusher, but will likely find merit elsewhere.
+ * 
+ * Other useful FlowMod utility functions and constants are also included.
+ *
+ * @author Ryan Izard <ryan.izard@bigswitch.com, rizard@g.clemson.edu>
+ */
+public class FlowModUtils {
+	public static final int INFINITE_TIMEOUT = 0;
+	
+	public static final int PRIORITY_MAX = 32768;
+	public static final int PRIORITY_VERY_HIGH = 28672;
+	public static final int PRIORITY_HIGH = 24576;
+	public static final int PRIORITY_MED_HIGH = 20480;
+	public static final int PRIORITY_MED = 16384;
+	public static final int PRIORITY_MED_LOW = 12288;
+	public static final int PRIORITY_LOW = 8192;
+	public static final int PRIORITY_VERY_LOW = 4096;
+	public static final int PRIORITY_MIN = 0;
+	
+	public static OFFlowAdd toFlowAdd(OFFlowMod fm) {
+		OFVersion version = fm.getVersion();
+		OFFlowAdd.Builder b = OFFactories.getFactory(version).buildFlowAdd();
+		return b.setActions(fm.getActions())
+				.setBufferId(fm.getBufferId())
+				.setCookie(fm.getCookie())
+				.setCookieMask(fm.getCookieMask())
+				.setFlags(fm.getFlags())
+				.setHardTimeout(fm.getHardTimeout())
+				.setIdleTimeout(fm.getIdleTimeout())
+				.setInstructions(fm.getInstructions())
+				.setMatch(fm.getMatch())
+				.setOutGroup(fm.getOutGroup())
+				.setOutPort(fm.getOutPort())
+				.setPriority(fm.getPriority())
+				.setTableId(fm.getTableId())
+				.setXid(fm.getXid())
+				.build();
+	}
+
+	public static OFFlowDelete toFlowDelete(OFFlowMod fm) {
+		OFVersion version = fm.getVersion();
+		OFFlowDelete.Builder b = OFFactories.getFactory(version).buildFlowDelete();
+		return b.setActions(fm.getActions())
+				.setBufferId(fm.getBufferId())
+				.setCookie(fm.getCookie())
+				.setCookieMask(fm.getCookieMask())
+				.setFlags(fm.getFlags())
+				.setHardTimeout(fm.getHardTimeout())
+				.setIdleTimeout(fm.getIdleTimeout())
+				.setInstructions(fm.getInstructions())
+				.setMatch(fm.getMatch())
+				.setOutGroup(fm.getOutGroup())
+				.setOutPort(fm.getOutPort())
+				.setPriority(fm.getPriority())
+				.setTableId(fm.getTableId())
+				.setXid(fm.getXid())
+				.build();
+	}
+
+	public static OFFlowDeleteStrict toFlowDeleteStrict(OFFlowMod fm) {
+		OFVersion version = fm.getVersion();
+		OFFlowDeleteStrict.Builder b = OFFactories.getFactory(version).buildFlowDeleteStrict();
+		return b.setActions(fm.getActions())
+				.setBufferId(fm.getBufferId())
+				.setCookie(fm.getCookie())
+				.setCookieMask(fm.getCookieMask())
+				.setFlags(fm.getFlags())
+				.setHardTimeout(fm.getHardTimeout())
+				.setIdleTimeout(fm.getIdleTimeout())
+				.setInstructions(fm.getInstructions())
+				.setMatch(fm.getMatch())
+				.setOutGroup(fm.getOutGroup())
+				.setOutPort(fm.getOutPort())
+				.setPriority(fm.getPriority())
+				.setTableId(fm.getTableId())
+				.setXid(fm.getXid())
+				.build();
+	}
+
+	public static OFFlowModify toFlowModify(OFFlowMod fm) {
+		OFVersion version = fm.getVersion();
+		OFFlowModify.Builder b = OFFactories.getFactory(version).buildFlowModify();
+		return b.setActions(fm.getActions())
+				.setBufferId(fm.getBufferId())
+				.setCookie(fm.getCookie())
+				.setCookieMask(fm.getCookieMask())
+				.setFlags(fm.getFlags())
+				.setHardTimeout(fm.getHardTimeout())
+				.setIdleTimeout(fm.getIdleTimeout())
+				.setInstructions(fm.getInstructions())
+				.setMatch(fm.getMatch())
+				.setOutGroup(fm.getOutGroup())
+				.setOutPort(fm.getOutPort())
+				.setPriority(fm.getPriority())
+				.setTableId(fm.getTableId())
+				.setXid(fm.getXid())
+				.build();
+	}
+
+	public static OFFlowModifyStrict toFlowModifyStrict(OFFlowMod fm) {
+		OFVersion version = fm.getVersion();
+		OFFlowModifyStrict.Builder b = OFFactories.getFactory(version).buildFlowModifyStrict();
+		return b.setActions(fm.getActions())
+				.setBufferId(fm.getBufferId())
+				.setCookie(fm.getCookie())
+				.setCookieMask(fm.getCookieMask())
+				.setFlags(fm.getFlags())
+				.setHardTimeout(fm.getHardTimeout())
+				.setIdleTimeout(fm.getIdleTimeout())
+				.setInstructions(fm.getInstructions())
+				.setMatch(fm.getMatch())
+				.setOutGroup(fm.getOutGroup())
+				.setOutPort(fm.getOutPort())
+				.setPriority(fm.getPriority())
+				.setTableId(fm.getTableId())
+				.setXid(fm.getXid())
+				.build();
+	}
+}
diff --git a/src/main/java/net/floodlightcontroller/util/MACAddress.java b/src/main/java/net/floodlightcontroller/util/MACAddress.java
deleted file mode 100644
index 808a37797f857c54fb7da07f4846d3896f465f25..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/util/MACAddress.java
+++ /dev/null
@@ -1,173 +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.util;
-
-import java.util.Arrays;
-
-/**
- * The class representing MAC address.
- *
- * @author Sho Shimizu (sho.shimizu@gmail.com)
- */
-public class MACAddress {
-    public static final int MAC_ADDRESS_LENGTH = 6;
-    private byte[] address = new byte[MAC_ADDRESS_LENGTH];
-
-    public MACAddress(byte[] address) {
-        this.address = Arrays.copyOf(address, MAC_ADDRESS_LENGTH);
-    }
-
-    /**
-     * Returns a MAC address instance representing the value of the specified {@code String}.
-     * @param address the String representation of the MAC Address to be parsed.
-     * @return a MAC Address instance representing the value of the specified {@code String}.
-     * @throws IllegalArgumentException if the string cannot be parsed as a MAC address.
-     */
-    public static MACAddress valueOf(String address) {
-        String[] elements = address.split(":");
-        if (elements.length != MAC_ADDRESS_LENGTH) {
-            throw new IllegalArgumentException(
-                    "Specified MAC Address must contain 12 hex digits" +
-                    " separated pairwise by :'s.");
-        }
-
-        byte[] addressInBytes = new byte[MAC_ADDRESS_LENGTH];
-        for (int i = 0; i < MAC_ADDRESS_LENGTH; i++) {
-            String element = elements[i];
-            addressInBytes[i] = (byte)Integer.parseInt(element, 16);
-        }
-
-        return new MACAddress(addressInBytes);
-    }
-
-    /**
-     * Returns a MAC address instance representing the specified {@code byte} array.
-     * @param address the byte array to be parsed.
-     * @return a MAC address instance representing the specified {@code byte} array.
-     * @throws IllegalArgumentException if the byte array cannot be parsed as a MAC address.
-     */
-    public static MACAddress valueOf(byte[] address) {
-        if (address.length != MAC_ADDRESS_LENGTH) {
-            throw new IllegalArgumentException("the length is not " + MAC_ADDRESS_LENGTH);
-        }
-
-        return new MACAddress(address);
-    }
-
-    /**
-     * Returns a MAC address instance representing the specified {@code long} value.
-     * The lower 48 bits of the long value are used to parse as a MAC address.
-     * @param address the long value to be parsed. The lower 48 bits are used for a MAC address.
-     * @return a MAC address instance representing the specified {@code long} value.
-     * @throws IllegalArgumentException if the long value cannot be parsed as a MAC address.
-     */
-    public static MACAddress valueOf(long address) {
-        byte[] addressInBytes = new byte[] {
-                (byte)((address >> 40) & 0xff),
-                (byte)((address >> 32) & 0xff),
-                (byte)((address >> 24) & 0xff),
-                (byte)((address >> 16) & 0xff),
-                (byte)((address >> 8 ) & 0xff),
-                (byte)((address >> 0) & 0xff)
-        };
-
-        return new MACAddress(addressInBytes);
-    }
-
-    /**
-     * Returns the length of the {@code MACAddress}.
-     * @return the length of the {@code MACAddress}.
-     */
-    public int length() {
-        return address.length;
-    }
-
-    /**
-     * Returns the value of the {@code MACAddress} as a {@code byte} array.
-     * @return the numeric value represented by this object after conversion to type {@code byte} array.
-     */
-    public byte[] toBytes() {
-        return Arrays.copyOf(address, address.length);
-    }
-
-    /**
-     * Returns the value of the {@code MACAddress} as a {@code long}.
-     * @return the numeric value represented by this object after conversion to type {@code long}.
-     */
-    public long toLong() {
-        long mac = 0;
-        for (int i = 0; i < 6; i++) {
-            long t = (address[i] & 0xffL) << ((5 - i) * 8);
-            mac |= t;
-        }
-        return mac;
-    }
-
-    /**
-     * Returns {@code true} if the MAC address is the broadcast address.
-     * @return {@code true} if the MAC address is the broadcast address.
-     */
-    public boolean isBroadcast() {
-        for (byte b : address) {
-            if (b != -1) // checks if equal to 0xff
-                return false;
-        }
-        return true;
-    }
-
-    /**
-     * Returns {@code true} if the MAC address is the multicast address.
-     * @return {@code true} if the MAC address is the multicast address.
-     */
-    public boolean isMulticast() {
-        if (isBroadcast()) {
-            return false;
-        }
-        return (address[0] & 0x01) != 0;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-
-        if (!(o instanceof MACAddress)) {
-            return false;
-        }
-
-        MACAddress other = (MACAddress)o;
-        return Arrays.equals(this.address, other.address);
-    }
-
-    @Override
-    public int hashCode() {
-        return Arrays.hashCode(this.address);
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        for (byte b: address) {
-            if (builder.length() > 0) {
-                builder.append(":");
-            }
-            builder.append(String.format("%02X", b & 0xFF));
-        }
-        return builder.toString();
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/util/MatchUtils.java b/src/main/java/net/floodlightcontroller/util/MatchUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..e10cf4a3fdf52b9466c9573f94ad06c49389f3e8
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/MatchUtils.java
@@ -0,0 +1,436 @@
+package net.floodlightcontroller.util;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.ArpOpcode;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.ICMPv4Code;
+import org.projectfloodlight.openflow.types.ICMPv4Type;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
+import org.projectfloodlight.openflow.types.IpDscp;
+import org.projectfloodlight.openflow.types.IpEcn;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFMetadata;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U8;
+import org.projectfloodlight.openflow.types.VlanPcp;
+
+/**
+ * Match helper functions. Use with any OpenFlowJ-Loxi Match.
+ * 
+ * Includes string methods adopted from OpenFlowJ for OpenFlow 1.0.
+ *
+ * @author Ryan Izard <ryan.izard@bigswitch.com, rizard@g.clemson.edu>
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class MatchUtils {
+	/* List of Strings for marshalling and unmarshalling to human readable forms.
+	 * Classes that convert from Match and String should reference these fields for a
+	 * common string representation throughout the controller. The StaticFlowEntryPusher
+	 * is one such example that references these strings.
+	 */
+	public static final String STR_IN_PORT = "ingress_port";
+
+	public static final String STR_DL_DST = "dl_dst";
+	public static final String STR_DL_SRC = "dl_src";
+	public static final String STR_DL_TYPE = "dl_type";
+	public static final String STR_DL_VLAN = "dl_vlan";
+	public static final String STR_DL_VLAN_PCP = "dl_vpcp";
+
+	public static final String STR_NW_DST = "nw_dst";
+	public static final String STR_NW_SRC = "nw_src";
+	public static final String STR_NW_PROTO = "nw_proto";
+	public static final String STR_NW_TOS = "nw_tos";
+
+	public static final String STR_TP_DST = "tp_dst";
+	public static final String STR_TP_SRC = "tp_src";
+
+	public static final String STR_ICMP_TYPE = "icmp_type";
+	public static final String STR_ICMP_CODE = "icmp_code";
+
+	public static final String STR_ARP_OPCODE = "arp_opcode";
+	public static final String STR_ARP_SHA = "arp_sha";
+	public static final String STR_ARP_DHA = "arp_dha";
+	public static final String STR_ARP_SPA = "arp_spa";
+	public static final String STR_ARP_DPA = "arp_dpa";
+
+	public static final String STR_MPLS_LABEL = "mpls_label";
+	public static final String STR_MPLS_TC = "mpls_tc";
+	public static final String STR_MPLS_BOS = "mpls_bos";
+
+	public static final String STR_METADATA = "metadata";
+	public static final String STR_TUNNEL_ID = "tunnel_id";
+
+	public static final String STR_PBB_ISID = "pbb_isid";	
+
+	/**
+	 * Create a point-to-point match for two devices at the IP layer.
+	 * Takes an existing match (e.g. from a PACKET_IN), and masks all
+	 * MatchFields leaving behind:
+	 * 		IN_PORT
+	 * 		VLAN_VID
+	 * 		ETH_TYPE
+	 * 		ETH_SRC
+	 * 		ETH_DST
+	 * 		IPV4_SRC
+	 * 		IPV4_DST
+	 * 		IP_PROTO (might remove this)
+	 * 
+	 * If one of the above MatchFields is wildcarded in Match m,
+	 * that MatchField will be wildcarded in the returned Match.
+	 * 
+	 * @param m The match to remove all L4+ MatchFields from
+	 * @return A new Match object with all MatchFields masked/wildcared
+	 * except for those listed above.
+	 */
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	public static Match maskL4AndUp(Match m) {
+		Match.Builder mb = m.createBuilder(); 
+		Iterator<MatchField<?>> itr = m.getMatchFields().iterator(); // only get exact or masked fields (not fully wildcarded)
+		while(itr.hasNext()) {
+			MatchField mf = itr.next();
+			// restrict MatchFields only to L3 and below: IN_PORT, ETH_TYPE, ETH_SRC, ETH_DST, IPV4_SRC, IPV4_DST, IP_PROTO (this one debatable...)
+			// if a MatchField is not in the access list below, it will not be set --> it will be left wildcarded (default)
+			if (mf.equals(MatchField.IN_PORT) || mf.equals(MatchField.ETH_TYPE) || mf.equals(MatchField.ETH_SRC) || mf.equals(MatchField.ETH_DST) ||
+					mf.equals(MatchField.IPV4_SRC) || mf.equals(MatchField.IPV4_DST) || mf.equals(MatchField.IP_PROTO)) {
+				if (m.isExact(mf)) {
+					mb.setExact(mf, m.get(mf));
+				} else if (m.isPartiallyMasked(mf)) {
+					mb.setMasked(mf, m.getMasked(mf));
+				} else {
+					// it's either exact, masked, or wildcarded
+					// itr only contains exact and masked MatchFields
+					// we should never get here
+				}
+			}
+		}
+		return mb.build();
+	}
+
+	/**
+	 * Create a builder from an existing Match object. Unlike Match's
+	 * createBuilder(), this utility function will preserve all of
+	 * Match m's MatchFields, even if new MatchFields are set or modified
+	 * with the builder after it is returned to the calling function.
+	 * 
+	 * All original MatchFields in m will be set if the build() method is 
+	 * invoked upon the returned builder. After the builder is returned, if
+	 * a MatchField is modified via setExact(), setMasked(), or wildcard(),
+	 * the newly modified MatchField will replace the original found in m.
+	 * 
+	 * @param m; the match to create the builder from
+	 * @return Match.Builder; the builder that can be modified, and when built,
+	 * will retain all of m's MatchFields, unless you explicitly overwrite them.
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public static Match.Builder createRetentiveBuilder(Match m) {
+		/* Builder retains a parent MatchField list, but list will not be used to  
+		 * build the new match if the builder's set methods have been invoked; only 
+		 * additions will be built, and all parent MatchFields will be ignored,  
+		 * even if they were not modified by the new builder. Create a builder, and
+		 * walk through m's list of non-wildcarded MatchFields. Set them all in the
+		 * new builder by invoking a set method for each. This will make them persist
+		 * in the Match built from this builder if the user decides to add or subtract
+		 * from the MatchField list.
+		 */
+		Match.Builder mb = m.createBuilder(); 
+		Iterator<MatchField<?>> itr = m.getMatchFields().iterator(); // only get exact or masked fields (not fully wildcarded)
+		while(itr.hasNext()) {
+			MatchField mf = itr.next();
+			if (m.isExact(mf)) {
+				mb.setExact(mf, m.get(mf));
+			} else if (m.isPartiallyMasked(mf)) {
+				mb.setMasked(mf, m.getMasked(mf));
+			} else {
+				// it's either exact, masked, or wildcarded
+				// itr only contains exact and masked MatchFields
+				// we should never get here
+			}
+		}
+		return mb;
+	}
+
+	/**
+	 * Create a Match builder the same OF version as Match m. The returned builder
+	 * will not retain any MatchField information from Match m and will
+	 * essentially return a clean-slate Match builder with no parent history. 
+	 * This simple method is included as a wrapper to provide the opposite functionality
+	 * of createRetentiveBuilder().
+	 * 
+	 * @param m; the match to create the builder from
+	 * @return Match.Builder; the builder retains no history from the parent Match m
+	 */
+	public static Match.Builder createForgetfulBuilder(Match m) {
+		return OFFactories.getFactory(m.getVersion()).buildMatch();
+	}
+
+	/**
+	 * Create a duplicate Match object from Match m.
+	 * 
+	 * @param m; the match to copy
+	 * @return Match; the new copy of Match m
+	 */
+	public static Match createCopy(Match m) {
+		return m.createBuilder().build(); // will use parent MatchFields to produce the new Match only if the builder is never modified
+	}
+
+	/**
+	 * TODO @Ryan NOT IMPLEMENTED! Returns empty string right now.
+	 * Output a dpctl-styled string, i.e., only list the elements that are not wildcarded.
+	 * 
+	 * A match-everything Match outputs "Match[]"
+	 * 
+	 * @return "Match[dl_src:00:20:01:11:22:33,nw_src:192.168.0.0/24,tp_dst:80]"
+	 */
+	public static String toString(Match match) {
+		/*String str = "";
+
+	        match
+
+	        // 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 + "="
+	                    + match.);
+	        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 + "=" + U8.f(this.networkProtocol);
+	        if ((wildcards & OFPFW_NW_TOS) == 0)
+	            str += "," + STR_NW_TOS + "=" + U8.f(this.networkTypeOfService);
+
+	        // l4
+	        if ((wildcards & OFPFW_TP_DST) == 0)
+	            str += "," + STR_TP_DST + "=" + U16.f(this.transportDestination);
+	        if ((wildcards & OFPFW_TP_SRC) == 0)
+	            str += "," + STR_TP_SRC + "=" + U16.f(this.transportSource);
+	        if ((str.length() > 0) && (str.charAt(0) == ','))
+	            str = str.substring(1); // trim the leading ","
+	        // done
+	        return "OFMatch[" + str + "]"; */
+		return "";
+	}
+
+	/**
+	 * Based on the method from OFMatch in openflowj 1.0.
+	 * Set this Match'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", "dl_dst"
+	 * <TD>hex-string
+	 * </TR>
+	 * <TR>
+	 * <TD>"dl_type", "dl_vlan", "dl_vlan_pcp"
+	 * <TD>integer
+	 * </TR>
+	 * <TR>
+	 * <TD>"nw_src", "nw_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,nw_dst=192.168.0.0/16,tp_src=80"
+	 * @throws IllegalArgumentException
+	 *             on unexpected key or value
+	 */
+	public static Match fromString(String match, OFVersion ofVersion) throws IllegalArgumentException {
+		if (match.equals("") || match.equalsIgnoreCase("any") || match.equalsIgnoreCase("all") || match.equals("[]")) {
+			match = "Match[]";
+		}
+		
+		// Split into pairs of key=value
+		String[] tokens = match.split("[\\[,\\]]");
+		int initArg = 0;
+		if (tokens[0].equals("Match")) {
+			initArg = 1;
+		}
+		
+		// Split up key=value pairs into [key, value], and insert into linked list
+		int i;
+		String[] tmp;
+		ArrayDeque<String[]> llValues = new ArrayDeque<String[]>();
+		for (i = initArg; i < tokens.length; i++) {
+			tmp = tokens[i].split("=");
+			if (tmp.length != 2) {
+				throw new IllegalArgumentException("Token " + tokens[i] + " does not have form 'key=value' parsing " + match);
+			}
+			tmp[0] = tmp[0].toLowerCase(); // try to make key parsing case insensitive
+			llValues.add(tmp); // llValues contains [key, value] pairs. Create a queue of pairs to process.
+		}	
+
+		Match.Builder mb = OFFactories.getFactory(ofVersion).buildMatch();
+
+		while (!llValues.isEmpty()) {
+			IpProtocol ipProto; // used to prevent lots of match.get()'s for detecting transport protocol
+			String[] key_value = llValues.pollFirst(); // pop off the first element; this completely removes it from the queue.
+			switch (key_value[0]) {
+			case STR_IN_PORT:
+				mb.setExact(MatchField.IN_PORT, OFPort.of(Integer.valueOf(key_value[1])));
+				break;
+			case STR_DL_DST:
+				mb.setExact(MatchField.ETH_DST, MacAddress.of(key_value[1]));
+				break;
+			case STR_DL_SRC:
+				mb.setExact(MatchField.ETH_SRC, MacAddress.of(key_value[1]));
+				break;
+			case STR_DL_TYPE:
+				if (key_value[1].startsWith("0x")) {
+					mb.setExact(MatchField.ETH_TYPE, EthType.of(Integer.valueOf(key_value[1].replaceFirst("0x", ""), 16)));
+				} else {
+					mb.setExact(MatchField.ETH_TYPE, EthType.of(Integer.valueOf(key_value[1])));
+				}
+				break;
+			case STR_DL_VLAN:
+				if (key_value[1].contains("0x")) {
+					mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(Integer.valueOf(key_value[1].replaceFirst("0x", ""), 16)));
+				} else {
+					mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(Integer.valueOf(key_value[1])));
+				}
+				break;
+			case STR_DL_VLAN_PCP:
+				mb.setExact(MatchField.VLAN_PCP, VlanPcp.of(U8.t(Short.valueOf(key_value[1]))));
+				break;
+			case STR_NW_DST:
+				mb.setMasked(MatchField.IPV4_DST, IPv4AddressWithMask.of(key_value[1]));
+				break;
+			case STR_NW_SRC:
+				mb.setMasked(MatchField.IPV4_SRC, IPv4AddressWithMask.of(key_value[1]));
+				break;
+			case STR_NW_PROTO:
+				mb.setExact(MatchField.IP_PROTO, IpProtocol.of(Short.valueOf(key_value[1])));
+				break;
+			case STR_NW_TOS:
+				mb.setExact(MatchField.IP_ECN, IpEcn.of(U8.t(Short.valueOf(key_value[1]))));
+				mb.setExact(MatchField.IP_DSCP, IpDscp.of(U8.t(Short.valueOf(key_value[1]))));
+				break;
+			case STR_TP_DST:
+				// if we don't know the transport protocol yet, postpone parsing this [key, value] pair until we know. Put it at the back of the queue.
+				if ((ipProto = mb.get(MatchField.IP_PROTO)) == null) {
+					llValues.add(key_value); // place it back if we can't proceed yet
+				} else if (ipProto.equals(IpProtocol.TCP)) {
+					mb.setExact(MatchField.TCP_DST, TransportPort.of(Integer.valueOf(key_value[1])));
+				} else if (ipProto.equals(IpProtocol.UDP)) {
+					mb.setExact(MatchField.UDP_DST, TransportPort.of(Integer.valueOf(key_value[1])));
+				} else if (ipProto.equals(IpProtocol.SCTP)) {
+					mb.setExact(MatchField.SCTP_DST, TransportPort.of(Integer.valueOf(key_value[1])));
+				}
+				break;
+			case STR_TP_SRC:
+				if ((ipProto = mb.get(MatchField.IP_PROTO)) == null) {
+					llValues.add(key_value); // place it back if we can't proceed yet
+				} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.TCP)) {
+					mb.setExact(MatchField.TCP_SRC, TransportPort.of(Integer.valueOf(key_value[1])));
+				} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.UDP)) {
+					mb.setExact(MatchField.UDP_SRC, TransportPort.of(Integer.valueOf(key_value[1])));
+				} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.SCTP)) {
+					mb.setExact(MatchField.SCTP_SRC, TransportPort.of(Integer.valueOf(key_value[1])));
+				}
+				break;
+			case STR_ICMP_TYPE:
+				mb.setExact(MatchField.ICMPV4_TYPE, ICMPv4Type.of(Short.parseShort(key_value[1])));
+				break;
+			case STR_ICMP_CODE:
+				mb.setExact(MatchField.ICMPV4_CODE, ICMPv4Code.of(Short.parseShort(key_value[1])));
+				break;
+			case STR_ARP_OPCODE:
+				mb.setExact(MatchField.ARP_OP, ArpOpcode.of(Integer.parseInt(key_value[1])));
+				break;
+			case STR_ARP_SHA:
+				mb.setExact(MatchField.ARP_SHA, MacAddress.of(key_value[1]));
+				break;
+			case STR_ARP_DHA:
+				mb.setExact(MatchField.ARP_THA, MacAddress.of(key_value[1]));
+				break;
+			case STR_ARP_SPA:
+				mb.setExact(MatchField.ARP_SPA, IPv4Address.of(key_value[1]));
+				break;
+			case STR_ARP_DPA:
+				mb.setExact(MatchField.ARP_TPA, IPv4Address.of(key_value[1]));
+				break;
+			case STR_MPLS_LABEL:
+				mb.setExact(MatchField.MPLS_LABEL, U32.of(Long.parseLong(key_value[1])));
+				break;
+			case STR_MPLS_TC:
+				mb.setExact(MatchField.MPLS_TC, U8.of(Short.parseShort(key_value[1])));
+				break;
+			case STR_MPLS_BOS:
+				//no-op. Not implemented.
+				break;
+			case STR_METADATA:
+				mb.setExact(MatchField.METADATA, OFMetadata.ofRaw(Long.parseLong(key_value[1])));
+				break;
+			case STR_TUNNEL_ID:
+				//no-op. Not implemented.
+				break;
+			case STR_PBB_ISID:
+				//no-op. Not implemented.
+				break;
+			default:
+				throw new IllegalArgumentException("unknown token " + key_value + " parsing " + match);
+			} 
+		}
+		return mb.build();
+	}
+}
diff --git a/src/main/java/net/floodlightcontroller/util/OFMatchWithSwDpid.java b/src/main/java/net/floodlightcontroller/util/OFMatchWithSwDpid.java
new file mode 100644
index 0000000000000000000000000000000000000000..b71ed6c3dabfac9ab6741b6aa14e425fb2f32a15
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/OFMatchWithSwDpid.java
@@ -0,0 +1,35 @@
+package net.floodlightcontroller.util;
+
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.types.DatapathId;
+
+public class OFMatchWithSwDpid {
+	private Match match;
+	private DatapathId dpid;
+	
+	public OFMatchWithSwDpid(Match match, DatapathId dpid) {
+		this.match = match;
+		this.dpid = dpid;
+	}
+	public OFMatchWithSwDpid() {
+		this.match = null;
+		this.dpid = DatapathId.NONE;
+	}
+	
+	public Match getMatch() {
+		return match;
+	}
+	
+	public void setMatch(Match match) {
+		this.match = match;
+	}
+	
+	public DatapathId getDpid() {
+		return dpid;
+	}
+	
+	public void setDpid(DatapathId dpid) {
+		this.dpid = dpid;
+	}
+	
+}
diff --git a/src/main/java/net/floodlightcontroller/util/OFMessageDamper.java b/src/main/java/net/floodlightcontroller/util/OFMessageDamper.java
index 75b0b00d3a9fb082e14a18e3da34712fcdee4e36..e599968ecd78e2f8dd937758094a2b36b1a19602 100644
--- a/src/main/java/net/floodlightcontroller/util/OFMessageDamper.java
+++ b/src/main/java/net/floodlightcontroller/util/OFMessageDamper.java
@@ -22,9 +22,10 @@ import java.util.Set;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.LogicalOFMessageCategory;
 
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
 
 /**
  * Dampens OFMessages sent to an OF switch. A message is only written to 
@@ -115,8 +116,7 @@ public class OFMessageDamper {
      * the message was dampened. 
      * @throws IOException
      */
-    public boolean write(IOFSwitch sw, OFMessage msg, FloodlightContext cntx)
-                    throws IOException {
+    public boolean write(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) throws IOException {
         return write(sw, msg, cntx, false);
     }
     
@@ -130,11 +130,9 @@ public class OFMessageDamper {
      * the message was dampened. 
      * @throws IOException
      */
-    public boolean write(IOFSwitch sw, OFMessage msg,
-                        FloodlightContext cntx, boolean flush) 
-            throws IOException {
+    public boolean write(IOFSwitch sw, OFMessage msg, FloodlightContext cntx, boolean flush) throws IOException {
         if (! msgTypesToCache.contains(msg.getType())) {
-            sw.writeThrottled(msg, cntx);
+            sw.write(msg, LogicalOFMessageCategory.MAIN);
             if (flush) {
                 sw.flush();
             }
@@ -146,7 +144,7 @@ public class OFMessageDamper {
             // entry exists in cache. Dampening.
             return false; 
         } else {
-            sw.writeThrottled(msg, cntx);
+            sw.write(msg);
             if (flush) {
                 sw.flush();
             }
diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/HostResource.java b/src/main/java/net/floodlightcontroller/virtualnetwork/HostResource.java
index 03f0a63ae3b93f20a1b370048fd81884bbd83cf5..b2eae7c74e3f09990e1e40fd7a1611832a6d7d2c 100644
--- a/src/main/java/net/floodlightcontroller/virtualnetwork/HostResource.java
+++ b/src/main/java/net/floodlightcontroller/virtualnetwork/HostResource.java
@@ -18,12 +18,12 @@ package net.floodlightcontroller.virtualnetwork;
 
 import java.io.IOException;
 
-import net.floodlightcontroller.util.MACAddress;
-
 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.MacAddress;
 import org.restlet.data.Status;
 import org.restlet.resource.Delete;
 import org.restlet.resource.Put;
@@ -92,7 +92,7 @@ public class HostResource extends org.restlet.resource.ServerResource {
         } catch (IOException e) {
             log.error("Could not parse JSON {}", e.getMessage());
         }
-        vns.addHost(MACAddress.valueOf(host.mac), host.guid, host.port);
+        vns.addHost(MacAddress.of(host.mac), host.guid, host.port);
         setStatus(Status.SUCCESS_OK);
         return "{\"status\":\"ok\"}";
     }
diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/IVirtualNetworkService.java b/src/main/java/net/floodlightcontroller/virtualnetwork/IVirtualNetworkService.java
index 993b2ffd04553bdab3ff9c73f5ac58fa1a0f283b..d3ebada8e3d56836dbf224c10f8e319341aadd43 100644
--- a/src/main/java/net/floodlightcontroller/virtualnetwork/IVirtualNetworkService.java
+++ b/src/main/java/net/floodlightcontroller/virtualnetwork/IVirtualNetworkService.java
@@ -17,8 +17,11 @@
 package net.floodlightcontroller.virtualnetwork;
 
 import java.util.Collection;
+
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+
 import net.floodlightcontroller.core.module.IFloodlightService;
-import net.floodlightcontroller.util.MACAddress;
 
 public interface IVirtualNetworkService extends IFloodlightService {
     /**
@@ -29,7 +32,7 @@ public interface IVirtualNetworkService extends IFloodlightService {
      * @param guid The ID of the network. Must be unique.
      * @param gateway The IP address of the network gateway, null if none.
      */
-    public void createNetwork(String guid, String network, Integer gateway);
+    public void createNetwork(String guid, String network, IPv4Address gateway);
     
     /**
      * Deletes a virtual network.
@@ -44,7 +47,7 @@ public interface IVirtualNetworkService extends IFloodlightService {
      * @param network The network to add the host to.
      * @param port The logical port name to attach the host to. Must be unique.
      */
-    public void addHost(MACAddress mac, String network, String port); 
+    public void addHost(MacAddress mac, String network, String port); 
     
     /**
      * Deletes a host from a virtual network. Either the MAC or Port must
@@ -52,7 +55,7 @@ public interface IVirtualNetworkService extends IFloodlightService {
      * @param mac The MAC address to delete.
      * @param port The logical port the host is attached to.
      */
-    public void deleteHost(MACAddress mac, String port);
+    public void deleteHost(MacAddress mac, String port);
     
     /**
      * Return list of all virtual networks.
diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/NetworkResource.java b/src/main/java/net/floodlightcontroller/virtualnetwork/NetworkResource.java
index 35ff629f4c557f5185585c3440fbaa22e77d43c9..735415d828e8e4f7d577405a796fbccfd2e44aef 100644
--- a/src/main/java/net/floodlightcontroller/virtualnetwork/NetworkResource.java
+++ b/src/main/java/net/floodlightcontroller/virtualnetwork/NetworkResource.java
@@ -19,12 +19,12 @@ package net.floodlightcontroller.virtualnetwork;
 import java.io.IOException;
 import java.util.Collection;
 
-import net.floodlightcontroller.packet.IPv4;
-
 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.IPv4Address;
 import org.restlet.data.Status;
 import org.restlet.resource.Delete;
 import org.restlet.resource.Get;
@@ -122,10 +122,10 @@ public class NetworkResource extends ServerResource {
                 (IVirtualNetworkService)getContext().getAttributes().
                     get(IVirtualNetworkService.class.getCanonicalName());
         
-        Integer gw = null;
+        IPv4Address gw = null;
         if (network.gateway != null) {
             try {
-                gw = IPv4.toIPv4Address(network.gateway);
+                gw = IPv4Address.of(network.gateway);
             } catch (IllegalArgumentException e) {
                 log.warn("Could not parse gateway {} as IP for network {}, setting as null",
                          network.gateway, network.name);
diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetwork.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetwork.java
index 829be702a36039fcfafa1140c68c6c958dffed2c..32a2e72f2b129f5b79338f73a8d18c8215706528 100644
--- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetwork.java
+++ b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetwork.java
@@ -19,9 +19,10 @@ package net.floodlightcontroller.virtualnetwork;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
-import net.floodlightcontroller.util.MACAddress;
+import org.projectfloodlight.openflow.types.MacAddress;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
 /**
  * Data structure for storing and outputing information of a virtual network created
@@ -35,7 +36,7 @@ public class VirtualNetwork{
     protected String name; // network name
     protected String guid; // network id
     protected String gateway; // network gateway
-	protected Map<String,MACAddress> portToMac; //port's logical namd and the host's mac address connected
+	protected Map<String, MacAddress> portToMac; //port's logical namd and the host's mac address connected
     /**
      * Constructor requires network name and id
      * @param name: network name
@@ -45,7 +46,7 @@ public class VirtualNetwork{
         this.name = name;
         this.guid = guid;
         this.gateway = null;
-		this.portToMac = new ConcurrentHashMap<String,MACAddress>();
+		this.portToMac = new ConcurrentHashMap<String,MacAddress>();
         return;        
     }
 
@@ -71,9 +72,9 @@ public class VirtualNetwork{
      * Adds a host to this network record
      * @param host: MAC address as MACAddress
      */
-    public void addHost(String port,MACAddress host){
-        this.portToMac.put(port,host); // ignore old mapping
-        return;        
+    public void addHost(String port, MacAddress host){
+        this.portToMac.put(port, host); // ignore old mapping
+        return;         
     }
     
     /**
@@ -81,9 +82,9 @@ public class VirtualNetwork{
      * @param host: MAC address as MACAddress
      * @return boolean: true: removed, false: host not found
      */
-    public boolean removeHost(MACAddress host){
-		for (Entry<String,MACAddress> entry : this.portToMac.entrySet()){
-			if(entry.getValue().equals(host)){
+    public boolean removeHost(MacAddress host){
+		for (Entry<String, MacAddress> entry : this.portToMac.entrySet()) {
+			if (entry.getValue().equals(host)){
 				this.portToMac.remove(entry.getKey());
 				return true;
 			}
diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java
index 1d64144dcf19a3d9a73fce36b3976f8b7d4cbaec..f5ea145c4af628df9331907d7ca7ca5942969f34 100644
--- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java
+++ b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java
@@ -16,7 +16,6 @@
 
 package net.floodlightcontroller.virtualnetwork;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -28,14 +27,15 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
-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.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.U64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -54,10 +54,8 @@ import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.packet.DHCP;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
-import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.routing.ForwardingBase;
-import net.floodlightcontroller.util.MACAddress;
 
 /**
  * A simple Layer 2 (MAC based) network virtualization module. This module allows
@@ -73,492 +71,480 @@ import net.floodlightcontroller.util.MACAddress;
  * @author alexreimers
  */
 public class VirtualNetworkFilter
-    implements IFloodlightModule, IVirtualNetworkService, IOFMessageListener {
-    protected static Logger log = LoggerFactory.getLogger(VirtualNetworkFilter.class);
-
-    private static final short APP_ID = 20;
-    static {
-        AppCookie.registerApp(APP_ID, "VirtualNetworkFilter");
-    }
-
-    // Our dependencies
-    IFloodlightProviderService floodlightProvider;
-    IRestApiService restApi;
-    IDeviceService deviceService;
-
-    // Our internal state
-    protected Map<String, VirtualNetwork> vNetsByGuid; // List of all created virtual networks
-    protected Map<String, String> nameToGuid; // Logical name -> Network ID
-    protected Map<String, Integer> guidToGateway; // Network ID -> Gateway IP
-    protected Map<Integer, Set<String>> gatewayToGuid; // Gateway IP -> Network ID
-    protected Map<MACAddress, Integer> macToGateway; // Gateway MAC -> Gateway IP
-    protected Map<MACAddress, String> macToGuid; // Host MAC -> Network ID
-    protected Map<String, MACAddress> portToMac; // Host MAC -> logical port name
-
-    // Device Listener impl class
-    protected DeviceListenerImpl deviceListener;
-
-    /**
-     * Adds a gateway to a virtual network.
-     * @param guid The ID (not name) of the network.
-     * @param ip The IP addresses of the gateway.
-     */
-    protected void addGateway(String guid, Integer ip) {
-        if (ip.intValue() != 0) {
-            if (log.isDebugEnabled()) {
-                log.debug("Adding {} as gateway for GUID {}",
-                    IPv4.fromIPv4Address(ip), guid);
-            }
-
-            guidToGateway.put(guid, ip);
-            if (vNetsByGuid.get(guid) != null)
-                vNetsByGuid.get(guid).setGateway(IPv4.fromIPv4Address(ip));
-            if (gatewayToGuid.containsKey(ip)) {
-                Set<String> gSet = gatewayToGuid.get(ip);
-                gSet.add(guid);
-            } else {
-                Set<String> gSet = Collections.synchronizedSet(new HashSet<String>());
-                gSet.add(guid);
-                gatewayToGuid.put(ip, gSet);
-            }
-        }
-    }
-
-    /**
-     * Deletes a gateway for a virtual network.
-     * @param guid The ID (not name) of the network to delete
-     * the gateway for.
-     */
-    protected void deleteGateway(String guid) {
-        Integer gwIp = guidToGateway.remove(guid);
-        if (gwIp == null) return;
-        Set<String> gSet = gatewayToGuid.get(gwIp);
-        gSet.remove(guid);
-        if(vNetsByGuid.get(guid)!=null)
-            vNetsByGuid.get(guid).setGateway(null);
-    }
-
-    // IVirtualNetworkService
-
-    @Override
-    public void createNetwork(String guid, String network, Integer gateway) {
-        if (log.isDebugEnabled()) {
-            String gw = null;
-            try {
-                gw = IPv4.fromIPv4Address(gateway);
-            } catch (Exception e) {
-                // fail silently
-            }
-            log.debug("Creating network {} with ID {} and gateway {}",
-                      new Object[] {network, guid, gw});
-        }
-
-        if (!nameToGuid.isEmpty()) {
-            // We have to iterate all the networks to handle name/gateway changes
-            for (Entry<String, String> entry : nameToGuid.entrySet()) {
-                if (entry.getValue().equals(guid)) {
-                    nameToGuid.remove(entry.getKey());
-                    break;
-                }
-            }
-        }
-        if(network != null)
-            nameToGuid.put(network, guid);
-        if (vNetsByGuid.containsKey(guid))
-            vNetsByGuid.get(guid).setName(network); //network already exists, just updating name
-        else
-            vNetsByGuid.put(guid, new VirtualNetwork(network, guid)); //new network
-
-        // If they don't specify a new gateway the old one will be preserved
-        if ((gateway != null) && (gateway != 0)) {
-            addGateway(guid, gateway);
-            if(vNetsByGuid.get(guid)!=null)
-                vNetsByGuid.get(guid).setGateway(IPv4.fromIPv4Address(gateway));
-        }
-    }
-
-    @Override
-    public void deleteNetwork(String guid) {
-        String name = null;
-        if (nameToGuid.isEmpty()) {
-            log.warn("Could not delete network with ID {}, network doesn't exist",
-                     guid);
-            return;
-        }
-        for (Entry<String, String> entry : nameToGuid.entrySet()) {
-            if (entry.getValue().equals(guid)) {
-                name = entry.getKey();
-                break;
-            }
-            log.warn("Could not delete network with ID {}, network doesn't exist",
-                     guid);
-        }
-
-        if (log.isDebugEnabled())
-            log.debug("Deleting network with name {} ID {}", name, guid);
-
-        nameToGuid.remove(name);
-        deleteGateway(guid);
-        if(vNetsByGuid.get(guid)!=null){
-            vNetsByGuid.get(guid).clearHosts();
-            vNetsByGuid.remove(guid);
-        }
-        Collection<MACAddress> deleteList = new ArrayList<MACAddress>();
-        for (MACAddress host : macToGuid.keySet()) {
-            if (macToGuid.get(host).equals(guid)) {
-                deleteList.add(host);
-            }
-        }
-        for (MACAddress mac : deleteList) {
-            if (log.isDebugEnabled()) {
-                log.debug("Removing host {} from network {}",
-                          HexString.toHexString(mac.toBytes()), guid);
-            }
-            macToGuid.remove(mac);
-            for (Entry<String, MACAddress> entry : portToMac.entrySet()) {
-                if (entry.getValue().equals(mac)) {
-                    portToMac.remove(entry.getKey());
-                    break;
-                }
-            }
-        }
-    }
-
-    @Override
-    public void addHost(MACAddress mac, String guid, String port) {
-        if (guid != null) {
-            if (log.isDebugEnabled()) {
-                log.debug("Adding {} to network ID {} on port {}",
-                          new Object[] {mac, guid, port});
-            }
-            // We ignore old mappings
-            macToGuid.put(mac, guid);
-            portToMac.put(port, mac);
-            if(vNetsByGuid.get(guid)!=null)
-                vNetsByGuid.get(guid).addHost(port,new MACAddress(mac.toBytes()));
-        } else {
-            log.warn("Could not add MAC {} to network ID {} on port {}, the network does not exist",
-                     new Object[] {mac, guid, port});
-        }
-    }
-
-    @Override
-    public void deleteHost(MACAddress mac, String port) {
-        if (log.isDebugEnabled()) {
-            log.debug("Removing host {} from port {}", mac, port);
-        }
-        if (mac == null && port == null) return;
-        if (port != null) {
-            MACAddress host = portToMac.remove(port);
-            if(host !=null && vNetsByGuid.get(macToGuid.get(host)) != null)
-                vNetsByGuid.get(macToGuid.get(host)).removeHost(host);
-			if(host !=null)
-	            macToGuid.remove(host);
-        } else if (mac != null) {
-            if (!portToMac.isEmpty()) {
-                for (Entry<String, MACAddress> entry : portToMac.entrySet()) {
-                    if (entry.getValue().equals(mac)) {
-                        if(vNetsByGuid.get(macToGuid.get(entry.getValue())) != null)
-                            vNetsByGuid.get(macToGuid.get(entry.getValue())).removeHost(entry.getValue());
-                        portToMac.remove(entry.getKey());
-                        macToGuid.remove(entry.getValue());
-                        return;
-                    }
-                }
-            }
-        }
-    }
-
-    // IFloodlightModule
-
-    @Override
-    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        Collection<Class<? extends IFloodlightService>> l =
-                new ArrayList<Class<? extends IFloodlightService>>();
-        l.add(IVirtualNetworkService.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(IVirtualNetworkService.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(IRestApiService.class);
-        l.add(IDeviceService.class);
-        return l;
-    }
-
-    @Override
-    public void init(FloodlightModuleContext context)
-                                 throws FloodlightModuleException {
-        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-        restApi = context.getServiceImpl(IRestApiService.class);
-        deviceService = context.getServiceImpl(IDeviceService.class);
-
-        vNetsByGuid = new ConcurrentHashMap<String, VirtualNetwork>();
-        nameToGuid = new ConcurrentHashMap<String, String>();
-        guidToGateway = new ConcurrentHashMap<String, Integer>();
-        gatewayToGuid = new ConcurrentHashMap<Integer, Set<String>>();
-        macToGuid = new ConcurrentHashMap<MACAddress, String>();
-        portToMac = new ConcurrentHashMap<String, MACAddress>();
-        macToGateway = new ConcurrentHashMap<MACAddress, Integer>();
-        deviceListener = new DeviceListenerImpl();
-
-    }
-
-    @Override
-    public void startUp(FloodlightModuleContext context) {
-        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-        restApi.addRestletRoutable(new VirtualNetworkWebRoutable());
-        deviceService.addListener(this.deviceListener);
-    }
-
-    // IOFMessageListener
-
-    @Override
-    public String getName() {
-        return "virtualizer";
-    }
-
-    @Override
-    public boolean isCallbackOrderingPrereq(OFType type, String name) {
-        // Link discovery should go before us so we don't block LLDPs
-        return (type.equals(OFType.PACKET_IN) &&
-                (name.equals("linkdiscovery") || (name.equals("devicemanager"))));
-    }
-
-    @Override
-    public boolean isCallbackOrderingPostreq(OFType type, String name) {
-        // We need to go before forwarding
-        return (type.equals(OFType.PACKET_IN) && name.equals("forwarding"));
-    }
-
-    @Override
-    public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
-        switch (msg.getType()) {
-            case PACKET_IN:
-                return processPacketIn(sw, (OFPacketIn)msg, cntx);
-            default:
-                break;
-        }
-        log.warn("Received unexpected message {}", msg);
-        return Command.CONTINUE;
-    }
-
-    /**
-     * Checks whether the frame is destined to or from a gateway.
-     * @param frame The ethernet frame to check.
-     * @return True if it is to/from a gateway, false otherwise.
-     */
-    protected boolean isDefaultGateway(Ethernet frame) {
-        if (macToGateway.containsKey(frame.getSourceMAC()))
-            return true;
-
-        Integer gwIp = macToGateway.get(frame.getDestinationMAC());
-        if (gwIp != null) {
-            MACAddress host = frame.getSourceMAC();
-            String srcNet = macToGuid.get(host);
-            if (srcNet != null) {
-                Integer gwIpSrcNet = guidToGateway.get(srcNet);
-                if ((gwIpSrcNet != null) && (gwIp.equals(gwIpSrcNet)))
-                    return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Checks to see if two MAC Addresses are on the same network.
-     * @param m1 The first MAC.
-     * @param m2 The second MAC.
-     * @return True if they are on the same virtual network,
-     *          false otherwise.
-     */
-    protected boolean oneSameNetwork(MACAddress m1, MACAddress m2) {
-        String net1 = macToGuid.get(m1);
-        String net2 = macToGuid.get(m2);
-        if (net1 == null) return false;
-        if (net2 == null) return false;
-        return net1.equals(net2);
-    }
-
-    /**
-     * Checks to see if an Ethernet frame is a DHCP packet.
-     * @param frame The Ethernet frame.
-     * @return True if it is a DHCP frame, false otherwise.
-     */
-    protected boolean isDhcpPacket(Ethernet frame) {
-        IPacket payload = frame.getPayload(); // IP
-        if (payload == null) return false;
-        IPacket p2 = payload.getPayload(); // TCP or UDP
-        if (p2 == null) return false;
-        IPacket p3 = p2.getPayload(); // Application
-        if ((p3 != null) && (p3 instanceof DHCP)) return true;
-        return false;
-    }
-
-    /**
-     * Processes an OFPacketIn message and decides if the OFPacketIn should be dropped
-     * or the processing should continue.
-     * @param sw The switch the PacketIn came from.
-     * @param msg The OFPacketIn message from the switch.
-     * @param cntx The FloodlightContext for this message.
-     * @return Command.CONTINUE if processing should be continued, Command.STOP otherwise.
-     */
-    protected Command processPacketIn(IOFSwitch sw, OFPacketIn msg, FloodlightContext cntx) {
-        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
-                                              IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-        Command ret = Command.STOP;
-        String srcNetwork = macToGuid.get(eth.getSourceMAC());
-        // If the host is on an unknown network we deny it.
-        // We make exceptions for ARP and DHCP.
-        if (eth.isBroadcast() || eth.isMulticast() || isDefaultGateway(eth) || isDhcpPacket(eth)) {
-            ret = Command.CONTINUE;
-        } else if (srcNetwork == null) {
-            log.trace("Blocking traffic from host {} because it is not attached to any network.",
-                      HexString.toHexString(eth.getSourceMACAddress()));
-            ret = Command.STOP;
-        } else if (oneSameNetwork(eth.getSourceMAC(), eth.getDestinationMAC())) {
-            // if they are on the same network continue
-            ret = Command.CONTINUE;
-        }
-
-        if (log.isTraceEnabled())
-            log.trace("Results for flow between {} and {} is {}",
-                    new Object[] {eth.getSourceMAC(), eth.getDestinationMAC(), ret});
-        /*
-         * TODO - figure out how to still detect gateways while using
-         * drop mods
+implements IFloodlightModule, IVirtualNetworkService, IOFMessageListener {
+	protected static Logger log = LoggerFactory.getLogger(VirtualNetworkFilter.class);
+
+	private static final short APP_ID = 20;
+	static {
+		AppCookie.registerApp(APP_ID, "VirtualNetworkFilter");
+	}
+
+	// Our dependencies
+	IFloodlightProviderService floodlightProviderService;
+	IRestApiService restApiService;
+	IDeviceService deviceService;
+
+	// Our internal state
+	protected Map<String, VirtualNetwork> vNetsByGuid; // List of all created virtual networks
+	protected Map<String, String> nameToGuid; // Logical name -> Network ID
+	protected Map<String, IPv4Address> guidToGateway; // Network ID -> Gateway IP
+	protected Map<IPv4Address, Set<String>> gatewayToGuid; // Gateway IP -> Network ID
+	protected Map<MacAddress, IPv4Address> macToGateway; // Gateway MAC -> Gateway IP
+	protected Map<MacAddress, String> macToGuid; // Host MAC -> Network ID
+	protected Map<String, MacAddress> portToMac; // Host MAC -> logical port name
+
+	// Device Listener impl class
+	protected DeviceListenerImpl deviceListener;
+
+	/**
+	 * Adds a gateway to a virtual network.
+	 * @param guid The ID (not name) of the network.
+	 * @param ip The IP addresses of the gateway.
+	 */
+	protected void addGateway(String guid, IPv4Address ip) {
+		if (ip.getInt() != 0) {
+			if (log.isDebugEnabled()) {
+				log.debug("Adding {} as gateway for GUID {}", ip.toString(), guid);
+			}
+
+			guidToGateway.put(guid, ip);
+			if (vNetsByGuid.get(guid) != null)
+				vNetsByGuid.get(guid).setGateway(ip.toString());
+			if (gatewayToGuid.containsKey(ip)) {
+				Set<String> gSet = gatewayToGuid.get(ip);
+				gSet.add(guid);
+			} else {
+				Set<String> gSet = Collections.synchronizedSet(new HashSet<String>());
+				gSet.add(guid);
+				gatewayToGuid.put(ip, gSet);
+			}
+		}
+	}
+
+	/**
+	 * Deletes a gateway for a virtual network.
+	 * @param guid The ID (not name) of the network to delete
+	 * the gateway for.
+	 */
+	protected void deleteGateway(String guid) {
+		IPv4Address gwIp = guidToGateway.remove(guid);
+		if (gwIp == null) return;
+		Set<String> gSet = gatewayToGuid.get(gwIp);
+		gSet.remove(guid);
+		if (vNetsByGuid.get(guid) != null)
+			vNetsByGuid.get(guid).setGateway(null);
+	}
+
+	// IVirtualNetworkService
+
+	@Override
+	public void createNetwork(String guid, String network, IPv4Address gateway) {
+		if (log.isDebugEnabled()) {
+			String gw = null;
+			try {
+				gw = gateway.toString();
+			} catch (Exception e) {
+				// fail silently
+			}
+			log.debug("Creating network {} with ID {} and gateway {}",
+					new Object[] {network, guid, gw});
+		}
+
+		if (!nameToGuid.isEmpty()) {
+			// We have to iterate all the networks to handle name/gateway changes
+			for (Entry<String, String> entry : nameToGuid.entrySet()) {
+				if (entry.getValue().equals(guid)) {
+					nameToGuid.remove(entry.getKey());
+					break;
+				}
+			}
+		}
+		if(network != null)
+			nameToGuid.put(network, guid);
+		if (vNetsByGuid.containsKey(guid))
+			vNetsByGuid.get(guid).setName(network); //network already exists, just updating name
+		else
+			vNetsByGuid.put(guid, new VirtualNetwork(network, guid)); //new network
+
+		// If they don't specify a new gateway the old one will be preserved
+		if ((gateway != null) && (gateway.getInt() != 0)) {
+			addGateway(guid, gateway);
+			if (vNetsByGuid.get(guid) != null)
+				vNetsByGuid.get(guid).setGateway(gateway.toString());
+		}
+	}
+
+	@Override
+	public void deleteNetwork(String guid) {
+		String name = null;
+		if (nameToGuid.isEmpty()) {
+			log.warn("Could not delete network with ID {}, network doesn't exist",
+					guid);
+			return;
+		}
+		for (Entry<String, String> entry : nameToGuid.entrySet()) {
+			if (entry.getValue().equals(guid)) {
+				name = entry.getKey();
+				break;
+			}
+			log.warn("Could not delete network with ID {}, network doesn't exist", guid);
+		}
+
+		if (log.isDebugEnabled())
+			log.debug("Deleting network with name {} ID {}", name, guid);
+
+		nameToGuid.remove(name);
+		deleteGateway(guid);
+		if (vNetsByGuid.get(guid) != null){
+			vNetsByGuid.get(guid).clearHosts();
+			vNetsByGuid.remove(guid);
+		}
+		Collection<MacAddress> deleteList = new ArrayList<MacAddress>();
+		for (MacAddress host : macToGuid.keySet()) {
+			if (macToGuid.get(host).equals(guid)) {
+				deleteList.add(host);
+			}
+		}
+		for (MacAddress mac : deleteList) {
+			if (log.isDebugEnabled()) {
+				log.debug("Removing host {} from network {}", mac.toString(), guid);
+			}
+			macToGuid.remove(mac);
+			for (Entry<String, MacAddress> entry : portToMac.entrySet()) {
+				if (entry.getValue().equals(mac)) {
+					portToMac.remove(entry.getKey());
+					break;
+				}
+			}
+		}
+	}
+
+	@Override
+	public void addHost(MacAddress mac, String guid, String port) {
+		if (guid != null) {
+			if (log.isDebugEnabled()) {
+				log.debug("Adding {} to network ID {} on port {}",
+						new Object[] {mac, guid, port});
+			}
+			// We ignore old mappings
+			macToGuid.put(mac, guid);
+			portToMac.put(port, mac);
+			if (vNetsByGuid.get(guid) != null)
+				vNetsByGuid.get(guid).addHost(port, mac);
+		} else {
+			log.warn("Could not add MAC {} to network ID {} on port {}, the network does not exist",
+					new Object[] {mac.toString(), guid, port});
+		}
+	}
+
+	@Override
+	public void deleteHost(MacAddress mac, String port) {
+		if (log.isDebugEnabled()) {
+			log.debug("Removing host {} from port {}", mac, port);
+		}
+		if (mac == null && port == null) return;
+		if (port != null) {
+			MacAddress host = portToMac.remove(port);
+			if (host != null && vNetsByGuid.get(macToGuid.get(host)) != null)
+				vNetsByGuid.get(macToGuid.get(host)).removeHost(host);
+			if (host != null)
+				macToGuid.remove(host);
+		} else if (mac != null) {
+			if (!portToMac.isEmpty()) {
+				for (Entry<String, MacAddress> entry : portToMac.entrySet()) {
+					if (entry.getValue().equals(mac)) {
+						if (vNetsByGuid.get(macToGuid.get(entry.getValue())) != null)
+							vNetsByGuid.get(macToGuid.get(entry.getValue())).removeHost(entry.getValue());
+						portToMac.remove(entry.getKey());
+						macToGuid.remove(entry.getValue());
+						return;
+					}
+				}
+			}
+		}
+	}
+
+	// IFloodlightModule
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		Collection<Class<? extends IFloodlightService>> l =
+				new ArrayList<Class<? extends IFloodlightService>>();
+		l.add(IVirtualNetworkService.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(IVirtualNetworkService.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(IRestApiService.class);
+		l.add(IDeviceService.class);
+		return l;
+	}
+
+	@Override
+	public void init(FloodlightModuleContext context)
+			throws FloodlightModuleException {
+		floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+		restApiService = context.getServiceImpl(IRestApiService.class);
+		deviceService = context.getServiceImpl(IDeviceService.class);
+
+		vNetsByGuid = new ConcurrentHashMap<String, VirtualNetwork>();
+		nameToGuid = new ConcurrentHashMap<String, String>();
+		guidToGateway = new ConcurrentHashMap<String, IPv4Address>();
+		gatewayToGuid = new ConcurrentHashMap<IPv4Address, Set<String>>();
+		macToGuid = new ConcurrentHashMap<MacAddress, String>();
+		portToMac = new ConcurrentHashMap<String, MacAddress>();
+		macToGateway = new ConcurrentHashMap<MacAddress, IPv4Address>();
+		deviceListener = new DeviceListenerImpl();
+
+	}
+
+	@Override
+	public void startUp(FloodlightModuleContext context) {
+		floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
+		restApiService.addRestletRoutable(new VirtualNetworkWebRoutable());
+		deviceService.addListener(this.deviceListener);
+	}
+
+	// IOFMessageListener
+
+	@Override
+	public String getName() {
+		return "virtualizer";
+	}
+
+	@Override
+	public boolean isCallbackOrderingPrereq(OFType type, String name) {
+		// Link discovery should go before us so we don't block LLDPs
+		return (type.equals(OFType.PACKET_IN) &&
+				(name.equals("linkdiscovery") || (name.equals("devicemanager"))));
+	}
+
+	@Override
+	public boolean isCallbackOrderingPostreq(OFType type, String name) {
+		// We need to go before forwarding
+		return (type.equals(OFType.PACKET_IN) && name.equals("forwarding"));
+	}
+
+	@Override
+	public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+		switch (msg.getType()) {
+		case PACKET_IN:
+			return processPacketIn(sw, (OFPacketIn)msg, cntx);
+		default:
+			break;
+		}
+		log.warn("Received unexpected message {}", msg);
+		return Command.CONTINUE;
+	}
+
+	/**
+	 * Checks whether the frame is destined to or from a gateway.
+	 * @param frame The ethernet frame to check.
+	 * @return True if it is to/from a gateway, false otherwise.
+	 */
+	protected boolean isDefaultGateway(Ethernet frame) {
+		if (macToGateway.containsKey(frame.getSourceMACAddress()))
+			return true;
+
+		IPv4Address gwIp = macToGateway.get(frame.getDestinationMACAddress());
+		if (gwIp != null) {
+			MacAddress host = frame.getSourceMACAddress();
+			String srcNet = macToGuid.get(host);
+			if (srcNet != null) {
+				IPv4Address gwIpSrcNet = guidToGateway.get(srcNet);
+				if ((gwIpSrcNet != null) && (gwIp.equals(gwIpSrcNet)))
+					return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Checks to see if two MAC Addresses are on the same network.
+	 * @param m1 The first MAC.
+	 * @param m2 The second MAC.
+	 * @return True if they are on the same virtual network,
+	 *          false otherwise.
+	 */
+	protected boolean oneSameNetwork(MacAddress m1, MacAddress m2) {
+		String net1 = macToGuid.get(m1);
+		String net2 = macToGuid.get(m2);
+		if (net1 == null) return false;
+		if (net2 == null) return false;
+		return net1.equals(net2);
+	}
+
+	/**
+	 * Checks to see if an Ethernet frame is a DHCP packet.
+	 * @param frame The Ethernet frame.
+	 * @return True if it is a DHCP frame, false otherwise.
+	 */
+	protected boolean isDhcpPacket(Ethernet frame) {
+		IPacket payload = frame.getPayload(); // IP
+		if (payload == null) return false;
+		IPacket p2 = payload.getPayload(); // TCP or UDP
+		if (p2 == null) return false;
+		IPacket p3 = p2.getPayload(); // Application
+		if ((p3 != null) && (p3 instanceof DHCP)) return true;
+		return false;
+	}
+
+	/**
+	 * Processes an OFPacketIn message and decides if the OFPacketIn should be dropped
+	 * or the processing should continue.
+	 * @param sw The switch the PacketIn came from.
+	 * @param msg The OFPacketIn message from the switch.
+	 * @param cntx The FloodlightContext for this message.
+	 * @return Command.CONTINUE if processing should be continued, Command.STOP otherwise.
+	 */
+	protected Command processPacketIn(IOFSwitch sw, OFPacketIn msg, FloodlightContext cntx) {
+		Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
+				IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+		Command ret = Command.STOP;
+		String srcNetwork = macToGuid.get(eth.getSourceMACAddress());
+		// If the host is on an unknown network we deny it.
+		// We make exceptions for ARP and DHCP.
+		if (eth.isBroadcast() || eth.isMulticast() || isDefaultGateway(eth) || isDhcpPacket(eth)) {
+			ret = Command.CONTINUE;
+		} else if (srcNetwork == null) {
+			log.trace("Blocking traffic from host {} because it is not attached to any network.",
+					eth.getSourceMACAddress().toString());
+			ret = Command.STOP;
+		} else if (oneSameNetwork(eth.getSourceMACAddress(), eth.getDestinationMACAddress())) {
+			// if they are on the same network continue
+			ret = Command.CONTINUE;
+		}
+
+		if (log.isTraceEnabled())
+			log.trace("Results for flow between {} and {} is {}",
+					new Object[] {eth.getSourceMACAddress(), eth.getDestinationMACAddress(), ret});
+		/*
+		 * TODO - figure out how to still detect gateways while using
+		 * drop mods
         if (ret == Command.STOP) {
             if (!(eth.getPayload() instanceof ARP))
                 doDropFlow(sw, msg, cntx);
         }
-        */
-        return ret;
-    }
-
-    /**
-     * Writes a FlowMod to a switch that inserts a drop flow.
-     * @param sw The switch to write the FlowMod to.
-     * @param pi The corresponding OFPacketIn. Used to create the OFMatch structure.
-     * @param cntx The FloodlightContext that gets passed to the switch.
-     */
-    protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
-        if (log.isTraceEnabled()) {
-            log.trace("doDropFlow pi={} srcSwitch={}",
-                    new Object[] { pi, sw });
-        }
-
-        if (sw == null) {
-            log.warn("Switch is null, not installing drop flowmod for PacketIn {}", pi);
-            return;
-        }
-
-        // Create flow-mod based on packet-in and src-switch
-        OFFlowMod fm =
-            (OFFlowMod) floodlightProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD);
-        OFMatch match = new OFMatch();
-        match.loadFromPacket(pi.getPacketData(), pi.getInPort());
-        List<OFAction> actions = new ArrayList<OFAction>(); // no actions = drop
-        long cookie = AppCookie.makeCookie(APP_ID, 0);
-        fm.setCookie(cookie)
-        .setIdleTimeout(ForwardingBase.FLOWMOD_DEFAULT_IDLE_TIMEOUT)
-        .setHardTimeout(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT)
-        .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-        .setMatch(match)
-        .setActions(actions)
-        .setLengthU(OFFlowMod.MINIMUM_LENGTH);
-//        fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
-        try {
-            if (log.isTraceEnabled()) {
-                log.trace("write drop flow-mod srcSwitch={} match={} " +
-                          "pi={} flow-mod={}",
-                          new Object[] {sw, match, pi, fm});
-            }
-            sw.write(fm, cntx);
-        } catch (IOException e) {
-            log.error("Failure writing drop flow mod", e);
-        }
-        return;
-    }
-
-    @Override
-    public Collection <VirtualNetwork> listNetworks() {
-        return vNetsByGuid.values();
-    }
-
-    // IDeviceListener
-    class DeviceListenerImpl implements IDeviceListener{
-        @Override
-        public void deviceAdded(IDevice device) {
-            if (device.getIPv4Addresses() == null) return;
-            for (Integer i : device.getIPv4Addresses()) {
-                if (gatewayToGuid.containsKey(i)) {
-                    MACAddress mac = MACAddress.valueOf(device.getMACAddress());
-                    if (log.isDebugEnabled())
-                        log.debug("Adding MAC {} with IP {} a a gateway",
-                                    HexString.toHexString(mac.toBytes()),
-                                    IPv4.fromIPv4Address(i));
-                        macToGateway.put(mac, i);
-                    }
-                }
-            }
-
-            @Override
-        public void deviceRemoved(IDevice device) {
-            // if device is a gateway remove
-            MACAddress mac = MACAddress.valueOf(device.getMACAddress());
-            if (macToGateway.containsKey(mac)) {
-                if (log.isDebugEnabled())
-                    log.debug("Removing MAC {} as a gateway",
-                                HexString.toHexString(mac.toBytes()));
-                macToGateway.remove(mac);
-             }
-        }
-
-        @Override
-        public void deviceIPV4AddrChanged(IDevice device) {
-            // add or remove entry as gateway
-            deviceAdded(device);
-        }
-
-        @Override
-        public void deviceMoved(IDevice device) {
-            // ignore
-        }
-
-        @Override
-        public void deviceVlanChanged(IDevice device) {
-            // ignore
-        }
-
-        @Override
-        public String getName() {
-            return VirtualNetworkFilter.this.getName();
-        }
-
-        @Override
-        public boolean isCallbackOrderingPrereq(String type, String name) {
-            return false;
-        }
-
-        @Override
-        public boolean isCallbackOrderingPostreq(String type, String name) {
-            // We need to go before forwarding
-            return false;
-        }
-    }
+		 */
+		return ret;
+	}
+
+	/**
+	 * Writes a FlowMod to a switch that inserts a drop flow.
+	 * @param sw The switch to write the FlowMod to.
+	 * @param pi The corresponding OFPacketIn. Used to create the OFMatch structure.
+	 * @param cntx The FloodlightContext that gets passed to the switch.
+	 */
+	protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
+		if (log.isTraceEnabled()) {
+			log.trace("doDropFlow pi={} srcSwitch={}",
+					new Object[] { pi, sw });
+		}
+
+		if (sw == null) {
+			log.warn("Switch is null, not installing drop flowmod for PacketIn {}", pi);
+			return;
+		}
+
+		// Create flow-mod based on packet-in and src-switch
+		OFFlowMod.Builder fmb = sw.getOFFactory().buildFlowModify();
+		List<OFAction> actions = new ArrayList<OFAction>(); // no actions = drop
+		U64 cookie = AppCookie.makeCookie(APP_ID, 0);
+		fmb.setCookie(cookie)
+		.setIdleTimeout(ForwardingBase.FLOWMOD_DEFAULT_IDLE_TIMEOUT)
+		.setHardTimeout(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT)
+		.setBufferId(OFBufferId.NO_BUFFER)
+		.setMatch(pi.getMatch())
+		.setActions(actions);
+
+		if (log.isTraceEnabled()) {
+			log.trace("write drop flow-mod srcSwitch={} match={} " +
+					"pi={} flow-mod={}",
+					new Object[] {sw, pi.getMatch(), pi, fmb.build()});
+		}
+		sw.write(fmb.build());
+		return;
+	}
+
+	@Override
+	public Collection <VirtualNetwork> listNetworks() {
+		return vNetsByGuid.values();
+	}
+
+	// IDeviceListener
+	class DeviceListenerImpl implements IDeviceListener{
+		@Override
+		public void deviceAdded(IDevice device) {
+			if (device.getIPv4Addresses() == null) return;
+			for (IPv4Address i : device.getIPv4Addresses()) {
+				if (gatewayToGuid.containsKey(i)) {
+					MacAddress mac = device.getMACAddress();
+					if (log.isDebugEnabled())
+						log.debug("Adding MAC {} with IP {} a a gateway",
+								mac.toString(),
+								i.toString());
+					macToGateway.put(mac, i);
+				}
+			}
+		}
+
+		@Override
+		public void deviceRemoved(IDevice device) {
+			// if device is a gateway remove
+			MacAddress mac = device.getMACAddress();
+			if (macToGateway.containsKey(mac)) {
+				if (log.isDebugEnabled())
+					log.debug("Removing MAC {} as a gateway", mac.toString());
+				macToGateway.remove(mac);
+			}
+		}
+
+		@Override
+		public void deviceIPV4AddrChanged(IDevice device) {
+			// add or remove entry as gateway
+			deviceAdded(device);
+		}
+
+		@Override
+		public void deviceMoved(IDevice device) {
+			// ignore
+		}
+
+		@Override
+		public void deviceVlanChanged(IDevice device) {
+			// ignore
+		}
+
+		@Override
+		public String getName() {
+			return VirtualNetworkFilter.this.getName();
+		}
+
+		@Override
+		public boolean isCallbackOrderingPrereq(String type, String name) {
+			return false;
+		}
+
+		@Override
+		public boolean isCallbackOrderingPostreq(String type, String name) {
+			// We need to go before forwarding
+			return false;
+		}
+	}
 }
diff --git a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkSerializer.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkSerializer.java
index 190432ab7aeacefcaa89054ecebbb59e26845811..1a345de45b43f62c08fc27efeab94e4a9d90fc25 100644
--- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkSerializer.java
+++ b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkSerializer.java
@@ -20,7 +20,7 @@ import java.io.IOException;
 import java.util.Iterator;
 import java.util.Map.Entry;
 
-import net.floodlightcontroller.util.MACAddress;
+import org.projectfloodlight.openflow.types.MacAddress;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -44,10 +44,10 @@ public class VirtualNetworkSerializer extends JsonSerializer<VirtualNetwork> {
         jGen.writeStringField("gateway", vNet.gateway);
 
         jGen.writeArrayFieldStart("portMac");
-		Iterator entries = vNet.portToMac.entrySet().iterator();
+		Iterator<Entry<String, MacAddress>> entries = vNet.portToMac.entrySet().iterator();
 		while (entries.hasNext()){
 			jGen.writeStartObject();
-			Entry entry = (Entry)entries.next();
+			Entry<String, MacAddress> entry = entries.next();
 			jGen.writeStringField("port",entry.getKey().toString());
 			jGen.writeStringField("mac",entry.getValue().toString());
 			jGen.writeEndObject();
diff --git a/src/main/java/org/sdnplatform/sync/ISyncService.java b/src/main/java/org/sdnplatform/sync/ISyncService.java
index 75f3948a8e7b20d669492573b3dc616f8d9c54a7..48feead4a3c378e61147292203db3ccaa6435900 100644
--- a/src/main/java/org/sdnplatform/sync/ISyncService.java
+++ b/src/main/java/org/sdnplatform/sync/ISyncService.java
@@ -40,6 +40,8 @@ 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/SyncManager.java b/src/main/java/org/sdnplatform/sync/internal/SyncManager.java
index 952918c50217c91cc5a2c30b39a1f9c7cbf4b60b..cfe27e00e7738d7daeab5cd02162512e1ab19f3b 100644
--- a/src/main/java/org/sdnplatform/sync/internal/SyncManager.java
+++ b/src/main/java/org/sdnplatform/sync/internal/SyncManager.java
@@ -60,8 +60,6 @@ import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.util.SingletonTask;
 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.storage.IStorageSourceService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 
@@ -513,39 +511,28 @@ public class SyncManager extends AbstractSyncManager {
 
     private void registerDebugCounters(FloodlightModuleContext context)
             throws FloodlightModuleException {
-        if (context != null) {
-            try {
-                counterHints = debugCounter.registerCounter(PACKAGE, "hints",
-                                    "Queued sync events processed",
-                                    CounterType.ALWAYS_COUNT);
-                counterSentValues = debugCounter.registerCounter(PACKAGE, "sent-values",
-                                    "Values synced to remote node",
-                                    CounterType.ALWAYS_COUNT);
-                counterReceivedValues = debugCounter.registerCounter(PACKAGE, "received-values",
-                                    "Values received from remote node",
-                                    CounterType.ALWAYS_COUNT);
-                counterPuts = debugCounter.registerCounter(PACKAGE, "puts",
-                                    "Local puts to store",
-                                    CounterType.ALWAYS_COUNT);
-                counterGets = debugCounter.registerCounter(PACKAGE, "gets",
-                                    "Local gets from store",
-                                    CounterType.ALWAYS_COUNT);
-                counterIterators = debugCounter.registerCounter(PACKAGE, "iterators",
-                                    "Local iterators created over store",
-                                    CounterType.ALWAYS_COUNT);
-                counterErrorRemote = debugCounter.registerCounter(PACKAGE, "error-remote",
-                                    "Number of errors sent from remote clients",
-                                    CounterType.ALWAYS_COUNT,
-                                    IDebugCounterService.CTR_MDATA_ERROR);
-                counterErrorProcessing = debugCounter.registerCounter(PACKAGE,
-                                    "error-processing",
-                                    "Number of errors processing messages from remote clients",
-                                    CounterType.ALWAYS_COUNT,
-                                    IDebugCounterService.CTR_MDATA_ERROR);
-            } catch (CounterException e) {
-                throw new FloodlightModuleException(e.getMessage());
-            }
-        }
+    	if (context != null) {
+    		debugCounter.registerModule(PACKAGE);
+    		counterHints = debugCounter.registerCounter(PACKAGE, "hints",
+    				"Queued sync events processed");
+    		counterSentValues = debugCounter.registerCounter(PACKAGE, "sent-values",
+    				"Values synced to remote node");
+    		counterReceivedValues = debugCounter.registerCounter(PACKAGE, "received-values",
+    				"Values received from remote node");
+    		counterPuts = debugCounter.registerCounter(PACKAGE, "puts",
+    				"Local puts to store");
+    		counterGets = debugCounter.registerCounter(PACKAGE, "gets",
+    				"Local gets from store");
+    		counterIterators = debugCounter.registerCounter(PACKAGE, "iterators",
+    				"Local iterators created over store");
+    		counterErrorRemote = debugCounter.registerCounter(PACKAGE, "error-remote",
+    				"Number of errors sent from remote clients",
+    				IDebugCounterService.MetaData.ERROR);
+    		counterErrorProcessing = debugCounter.registerCounter(PACKAGE,
+    				"error-processing",
+    				"Number of errors processing messages from remote clients",
+    				IDebugCounterService.MetaData.ERROR);
+    	}
 
     }
 
@@ -780,7 +767,7 @@ public class SyncManager extends AbstractSyncManager {
                     // XXX - todo - handle hints targeted to specific nodes
                     storeRegistry.takeHints(tasks, 50);
                     for (Hint task : tasks) {
-                        counterHints.updateCounterWithFlush();
+                        counterHints.increment();
                         SynchronizingStorageEngine store =
                                 storeRegistry.get(task.getHintKey().
                                                   getStoreName());
@@ -811,10 +798,8 @@ public class SyncManager extends AbstractSyncManager {
                             }
 
                             svm.getHeader().
-                            setTransactionId(rpcService.
-                                             getTransactionId());
-                            counterSentValues.updateCounterWithFlush(bsm.getSyncValue().
-                                                           getValuesSize());
+                            setTransactionId(rpcService.getTransactionId());
+                            counterSentValues.add(bsm.getSyncValue().getValuesSize());
                             rpcService.writeToNode(n.getNodeId(), bsm);
                         }
                     }
diff --git a/src/main/java/org/sdnplatform/sync/internal/SyncTorture.java b/src/main/java/org/sdnplatform/sync/internal/SyncTorture.java
index 74e4ae96648089a28dd38758b817886a01f57f63..c6e218132a6f7d4b1cba9c5fb5c3724f77ecbc4f 100644
--- a/src/main/java/org/sdnplatform/sync/internal/SyncTorture.java
+++ b/src/main/java/org/sdnplatform/sync/internal/SyncTorture.java
@@ -184,7 +184,6 @@ public class SyncTorture implements IFloodlightModule {
                     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),
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 27addf7fe1ff448d154af8222d561604a31e86b3..416f4ebaacddf5455a40e404ceefe251526a2617 100644
--- a/src/main/java/org/sdnplatform/sync/internal/config/ClusterConfig.java
+++ b/src/main/java/org/sdnplatform/sync/internal/config/ClusterConfig.java
@@ -15,6 +15,7 @@ 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/config/FallbackCCProvider.java b/src/main/java/org/sdnplatform/sync/internal/config/FallbackCCProvider.java
index fcdfb6fafc76e25a3f29154828b2072cd8449a03..09278ae2c76ae9182858cd7f3bc7afd8e4f9ebe2 100644
--- a/src/main/java/org/sdnplatform/sync/internal/config/FallbackCCProvider.java
+++ b/src/main/java/org/sdnplatform/sync/internal/config/FallbackCCProvider.java
@@ -25,6 +25,7 @@ public class FallbackCCProvider implements IClusterConfigProvider {
     AuthScheme authScheme;
     String keyStorePath;
     String keyStorePassword;
+    int syncPort = 6642;
     
     public FallbackCCProvider() throws SyncException {
         
@@ -43,7 +44,7 @@ public class FallbackCCProvider implements IClusterConfigProvider {
         }
         return new ClusterConfig(Collections.
                                  singletonList(new Node("localhost",
-                                                        6642,
+                                                        syncPort,
                                                         Short.MAX_VALUE,
                                                         Short.MAX_VALUE)),
                                                         Short.MAX_VALUE,
@@ -61,6 +62,7 @@ public class FallbackCCProvider implements IClusterConfigProvider {
         authScheme = AuthScheme.NO_AUTH;
         try {
             authScheme = AuthScheme.valueOf(config.get("authScheme"));
+            syncPort = Integer.parseInt(config.get("port"));
         } catch (Exception e) {}
     }
 }
diff --git a/src/main/java/org/sdnplatform/sync/internal/rpc/RPCChannelHandler.java b/src/main/java/org/sdnplatform/sync/internal/rpc/RPCChannelHandler.java
index af5dafb1b147a247cd696834618cb4c4b7f349ab..516f387a291f2b655c1a6d0af2cd4f2fc7abed29 100644
--- a/src/main/java/org/sdnplatform/sync/internal/rpc/RPCChannelHandler.java
+++ b/src/main/java/org/sdnplatform/sync/internal/rpc/RPCChannelHandler.java
@@ -596,7 +596,7 @@ public class RPCChannelHandler extends AbstractRPCChannelHandler {
     // *****************
 
     protected void updateCounter(IDebugCounter counter, int incr) {
-        counter.updateCounterWithFlush(incr);
+        counter.add(incr);
     }
 
     protected void startAntientropy() {
diff --git a/src/main/java/org/sdnplatform/sync/internal/store/ListenerStorageEngine.java b/src/main/java/org/sdnplatform/sync/internal/store/ListenerStorageEngine.java
index d6e730c21484b050df395dbe6b68d4aa66c7093a..9d6f9d79e9e1612eaaf9a98620d3add0941e5b95 100644
--- a/src/main/java/org/sdnplatform/sync/internal/store/ListenerStorageEngine.java
+++ b/src/main/java/org/sdnplatform/sync/internal/store/ListenerStorageEngine.java
@@ -160,7 +160,7 @@ public class ListenerStorageEngine
 
     protected void updateCounter(IDebugCounter counter) {
         if (debugCounter != null) {
-            counter.updateCounterWithFlush();
+            counter.increment();
         }
     }
 }
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 5a9473562e4d226fb7e8f5f22e805074bcd90129..733f03af894c09f3e310ed84f7d5feada55a41b0 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.openflow.util.HexString;
+import org.projectfloodlight.openflow.util.HexString;
 
 /**
  * A byte array container that provides an equals and hashCode pair based on the
diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
index ce4fea11dd6e2355e6ede131d8ee5816e9efa29f..40d0cd1bc7e878267c1a195708b9c5ef1094809b 100644
--- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
+++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
@@ -1,28 +1,26 @@
-net.floodlightcontroller.core.module.ApplicationLoader
 net.floodlightcontroller.core.internal.FloodlightProvider
 net.floodlightcontroller.storage.memory.MemoryStorageSource
-net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl
-net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager
-net.floodlightcontroller.topology.TopologyManager
-net.floodlightcontroller.forwarding.Forwarding
 net.floodlightcontroller.flowcache.FlowReconcileManager
-net.floodlightcontroller.core.OFMessageFilterManager
-net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher
-net.floodlightcontroller.perfmon.PktInProcessingTime
-net.floodlightcontroller.perfmon.NullPktInProcessingTime
-net.floodlightcontroller.restserver.RestApiServer
-net.floodlightcontroller.learningswitch.LearningSwitch
 net.floodlightcontroller.hub.Hub
 net.floodlightcontroller.jython.JythonDebugInterface
-net.floodlightcontroller.counter.CounterStore
-net.floodlightcontroller.counter.NullCounterStore
-net.floodlightcontroller.debugcounter.DebugCounter
-net.floodlightcontroller.debugevent.DebugEvent
+net.floodlightcontroller.debugcounter.DebugCounterServiceImpl
+net.floodlightcontroller.debugevent.DebugEventService
 net.floodlightcontroller.threadpool.ThreadPool
+net.floodlightcontroller.perfmon.PktInProcessingTime
+net.floodlightcontroller.restserver.RestApiServer
 net.floodlightcontroller.ui.web.StaticWebRoutable
 net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter
-net.floodlightcontroller.firewall.Firewall
-net.floodlightcontroller.loadbalancer.LoadBalancer
+net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier
+net.floodlightcontroller.core.internal.OFSwitchManager
+net.floodlightcontroller.threadpool.ThreadPool
+net.floodlightcontroller.core.internal.ShutdownServiceImpl
 org.sdnplatform.sync.internal.SyncManager
 org.sdnplatform.sync.internal.SyncTorture
-net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier
+net.floodlightcontroller.hub.Hub
+net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher
+net.floodlightcontroller.testmodule.TestModule
+net.floodlightcontroller.topology.TopologyManager
+net.floodlightcontroller.forwarding.Forwarding
+net.floodlightcontroller.loadbalancer.LoadBalancer
+net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager
+net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl
\ No newline at end of file
diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties
index 47d2ae4c164061064f6aae682f6a5993321f51fe..3dbacb7bae8f06c048021048013811e26471de85 100644
--- a/src/main/resources/floodlightdefault.properties
+++ b/src/main/resources/floodlightdefault.properties
@@ -1,24 +1,19 @@
 floodlight.modules=\
 net.floodlightcontroller.jython.JythonDebugInterface,\
-net.floodlightcontroller.counter.CounterStore,\
 net.floodlightcontroller.storage.memory.MemoryStorageSource,\
 net.floodlightcontroller.core.internal.FloodlightProvider,\
 net.floodlightcontroller.threadpool.ThreadPool,\
-net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
-net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier,\
+net.floodlightcontroller.debugcounter.DebugCounterServiceImpl,\
+net.floodlightcontroller.restserver.RestApiServer,\
+net.floodlightcontroller.perfmon.PktInProcessingTime,\
+net.floodlightcontroller.debugevent.DebugEventService,\
 net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
-net.floodlightcontroller.firewall.Firewall,\
+net.floodlightcontroller.restserver.RestApiServer,\
+net.floodlightcontroller.topology.TopologyManager,\
 net.floodlightcontroller.forwarding.Forwarding,\
 net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager,\
-net.floodlightcontroller.topology.TopologyManager,\
-net.floodlightcontroller.flowcache.FlowReconcileManager,\
-net.floodlightcontroller.debugcounter.DebugCounter,\
-net.floodlightcontroller.debugevent.DebugEvent,\
-net.floodlightcontroller.perfmon.PktInProcessingTime,\
-net.floodlightcontroller.ui.web.StaticWebRoutable,\
-net.floodlightcontroller.loadbalancer.LoadBalancer,\
-org.sdnplatform.sync.internal.SyncManager,\
-net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier
+net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl
 org.sdnplatform.sync.internal.SyncManager.authScheme=CHALLENGE_RESPONSE
 org.sdnplatform.sync.internal.SyncManager.keyStorePath=/etc/floodlight/auth_credentials.jceks
 org.sdnplatform.sync.internal.SyncManager.dbPath=/var/lib/floodlight/
+net.floodlightcontroller.core.internal.FloodlightProvider.role=ACTIVE
diff --git a/src/main/resources/logback-test.xml b/src/main/resources/logback-test.xml
index e3f2a4fcf21aaf13d7faa25ccbc97da54459a7c5..7f61e32e22bac17b1f72ccd1562370afe70d2673 100644
--- a/src/main/resources/logback-test.xml
+++ b/src/main/resources/logback-test.xml
@@ -6,13 +6,16 @@
   </appender>
   <appender name="EV_WARN_ERR" class="net.floodlightcontroller.debugevent.DebugEventAppender">
   </appender>
-  <root level="INFO">
+  <root level="DEBUG">
     <appender-ref ref="STDOUT" />
     <appender-ref ref="EV_WARN_ERR" />
   </root>
-  <logger name="org" level="WARN"/>
-  <logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
-  <logger name="net.bigdb" level="INFO"/>
-  <logger name="net.floodlightcontroller" level="INFO"/>
-  <logger name="org.sdnplatform" level="INFO"/>
+  <logger name="org" level="DEBUG"/>
+  <logger name="LogService" level="DEBUG"/> <!-- Restlet access logging -->
+  <logger name="net.floodlightcontroller" level="DEBUG"/>
+  <logger name="org.sdnplatform" level="INFO"></logger>
+  <logger name="net.floodlightcontroller.devicemanager" level="TRACE"></logger>
+  <logger name="net.floodlightcontroller.packet" level="TRACE"></logger>
+  <logger name="net.floodlightcontroller.forwarding" level="TRACE"></logger>
+  <logger name="net.floodlightcontroller.routing" level="TRACE"></logger>
 </configuration>
diff --git a/src/test/java/com/bigswitch/floodlight/vendor/OFActionNiciraTtlDecrementTest.java b/src/test/java/com/bigswitch/floodlight/vendor/OFActionNiciraTtlDecrementTest.java
deleted file mode 100644
index a8214b6dfc47b5e8c34c52184aa09397e952ccd4..0000000000000000000000000000000000000000
--- a/src/test/java/com/bigswitch/floodlight/vendor/OFActionNiciraTtlDecrementTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.junit.Test;
-import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionType;
-import org.openflow.protocol.action.OFActionVendor;
-
-import static org.junit.Assert.*;
-
-public class OFActionNiciraTtlDecrementTest {
-    protected static byte[] expectedWireFormat = { 
-                (byte) 0xff, (byte) 0xff,          // action vendor
-                0x00, 0x10,                        // length 
-                0x00, 0x00, 0x23, 0x20,            // nicira
-                0x00, 0x12,                        // subtype 18 == 0x12
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // pad 
-    };
-    
-    @Test
-    public void testAction() {
-        ChannelBuffer buf = ChannelBuffers.buffer(32);
-        
-        OFActionNiciraTtlDecrement act = new OFActionNiciraTtlDecrement();
-        
-        assertEquals(true, act instanceof OFActionNiciraVendor);
-        assertEquals(true, act instanceof OFActionVendor);
-        assertEquals(true, act instanceof OFAction);
-        
-        act.writeTo(buf);
-        
-        ChannelBuffer buf2 = buf.copy();
-        
-        assertEquals(16, buf.readableBytes());
-        byte fromBuffer[] = new byte[16]; 
-        buf.readBytes(fromBuffer);
-        assertArrayEquals(expectedWireFormat, fromBuffer);
-        
-        // Test parsing. TODO: we don't really have the proper parsing
-        // infrastructure....
-        OFActionNiciraVendor act2 = new OFActionNiciraTtlDecrement();
-        act2.readFrom(buf2);
-        assertEquals(act, act2);
-        assertNotSame(act, act2);
-        
-        assertEquals(OFActionType.VENDOR, act2.getType());
-        assertEquals(16, act2.getLength());
-        assertEquals(OFActionNiciraVendor.NICIRA_VENDOR_ID, act2.getVendor());
-        assertEquals((short)18, act2.getSubtype());
-    }
-
-}
diff --git a/src/test/java/com/bigswitch/floodlight/vendor/OFActionTunnelDstIPTest.java b/src/test/java/com/bigswitch/floodlight/vendor/OFActionTunnelDstIPTest.java
deleted file mode 100644
index 38daa746ef6d310a1ce14f02e4e5c21f5f897b4e..0000000000000000000000000000000000000000
--- a/src/test/java/com/bigswitch/floodlight/vendor/OFActionTunnelDstIPTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import net.floodlightcontroller.packet.IPv4;
-import net.floodlightcontroller.test.FloodlightTestCase;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.junit.Test;
-import org.openflow.protocol.action.OFActionType;
-
-import static org.junit.Assert.*;
-
-public class OFActionTunnelDstIPTest extends FloodlightTestCase{
-    protected static byte[] expectedWireFormat1 = { 
-            (byte) 0xff, (byte) 0xff,       // ActionVendor
-            0x00, 0x10,                     // 16 bytes
-            0x00, 0x5c, 0x16, (byte)0xc7,   // VendorId BSN
-            0x00, 0x00, 0x00, 0x02,         // subtype 2 (32 bit)
-            0x11, 0x21, 0x31, 0x41          // IP 17.33.49.65
-    };
-
-    @Test
-    public void testAction() {
-        OFActionTunnelDstIP tunnAct1 = new OFActionTunnelDstIP();
-        assertEquals(0, tunnAct1.dstIPAddr);
-
-        OFActionTunnelDstIP tunnAct2 = new OFActionTunnelDstIP(1);
-        
-        assertEquals(false, tunnAct1.equals(tunnAct2));
-        tunnAct1.setTunnelDstIP(1);
-        assertEquals(tunnAct1, tunnAct2);
-        
-        testAll(tunnAct1);
-        testAll(tunnAct2);
-    }
-    
-    private void testAll(OFActionTunnelDstIP tip) {
-        assertEquals(OFActionType.VENDOR, tip.getType());
-        assertEquals(2, tip.getSubtype());
-        assertEquals(16, tip.getLength());
-        assertEquals(0x005c16c7, tip.getVendor());
-
-        tip.setTunnelDstIP(24);
-        assertEquals(24, tip.getTunnelDstIP());
-        
-        // Test wire format
-        int ip = IPv4.toIPv4Address("17.33.49.65");
-        tip.setTunnelDstIP(ip);
-        ChannelBuffer buf = ChannelBuffers.buffer(32);
-        tip.writeTo(buf);
-        ChannelBuffer buf2 = buf.copy();
-        assertEquals(16, buf.readableBytes());
-        byte fromBuffer[] = new byte[16]; 
-        buf.readBytes(fromBuffer);
-        assertArrayEquals(expectedWireFormat1, fromBuffer);
-        
-        OFActionTunnelDstIP act2 = new OFActionTunnelDstIP();
-        act2.readFrom(buf2);
-        assertEquals(tip, act2);
-        
-        
-    }
-    
-    
-}
diff --git a/src/test/java/com/bigswitch/floodlight/vendor/OFBsnPktinSupressionSetRequestVendorDataTest.java b/src/test/java/com/bigswitch/floodlight/vendor/OFBsnPktinSupressionSetRequestVendorDataTest.java
deleted file mode 100644
index 2be162e1ca457c6f03e41ef03c9bbd84cb708f16..0000000000000000000000000000000000000000
--- a/src/test/java/com/bigswitch/floodlight/vendor/OFBsnPktinSupressionSetRequestVendorDataTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class OFBsnPktinSupressionSetRequestVendorDataTest {
-    protected static byte[] expectedWireFormat = {
-            0x00, 0x00, 0x00, 0x0b, // type == 11
-            0x01,                   // enabled
-            0x00,                   // pad
-            0x00, 0x5a,             // idle timeout
-            (byte) 0xf0, (byte) 0xe0,  // hard timeout
-            0x12, 0x34,             // priority
-            0x33, 0x33, 0x66, 0x66,
-            0x77, 0x77, (byte) 0x99, (byte) 0x99  // cookie
-    };
-
-    @Test
-    public void test() {
-        ChannelBuffer buf = ChannelBuffers.buffer(32);
-
-        OFBsnPktinSuppressionSetRequestVendorData vendorData =
-                new OFBsnPktinSuppressionSetRequestVendorData(
-                                                     true,
-                                                     (short)0x5a,
-                                                     (short)0xf0e0,
-                                                     (short)0x1234,
-                                                     0x3333666677779999L);
-        assertEquals(11, vendorData.getDataType());
-
-        assertEquals(true, vendorData instanceof OFBigSwitchVendorData);
-
-        vendorData.writeTo(buf);
-
-        ChannelBuffer buf2 = buf.copy();
-        assertEquals(20, buf.readableBytes());
-        byte fromBuffer[] = new byte[20];
-        buf.readBytes(fromBuffer);
-        assertArrayEquals(expectedWireFormat, fromBuffer);
-
-        OFBsnPktinSuppressionSetRequestVendorData vendorData2 =
-                new OFBsnPktinSuppressionSetRequestVendorData();
-
-        assertEquals(11, vendorData2.getDataType());
-
-        vendorData2.setIdleTimeout((short)1);
-        assertEquals((short)1, vendorData2.getIdleTimeout());
-
-        vendorData2.setHardTimeout((short)2);
-        assertEquals((short)2, vendorData2.getHardTimeout());
-
-        vendorData2.setPriority((short)3);
-        assertEquals((short)3, vendorData2.getPriority());
-
-        vendorData2.setCookie(12345678901234L);
-        assertEquals(12345678901234L, vendorData2.getCookie());
-
-        vendorData2.readFrom(buf2, buf2.readableBytes());
-        assertEquals(vendorData, vendorData2);
-    }
-
-
-}
diff --git a/src/test/java/com/bigswitch/floodlight/vendor/OFVendorActionFactoriesTest.java b/src/test/java/com/bigswitch/floodlight/vendor/OFVendorActionFactoriesTest.java
deleted file mode 100644
index 4ba390bf5cd35c97312a1cfd77b0d0e4b5fd5e22..0000000000000000000000000000000000000000
--- a/src/test/java/com/bigswitch/floodlight/vendor/OFVendorActionFactoriesTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.bigswitch.floodlight.vendor;
-
-import static org.junit.Assert.assertEquals;
-
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.InvocationTargetException;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.junit.Test;
-import org.openflow.protocol.action.OFActionVendor;
-import org.openflow.protocol.factory.OFVendorActionFactory;
-
-public class OFVendorActionFactoriesTest {
-
-    @Test
-    public void testNiciraVendorActionFactory() {
-        OFNiciraVendorActionFactory factory =
-                new OFNiciraVendorActionFactory();
-
-        OFActionNiciraTtlDecrement ttl = new OFActionNiciraTtlDecrement();
-        rereadAndCheck(factory, ttl);
-    }
-
-    @Test
-    public void testBSNVendorActionFactory() {
-        OFBigSwitchVendorActionFactory factory =
-                new OFBigSwitchVendorActionFactory();
-
-        OFActionMirror mirror = new OFActionMirror((short) 12);
-        mirror.setCopyStage((byte) 96);
-        mirror.setDestPort(123);
-        mirror.setVlanTag(42);
-        rereadAndCheck(factory, mirror);
-
-        OFActionTunnelDstIP dstIP = new OFActionTunnelDstIP((short) 12);
-        dstIP.setTunnelDstIP(0x01020304);
-        rereadAndCheck(factory, dstIP);
-
-    }
-
-
-    protected void rereadAndCheck(OFVendorActionFactory factory, OFActionVendor action) {
-        ChannelBuffer buf= ChannelBuffers.buffer(action.getLengthU());
-        action.writeTo(buf);
-        OFActionVendor readAction = factory.readFrom(buf);
-        assertBeansEqual(action, readAction);
-    }
-
-    public void assertBeansEqual(Object expected, Object actual) {
-        BeanInfo beanInfo;
-        try {
-            beanInfo = Introspector.getBeanInfo(expected.getClass());
-            for (PropertyDescriptor propertyDesc : beanInfo.getPropertyDescriptors()) {
-                Object srcValue = propertyDesc.getReadMethod().invoke(expected);
-                Object dstValue = propertyDesc.getReadMethod().invoke(actual);
-                assertEquals("Bean Value: "+propertyDesc.getName() + " expected: "+srcValue + " != actual: "+dstValue, srcValue, dstValue);
-            }
-        } catch (IntrospectionException e) {
-            throw new RuntimeException(e);
-        } catch (IllegalArgumentException e) {
-            throw new RuntimeException(e);
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException(e);
-        } catch (InvocationTargetException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}
diff --git a/src/test/java/net/floodlightcontroller/core/OFConnectionTest.java b/src/test/java/net/floodlightcontroller/core/OFConnectionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..af62aa9cdf228c1f121ca979ecafc939940aacfb
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/OFConnectionTest.java
@@ -0,0 +1,271 @@
+package net.floodlightcontroller.core;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Matchers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timer;
+import org.junit.Before;
+import org.junit.Test;
+import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFEchoReply;
+import org.projectfloodlight.openflow.protocol.OFEchoRequest;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFHello;
+import org.projectfloodlight.openflow.protocol.OFHelloElem;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketOut;
+import org.projectfloodlight.openflow.protocol.OFRoleReply;
+import org.projectfloodlight.openflow.protocol.OFRoleRequest;
+import org.projectfloodlight.openflow.protocol.OFRoleRequestFailedCode;
+import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.errormsg.OFRoleRequestFailedErrorMsg;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFAuxId;
+import org.projectfloodlight.openflow.types.OFPort;
+import net.floodlightcontroller.util.FutureTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class OFConnectionTest {
+    private static final Logger logger = LoggerFactory.getLogger(OFConnectionTest.class);
+
+    private OFFactory factory;
+    private Channel channel;
+    private OFConnection conn;
+    private DatapathId switchId;
+    private Timer timer;
+
+    @Before
+    public void setUp() throws Exception {
+        factory = OFFactories.getFactory(OFVersion.OF_13);
+        switchId = DatapathId.of(1);
+        timer = new HashedWheelTimer();
+        channel = EasyMock.createMock(Channel.class);
+        IDebugCounterService debugCounterService = new DebugCounterServiceImpl();
+        debugCounterService.registerModule(OFConnectionCounters.COUNTER_MODULE);
+        conn = new OFConnection(switchId, factory, channel, OFAuxId.MAIN,
+                                debugCounterService, timer);
+    }
+
+    @Test(timeout = 5000)
+    public void testWriteRequestSuccess() throws InterruptedException, ExecutionException {
+        Capture<List<OFMessage>> cMsgList = prepareChannelForWriteList();
+
+        OFEchoRequest echoRequest = factory.echoRequest(new byte[] {});
+        ListenableFuture<OFEchoReply> future = conn.writeRequest(echoRequest);
+        assertThat("Connection should have 1 pending request",
+                conn.getPendingRequestIds().size(), equalTo(1));
+
+        assertThat("Should have captured MsgList", cMsgList.getValue(),
+                Matchers.<OFMessage> contains(echoRequest));
+
+        assertThat("Future should not be complete yet", future.isDone(), equalTo(false));
+
+        OFEchoReply echoReply = factory.buildEchoReply()
+                .setXid(echoRequest.getXid())
+                .build();
+
+        assertThat("Connection should have accepted the response",
+                conn.deliverResponse(echoReply),
+                equalTo(true));
+        assertThat("Future should be complete ", future.isDone(), equalTo(true));
+        assertThat(future.get(), equalTo(echoReply));
+        assertThat("Connection should have no pending requests",
+                conn.getPendingRequestIds().isEmpty(), equalTo(true));
+    }
+
+    /** write a stats request message that triggers two responses */
+    @Test(timeout = 5000)
+    public void testWriteStatsRequestSuccess() throws InterruptedException, ExecutionException {
+        Capture<List<OFMessage>> cMsgList = prepareChannelForWriteList();
+
+        OFFlowStatsRequest flowStatsRequest = factory.buildFlowStatsRequest().build();
+        ListenableFuture<List<OFFlowStatsReply>> future = conn.writeStatsRequest(flowStatsRequest);
+        assertThat("Connection should have 1 pending request",
+                conn.getPendingRequestIds().size(), equalTo(1));
+
+        assertThat("Should have captured MsgList", cMsgList.getValue(),
+                Matchers.<OFMessage> contains(flowStatsRequest));
+
+        assertThat("Future should not be complete yet", future.isDone(), equalTo(false));
+
+        OFFlowStatsReply statsReply1 = factory.buildFlowStatsReply()
+                .setXid(flowStatsRequest.getXid())
+                .setFlags(Sets.immutableEnumSet(OFStatsReplyFlags.REPLY_MORE))
+                .build();
+
+        assertThat("Connection should have accepted the response",
+                conn.deliverResponse(statsReply1),
+                equalTo(true));
+        assertThat("Future should not be complete ", future.isDone(), equalTo(false));
+
+        OFFlowStatsReply statsReply2 = factory.buildFlowStatsReply()
+                .setXid(flowStatsRequest.getXid())
+                .build();
+
+        assertThat("Connection should have accepted the response",
+                conn.deliverResponse(statsReply2),
+                equalTo(true));
+        assertThat("Future should be complete ", future.isDone(), equalTo(true));
+
+        assertThat(future.get(), Matchers.contains(statsReply1, statsReply2));
+        assertThat("Connection should have no pending requests",
+                conn.getPendingRequestIds().isEmpty(), equalTo(true));
+    }
+
+    private Capture<List<OFMessage>> prepareChannelForWriteList() {
+        EasyMock.expect(channel.isConnected()).andReturn(Boolean.TRUE).anyTimes();
+        Capture<List<OFMessage>> cMsgList = new Capture<>();
+        expect(channel.write(capture(cMsgList))).andReturn(null).once();
+        replay(channel);
+        return cMsgList;
+    }
+
+    /** write a request which triggers an OFErrorMsg response */
+    @Test(timeout = 5000)
+    public void testWriteRequestOFErrorMsg() throws InterruptedException, ExecutionException {
+        Capture<List<OFMessage>> cMsgList = prepareChannelForWriteList();
+
+        OFRoleRequest roleRequest = factory.buildRoleRequest().setRole(OFControllerRole.ROLE_MASTER).build();
+        ListenableFuture<OFRoleReply> future = conn.writeRequest(roleRequest);
+        assertThat("Connection should have 1 pending request",
+                conn.getPendingRequestIds().size(), equalTo(1));
+
+        assertThat("Should have captured MsgList", cMsgList.getValue(),
+                Matchers.<OFMessage> contains(roleRequest));
+
+        assertThat("Future should not be complete yet", future.isDone(), equalTo(false));
+        OFRoleRequestFailedErrorMsg roleError = factory.errorMsgs().buildRoleRequestFailedErrorMsg()
+            .setXid(roleRequest.getXid())
+            .setCode(OFRoleRequestFailedCode.STALE)
+            .build();
+
+        assertThat("Connection should have accepted the response",
+                conn.deliverResponse(roleError),
+                equalTo(true));
+
+        OFErrorMsgException e =
+                FutureTestUtils.assertFutureFailedWithException(future,
+                        OFErrorMsgException.class);
+        assertThat(e.getErrorMessage(), CoreMatchers.<OFErrorMsg>equalTo(roleError));
+    }
+
+    @Test(timeout = 5000)
+    public void testWriteRequestNotConnectedFailure() throws InterruptedException,
+            ExecutionException {
+        EasyMock.expect(channel.isConnected()).andReturn(Boolean.FALSE).anyTimes();
+        replay(channel);
+
+        OFEchoRequest echoRequest = factory.echoRequest(new byte[] {});
+        ListenableFuture<OFEchoReply> future = conn.writeRequest(echoRequest);
+
+        SwitchDisconnectedException e =
+                FutureTestUtils.assertFutureFailedWithException(future,
+                        SwitchDisconnectedException.class);
+        assertThat(e.getId(), equalTo(switchId));
+        assertThat("Connection should have no pending requests",
+                conn.getPendingRequestIds().isEmpty(), equalTo(true));
+    }
+
+    @Test(timeout = 5000)
+    public void testWriteRequestDisconnectFailure() throws InterruptedException, ExecutionException {
+        prepareChannelForWriteList();
+
+        OFEchoRequest echoRequest = factory.echoRequest(new byte[] {});
+        ListenableFuture<OFEchoReply> future = conn.writeRequest(echoRequest);
+
+        assertThat("Connection should have 1 pending request", conn.getPendingRequestIds().size(),
+                equalTo(1));
+        assertThat("Future should not be complete yet", future.isDone(), equalTo(false));
+
+        conn.disconnected();
+
+        SwitchDisconnectedException e =
+                FutureTestUtils.assertFutureFailedWithException(future,
+                        SwitchDisconnectedException.class);
+        assertThat(e.getId(), equalTo(switchId));
+        assertThat("Connection should have no pending requests",
+                conn.getPendingRequestIds().isEmpty(), equalTo(true));
+    }
+
+    /** write a packetOut, which is buffered */
+    @Test(timeout = 5000)
+    public void testMessageWriteBuffered() throws InterruptedException, ExecutionException {
+        Capture<List<OFMessage>> cMsgList = prepareChannelForWriteList();
+
+        OFPacketOut packetOut = factory.buildPacketOut()
+                .setData(new byte[] { 0x01, 0x02, 0x03, 0x04 })
+                .setActions(ImmutableList.<OFAction>of( factory.actions().output(OFPort.of(1), 0)))
+                .build();
+        conn.write(packetOut);
+        assertThat("Write should have been buffered", cMsgList.hasCaptured(), equalTo(false));
+
+        conn.flush();
+
+        assertThat("Write should have been flushed", cMsgList.hasCaptured(), equalTo(true));
+        List<OFMessage> value = cMsgList.getValue();
+        logger.info("Captured channel write: "+value);
+        assertThat("Should have captured MsgList", cMsgList.getValue(),
+                Matchers.<OFMessage> contains(packetOut));
+    }
+
+    /** write a hello, which is not buffered */
+    @Test(timeout = 5000)
+    public void testMessageWriteNonBuffered() throws InterruptedException, ExecutionException {
+        Capture<List<OFMessage>> cMsgList = prepareChannelForWriteList();
+
+        OFHello hello = factory.hello(ImmutableList.<OFHelloElem>of());
+        conn.write(hello);
+
+        assertThat("Write should have been written immediately", cMsgList.hasCaptured(), equalTo(true));
+        List<OFMessage> value = cMsgList.getValue();
+        logger.info("Captured channel write: "+value);
+        assertThat("Should have captured MsgList", cMsgList.getValue(),
+                Matchers.<OFMessage> contains(hello));
+    }
+
+    /** write a list of messages */
+    @Test(timeout = 5000)
+    public void testMessageWriteList() throws InterruptedException, ExecutionException {
+        Capture<List<OFMessage>> cMsgList = prepareChannelForWriteList();
+
+        OFHello hello = factory.hello(ImmutableList.<OFHelloElem>of());
+        OFPacketOut packetOut = factory.buildPacketOut()
+                .setData(new byte[] { 0x01, 0x02, 0x03, 0x04 })
+                .setActions(ImmutableList.<OFAction>of( factory.actions().output(OFPort.of(1), 0)))
+                .build();
+
+        conn.write(ImmutableList.of(hello, packetOut));
+
+        assertThat("Write should have been written", cMsgList.hasCaptured(), equalTo(true));
+        List<OFMessage> value = cMsgList.getValue();
+        logger.info("Captured channel write: "+value);
+        assertThat("Should have captured MsgList", cMsgList.getValue(),
+                Matchers.<OFMessage> contains(hello, packetOut));
+    }
+
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java b/src/test/java/net/floodlightcontroller/core/OFSwitchBaseTest.java
similarity index 65%
rename from src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java
rename to src/test/java/net/floodlightcontroller/core/OFSwitchBaseTest.java
index 2899d44400ad49663c009ede80e5141cebff077e..81e065c2bdf2a25763138dd15e0ed697017a7e3a 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchBaseTest.java
+++ b/src/test/java/net/floodlightcontroller/core/OFSwitchBaseTest.java
@@ -14,97 +14,71 @@
  *    under the License.
  **/
 
-package net.floodlightcontroller.core.internal;
-
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.*;
+package net.floodlightcontroller.core;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
-import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
-import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
-import net.floodlightcontroller.core.IOFSwitch.PortChangeEvent;
-import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
-import net.floodlightcontroller.core.ImmutablePort;
-import net.floodlightcontroller.core.OFSwitchBase;
-import net.floodlightcontroller.debugcounter.DebugCounter;
-import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import net.floodlightcontroller.packet.ARP;
-import net.floodlightcontroller.packet.Ethernet;
-import net.floodlightcontroller.packet.IPacket;
-import net.floodlightcontroller.packet.IPv4;
-
+import org.easymock.Capture;
+import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
-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.OFType;
-import org.openflow.protocol.OFPacketIn.OFPacketInReason;
-import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
-import org.openflow.protocol.OFPhysicalPort.OFPortFeatures;
-import org.openflow.protocol.OFPortStatus.OFPortReason;
-import org.openflow.protocol.factory.BasicFactory;
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
-import org.openflow.util.HexString;
 
-public class OFSwitchBaseTest {
-    private static final String srcMac = "00:44:33:22:11:00";
-    IFloodlightProviderService floodlightProvider;
-    Map<Long, IOFSwitch> switches;
-    private OFMessage blockMessage;
-    private OFPacketIn pi;
-    private IPacket testPacket;
-    private byte[] testPacketSerialized;
-
-    private class OFSwitchTest extends OFSwitchBase {
-        public OFSwitchTest(IFloodlightProviderService fp) {
-            super();
-            stringId = "whatever";
-            datapathId = 1L;
-            floodlightProvider = fp;
-        }
+import net.floodlightcontroller.core.internal.IOFSwitchManager;
+import net.floodlightcontroller.core.internal.SwitchManagerCounters;
+import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
 
-        @Override
-        public void setSwitchProperties(OFDescriptionStatistics description) {
-            // TODO Auto-generated method stub
-        }
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortConfig;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortFeatures;
+import org.projectfloodlight.openflow.protocol.OFPortReason;
+import org.projectfloodlight.openflow.protocol.OFPortState;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFAuxId;
+import org.projectfloodlight.openflow.types.OFPort;
 
-        @Override
-        public OFPortType getPortType(short port_num) {
-            // TODO Auto-generated method stub
-            return null;
+public class OFSwitchBaseTest {
+    IOFSwitchManager switchManager;
+    Map<DatapathId, IOFSwitchBackend> switches;
+    //OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
+    private OFMessage testMessage;
+
+    private static class OFSwitchTest extends OFSwitch {
+        public OFSwitchTest(IOFConnectionBackend connection, IOFSwitchManager switchManager) {
+            super(connection, OFFactories.getFactory(OFVersion.OF_13), switchManager, DatapathId.of(1));
         }
 
         @Override
-        public boolean isFastPort(short port_num) {
-            // TODO Auto-generated method stub
-            return false;
+        public void setSwitchProperties(SwitchDescription description) {
         }
 
         @Override
-        public void write(OFMessage msg, FloodlightContext cntx) {
-            blockMessage = msg;
-        }
-
-        public void setThresholds(int high, int low, int host, int port) {
-            sw.setInputThrottleThresholds(high, low, host, port);
-        }
-
-        public boolean inputThrottleEnabled() {
-            return packetInThrottleEnabled;
+        public OFFactory getOFFactory() {
+            return OFFactories.getFactory(OFVersion.OF_13);
         }
 
         @Override
@@ -113,15 +87,15 @@ public class OFSwitchBaseTest {
         }
     }
     private OFSwitchTest sw;
-    private ImmutablePort p1a;
-    private ImmutablePort p1b;
-    private ImmutablePort p2a;
-    private ImmutablePort p2b;
-    private ImmutablePort p3;
-    private final ImmutablePort portFoo1 = ImmutablePort.create("foo", (short)11);
-    private final ImmutablePort portFoo2 = ImmutablePort.create("foo", (short)12);
-    private final ImmutablePort portBar1 = ImmutablePort.create("bar", (short)11);
-    private final ImmutablePort portBar2 = ImmutablePort.create("bar", (short)12);
+    private OFPortDesc p1a;
+    private OFPortDesc p1b;
+    private OFPortDesc p2a;
+    private OFPortDesc p2b;
+    private OFPortDesc p3;
+    private final OFPortDesc portFoo1 = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc().setPortNo(OFPort.of(11)).setName("foo").build();
+    private final OFPortDesc portFoo2 = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc().setPortNo(OFPort.of(12)).setName("foo").build();
+    private final OFPortDesc portBar1 = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc().setPortNo(OFPort.of(11)).setName("bar").build();
+    private final OFPortDesc portBar2 = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc().setPortNo(OFPort.of(12)).setName("bar").build();
     private final PortChangeEvent portFoo1Add =
             new PortChangeEvent(portFoo1, PortChangeType.ADD);
     private final PortChangeEvent portFoo2Add =
@@ -138,247 +112,105 @@ public class OFSwitchBaseTest {
             new PortChangeEvent(portBar1, PortChangeType.DELETE);
     private final PortChangeEvent portBar2Del =
             new PortChangeEvent(portBar2, PortChangeType.DELETE);
+    private Capture<OFMessage> capturedMessage;
+    private OFFactory factory;
 
     @Before
     public void setUp() throws Exception {
-        blockMessage = null;
+
         // Build our test packet
-        testPacket = new Ethernet()
-        .setSourceMACAddress(srcMac)
-        .setDestinationMACAddress("00:11:22:33:44:55")
-        .setEtherType(Ethernet.TYPE_ARP)
-        .setPayload(
-                new ARP()
-                .setHardwareType(ARP.HW_TYPE_ETHERNET)
-                .setProtocolType(ARP.PROTO_TYPE_IP)
-                .setHardwareAddressLength((byte) 6)
-                .setProtocolAddressLength((byte) 4)
-                .setOpCode(ARP.OP_REPLY)
-                .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00"))
-                .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
-                .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
-                .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
-        testPacketSerialized = testPacket.serialize();
-
-        pi = ((OFPacketIn) BasicFactory.getInstance().getMessage(OFType.PACKET_IN))
-                .setBufferId(-1)
-                .setInPort((short) 1)
-                .setPacketData(testPacketSerialized)
-                .setReason(OFPacketInReason.NO_MATCH)
-                .setTotalLength((short) testPacketSerialized.length);
-        floodlightProvider = createMock(IFloodlightProviderService.class);
-        sw = new OFSwitchTest(floodlightProvider);
-        IDebugCounterService debugCounter = new DebugCounter();
-        sw.setDebugCounterService(debugCounter);
-        switches = new ConcurrentHashMap<Long, IOFSwitch>();
+        IDebugCounterService debugCounter = new DebugCounterServiceImpl();
+        switchManager = createMock(IOFSwitchManager.class);
+        SwitchManagerCounters counters = new SwitchManagerCounters(debugCounter);
+
+        expect(switchManager.getCounters()).andReturn(counters).anyTimes();
+        replay(switchManager);
+
+        factory = OFFactories.getFactory(OFVersion.OF_13);
+
+        testMessage = factory.buildRoleReply()
+                .setXid(1)
+                .setRole(OFControllerRole.ROLE_MASTER)
+                .build();
+
+        IOFConnectionBackend conn = EasyMock.createNiceMock(IOFConnectionBackend.class);
+        capturedMessage = new Capture<OFMessage>();
+        conn.write(EasyMock.capture(capturedMessage));
+        expectLastCall().anyTimes();
+        expect(conn.getOFFactory()).andReturn(factory).anyTimes();
+        expect(conn.getAuxId()).andReturn(OFAuxId.MAIN).anyTimes();
+        EasyMock.replay(conn);
+
+        IOFConnectionBackend auxConn = EasyMock.createNiceMock(IOFConnectionBackend.class);
+        expect(auxConn.getOFFactory()).andReturn(factory).anyTimes();
+        expect(auxConn.getAuxId()).andReturn(OFAuxId.of(1)).anyTimes();
+        EasyMock.replay(auxConn);
+
+        sw = new OFSwitchTest(conn, switchManager);
+        sw.registerConnection(auxConn);
+
+        switches = new ConcurrentHashMap<DatapathId, IOFSwitchBackend>();
         switches.put(sw.getId(), sw);
-        expect(floodlightProvider.getSwitch(sw.getId())).andReturn(sw).anyTimes();
-        expect(floodlightProvider.getOFMessageFactory())
-                .andReturn(BasicFactory.getInstance()).anyTimes();
+        reset(switchManager);
+        //expect(switchManager.getSwitch(sw.getId())).andReturn(sw).anyTimes();
     }
 
     @Before
     public void setUpPorts() {
-        ImmutablePort.Builder bld = new ImmutablePort.Builder();
+        OFPortDesc.Builder pdb = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc();
         // p1a is disabled
-        p1a = bld.setName("port1")
-                 .setPortNumber((short)1)
-                 .setPortStateLinkDown(true)
-                 .build();
-        assertFalse("Sanity check portEnabled", p1a.isEnabled());
+        pdb.setName("port1");
+        pdb.setPortNo(OFPort.of(1));
+        Set<OFPortState> portState = new HashSet<OFPortState>();
+        portState.add(OFPortState.LINK_DOWN);
+        pdb.setState(portState);
+        p1a = pdb.build();
+        assertFalse("Sanity check portEnabled", !p1a.getState().contains(OFPortState.LINK_DOWN));
 
         // p1b is enabled
         // p1b has different feature from p1a
-        p1b = bld.addCurrentFeature(OFPortFeatures.OFPPF_1GB_FD)
-                 .setPortStateLinkDown(false)
-                 .build();
-        assertTrue("Sanity check portEnabled", p1b.isEnabled());
+        pdb = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc();
+        pdb.setName("port1");
+        pdb.setPortNo(OFPort.of(1));
+        Set<OFPortFeatures> portFeatures = new HashSet<OFPortFeatures>();
+        portFeatures.add(OFPortFeatures.PF_1GB_FD);
+        pdb.setCurr(portFeatures);
+        p1b = pdb.build();
+        assertTrue("Sanity check portEnabled", !p1b.getState().contains(OFPortState.LIVE));
 
         // p2 is disabled
         // p2 has mixed case
-        bld = new ImmutablePort.Builder();
-        p2a = bld.setName("Port2")
-                .setPortNumber((short)2)
-                .setPortStateLinkDown(false)
-                .addConfig(OFPortConfig.OFPPC_PORT_DOWN)
-                .build();
+        pdb = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc();
+        portState = new HashSet<OFPortState>();
+        Set<OFPortConfig> portConfig = new HashSet<OFPortConfig>();
+        portFeatures = new HashSet<OFPortFeatures>();
+        pdb.setName("Port2");
+        pdb.setPortNo(OFPort.of(2));
+        portConfig.add(OFPortConfig.PORT_DOWN);
+        pdb.setConfig(portConfig);
+        p2a = pdb.build();
         // p2b only differs in PortFeatures
-        p2b = bld.addCurrentFeature(OFPortFeatures.OFPPF_100MB_HD)
-                 .build();
-        assertFalse("Sanity check portEnabled", p2a.isEnabled());
+        pdb = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc();
+        portState = new HashSet<OFPortState>();
+        portConfig = new HashSet<OFPortConfig>();
+        portFeatures = new HashSet<OFPortFeatures>();
+        pdb.setName("Port2");
+        pdb.setPortNo(OFPort.of(2));
+        portConfig.add(OFPortConfig.PORT_DOWN);
+        pdb.setConfig(portConfig);
+        portFeatures.add(OFPortFeatures.PF_100MB_HD);
+        pdb.setCurr(portFeatures);
+        p2b = pdb.build();
+        //TODO @Ryan does setting the config as PORT_DOWN undo a prior setting of state = LIVE? Answer: NO
+        assertFalse("Sanity check portEnabled", p2a.getState().contains(OFPortState.LIVE));
         // p3 is enabled
         // p3 has mixed case
-        bld = new ImmutablePort.Builder();
-        p3 = bld.setName("porT3")
-                .setPortNumber((short)3)
-                .setPortStateLinkDown(false)
-                .build();
-        assertTrue("Sanity check portEnabled", p3.isEnabled());
-
-    }
+        pdb = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc();
+        pdb.setName("porT3");
+        pdb.setPortNo(OFPort.of(3));
+        p3 = pdb.build();
+        assertTrue("Sanity check portEnabled", !p3.getState().contains(OFPortState.LINK_DOWN));
 
-    /**
-     * By default, high threshold is infinite
-     */
-    @Test
-    public void testNoPacketInThrottle() {
-        replay(floodlightProvider);
-        /* disable input throttle */
-        sw.setThresholds(Integer.MAX_VALUE, 1, 0, 0);
-        for (int i = 0; i < 200; i++) {
-            assertFalse(sw.inputThrottled(pi));
-        }
-        assertTrue(blockMessage == null);
-        assertFalse(sw.inputThrottleEnabled());
-    }
-
-    /**
-     * The test sends packet in at infinite rate (< 1ms),
-     * so throttling should be enabled on 100th packet, when the first
-     * rate measurement is done.
-     */
-    @Test
-    public void testPacketInStartThrottle() {
-        floodlightProvider.addSwitchEvent(anyLong(),
-                (String)anyObject(), anyBoolean());
-        replay(floodlightProvider);
-
-        int high = 500;
-        sw.setThresholds(high, 10, 50, 200);
-        // We measure time lapse every 1000 packets
-        for (int i = 0; i < 1000; i++) {
-            assertFalse(sw.inputThrottleEnabled());
-            assertFalse(sw.inputThrottled(pi));
-        }
-        assertTrue(sw.inputThrottleEnabled());
-        assertTrue(sw.inputThrottled(pi));
-        assertTrue(sw.inputThrottled(pi));
-        assertTrue(blockMessage == null);
-    }
-
-    /**
-     * With throttling enabled, raise the low water mark threshold,
-     * verify throttling stops.
-     * @throws InterruptedException
-     */
-    @Test
-    public void testPacketInStopThrottle() throws InterruptedException {
-        floodlightProvider.addSwitchEvent(anyLong(),
-                (String)anyObject(), anyBoolean());
-        expectLastCall().times(2);
-        replay(floodlightProvider);
-
-        sw.setThresholds(100, 10, 50, 200);
-        // First, enable throttling
-        for (int i = 0; i < 1000; i++) {
-            assertFalse(sw.inputThrottleEnabled());
-            assertFalse(sw.inputThrottled(pi));
-        }
-        assertTrue(sw.inputThrottleEnabled());
-
-        sw.setThresholds(Integer.MAX_VALUE, 100000, 50, 200);
-        for (int i = 0; i < 999; i++) {
-            assertTrue(sw.inputThrottled(pi));
-            assertTrue(sw.inputThrottleEnabled());
-        }
-        // Sleep for 2 msec, next packet should disable throttling
-        Thread.sleep(2);
-        assertFalse(sw.inputThrottled(pi));
-        assertFalse(sw.inputThrottleEnabled());
-   }
-
-    /**
-     * With throttling enabled, if rate of unique flows from a host
-     * exceeds set threshold, a flow mod should be emitted to block host
-     */
-    @Test
-    public void testPacketInBlockHost() {
-        floodlightProvider.addSwitchEvent(anyLong(),
-                (String)anyObject(), anyBoolean());
-        expectLastCall().times(2);
-        replay(floodlightProvider);
-
-        int high = 500;
-        int perMac = 50;
-        sw.setThresholds(high, 10, perMac, 200);
-        // First, enable throttling
-        for (int i = 0; i < 1000; i++) {
-            assertFalse(sw.inputThrottleEnabled());
-            assertFalse(sw.inputThrottled(pi));
-        }
-        assertTrue(sw.inputThrottleEnabled());
-        assertTrue(blockMessage == null);
-
-        // Build unique flows with the same source mac
-        for (int j = 0; j < perMac - 1; j++) {
-            testPacketSerialized[5]++;
-            pi.setPacketData(testPacketSerialized);
-            assertFalse(sw.inputThrottled(pi));
-        }
-        assertTrue(blockMessage == null);
-        testPacketSerialized[5]++;
-        pi.setPacketData(testPacketSerialized);
-        assertFalse(sw.inputThrottled(pi));
-
-        // Verify the message is a flowmod with a hard timeout and srcMac
-        assertTrue(blockMessage != null);
-        assertTrue(blockMessage instanceof OFFlowMod);
-        OFFlowMod fm = (OFFlowMod) blockMessage;
-        assertTrue(fm.getHardTimeout() == 5);
-        OFMatch match = fm.getMatch();
-        assertTrue((match.getWildcards() & OFMatch.OFPFW_DL_SRC) == 0);
-        assertTrue(Arrays.equals(match.getDataLayerSource(),
-                HexString.fromHexString(srcMac)));
-
-        // Verify non-unique OFMatches are throttled
-        assertTrue(sw.inputThrottled(pi));
-    }
-
-    /**
-     * With throttling enabled, if rate of unique flows from a port
-     * exceeds set threshold, a flow mod should be emitted to block port
-     */
-    @Test
-    public void testPacketInBlockPort() {
-        floodlightProvider.addSwitchEvent(anyLong(),
-                (String)anyObject(), anyBoolean());
-        expectLastCall().times(2);
-        replay(floodlightProvider);
-
-        int high = 500;
-        int perPort = 200;
-        sw.setThresholds(high, 10, 50, perPort);
-        // First, enable throttling
-        for (int i = 0; i < 1000; i++) {
-            assertFalse(sw.inputThrottleEnabled());
-            assertFalse(sw.inputThrottled(pi));
-        }
-        assertTrue(sw.inputThrottleEnabled());
-        assertTrue(blockMessage == null);
-
-        // Build unique flows with different source mac
-        for (int j = 0; j < perPort - 1; j++) {
-            testPacketSerialized[11]++;
-            pi.setPacketData(testPacketSerialized);
-            assertFalse(sw.inputThrottled(pi));
-        }
-        assertTrue(blockMessage == null);
-        testPacketSerialized[11]++;
-        pi.setPacketData(testPacketSerialized);
-        assertFalse(sw.inputThrottled(pi));
-
-        // Verify the message is a flowmod with a hard timeout and per port
-        assertTrue(blockMessage != null);
-        assertTrue(blockMessage instanceof OFFlowMod);
-        OFFlowMod fm = (OFFlowMod) blockMessage;
-        assertTrue(fm.getHardTimeout() == 5);
-        OFMatch match = fm.getMatch();
-        assertTrue((match.getWildcards() & OFMatch.OFPFW_DL_SRC) != 0);
-        assertTrue((match.getWildcards() & OFMatch.OFPFW_IN_PORT) == 0);
-        assertTrue(match.getInputPort() == 1);
-
-        // Verify non-unique OFMatches are throttled
-        assertTrue(sw.inputThrottled(pi));
     }
 
     /**
@@ -390,7 +222,7 @@ public class OFSwitchBaseTest {
     private static <T> void assertCollectionEqualsNoOrder(Collection<T> expected,
                                          Collection<T> actual) {
         String msg = String.format("expected=%s, actual=%s",
-                                   expected, actual);
+                                   expected.toString(), actual.toString());
         assertEquals(msg, expected.size(), actual.size());
         for(T e: expected) {
             if (!actual.contains(e)) {
@@ -409,14 +241,14 @@ public class OFSwitchBaseTest {
      */
     @Test
     public void testBasicSetPortOperations() {
-        Collection<ImmutablePort> oldPorts = Collections.emptyList();
-        Collection<ImmutablePort> oldEnabledPorts = Collections.emptyList();
-        Collection<Short> oldEnabledPortNumbers = Collections.emptyList();
-        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();
+        Collection<OFPortDesc> oldPorts = Collections.emptyList();
+        Collection<OFPortDesc> oldEnabledPorts = Collections.emptyList();
+        Collection<OFPort> oldEnabledPortNumbers = Collections.emptyList();
+        List<OFPortDesc> ports = new ArrayList<OFPortDesc>();
 
 
         Collection<PortChangeEvent> expectedChanges =
-                new ArrayList<IOFSwitch.PortChangeEvent>();
+                new ArrayList<PortChangeEvent>();
 
         Collection<PortChangeEvent> actualChanges = sw.comparePorts(ports);
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
@@ -460,15 +292,15 @@ public class OFSwitchBaseTest {
                    sw.getEnabledPortNumbers().isEmpty());
         assertTrue("enabled ports should be empty",
                    sw.getEnabledPorts().isEmpty());
-        assertEquals(p1a, sw.getPort((short)1));
+        assertEquals(p1a, sw.getPort(OFPort.of(1)));
         assertEquals(p1a, sw.getPort("port1"));
         assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2a, sw.getPort((short)2));
+        assertEquals(p2a, sw.getPort(OFPort.of(2)));
         assertEquals(p2a, sw.getPort("port2"));
         assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)3));
+        assertEquals(null, sw.getPort(OFPort.of(3)));
         assertEquals(null, sw.getPort("port3"));
         assertEquals(null, sw.getPort("PoRt3")); // case insensitive get
 
@@ -498,15 +330,15 @@ public class OFSwitchBaseTest {
                    sw.getEnabledPortNumbers().isEmpty());
         assertTrue("enabled ports should be empty",
                    sw.getEnabledPorts().isEmpty());
-        assertEquals(p1a, sw.getPort((short)1));
+        assertEquals(p1a, sw.getPort(OFPort.of(1)));
         assertEquals(p1a, sw.getPort("port1"));
         assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2a, sw.getPort((short)2));
+        assertEquals(p2a, sw.getPort(OFPort.of(2)));
         assertEquals(p2a, sw.getPort("port2"));
         assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)3));
+        assertEquals(null, sw.getPort(OFPort.of(3)));
         assertEquals(null, sw.getPort("port3"));
         assertEquals(null, sw.getPort("PoRt3")); // case insensitive get
 
@@ -533,22 +365,22 @@ public class OFSwitchBaseTest {
         assertEquals(1, actualChanges.size());
         assertTrue("No UP event for port1", actualChanges.contains(evP1bUp));
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
-        List<ImmutablePort> enabledPorts = new ArrayList<ImmutablePort>();
+        List<OFPortDesc> enabledPorts = new ArrayList<OFPortDesc>();
         enabledPorts.add(p1b);
-        List<Short> enabledPortNumbers = new ArrayList<Short>();
-        enabledPortNumbers.add((short)1);
+        List<OFPort> enabledPortNumbers = new ArrayList<OFPort>();
+        enabledPortNumbers.add(OFPort.of(1));
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1b, sw.getPort((short)1));
+        assertEquals(p1b, sw.getPort(OFPort.of(1)));
         assertEquals(p1b, sw.getPort("port1"));
         assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2a, sw.getPort((short)2));
+        assertEquals(p2a, sw.getPort(OFPort.of(2)));
         assertEquals(p2a, sw.getPort("port2"));
         assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)3));
+        assertEquals(null, sw.getPort(OFPort.of(3)));
         assertEquals(null, sw.getPort("port3"));
         assertEquals(null, sw.getPort("PoRt3")); // case insensitive get
 
@@ -579,22 +411,22 @@ public class OFSwitchBaseTest {
         assertTrue("No OTHER_CHANGE event for port2",
                    actualChanges.contains(evP2bModified));
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
-        enabledPorts = new ArrayList<ImmutablePort>();
+        enabledPorts = new ArrayList<OFPortDesc>();
         enabledPorts.add(p1b);
-        enabledPortNumbers = new ArrayList<Short>();
-        enabledPortNumbers.add((short)1);
+        enabledPortNumbers = new ArrayList<OFPort>();
+        enabledPortNumbers.add(OFPort.of(1));
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1b, sw.getPort((short)1));
+        assertEquals(p1b, sw.getPort(OFPort.of(1)));
         assertEquals(p1b, sw.getPort("port1"));
         assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2b, sw.getPort((short)2));
+        assertEquals(p2b, sw.getPort(OFPort.of(2)));
         assertEquals(p2b, sw.getPort("port2"));
         assertEquals(p2b, sw.getPort("PoRt2")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)3));
+        assertEquals(null, sw.getPort(OFPort.of(3)));
         assertEquals(null, sw.getPort("port3"));
         assertEquals(null, sw.getPort("PoRt3")); // case insensitive get
 
@@ -636,19 +468,19 @@ public class OFSwitchBaseTest {
         enabledPorts.clear();
         enabledPorts.add(p3);
         enabledPortNumbers.clear();
-        enabledPortNumbers.add((short)3);
+        enabledPortNumbers.add(OFPort.of(3));
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1a, sw.getPort((short)1));
+        assertEquals(p1a, sw.getPort(OFPort.of(1)));
         assertEquals(p1a, sw.getPort("port1"));
         assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2a, sw.getPort((short)2));
+        assertEquals(p2a, sw.getPort(OFPort.of(2)));
         assertEquals(p2a, sw.getPort("port2"));
         assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get
 
-        assertEquals(p3, sw.getPort((short)3));
+        assertEquals(p3, sw.getPort(OFPort.of(3)));
         assertEquals(p3, sw.getPort("port3"));
         assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get
 
@@ -684,12 +516,12 @@ public class OFSwitchBaseTest {
         enabledPorts.clear();
         enabledPorts.add(p3);
         enabledPortNumbers.clear();
-        enabledPortNumbers.add((short)3);
+        enabledPortNumbers.add(OFPort.of(3));
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
 
-        assertEquals(p3, sw.getPort((short)3));
+        assertEquals(p3, sw.getPort(OFPort.of(3)));
         assertEquals(p3, sw.getPort("port3"));
         assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get
     }
@@ -701,9 +533,8 @@ public class OFSwitchBaseTest {
      */
     @Test
     public void testBasicPortStatusOperation() {
-        OFPortStatus ps = (OFPortStatus)
-                BasicFactory.getInstance().getMessage(OFType.PORT_STATUS);
-        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();
+        OFPortStatus.Builder builder = sw.getOFFactory().buildPortStatus();
+        List<OFPortDesc> ports = new ArrayList<OFPortDesc>();
         ports.add(p1a);
         ports.add(p2a);
 
@@ -715,7 +546,7 @@ public class OFSwitchBaseTest {
                 new PortChangeEvent(p2a, PortChangeType.ADD);
 
         Collection<PortChangeEvent> expectedChanges =
-                new ArrayList<IOFSwitch.PortChangeEvent>();
+                new ArrayList<PortChangeEvent>();
         expectedChanges.add(evP1aAdded);
         expectedChanges.add(evP2aAdded);
 
@@ -735,11 +566,11 @@ public class OFSwitchBaseTest {
                    sw.getEnabledPortNumbers().isEmpty());
         assertTrue("enabled ports should be empty",
                    sw.getEnabledPorts().isEmpty());
-        assertEquals(p1a, sw.getPort((short)1));
+        assertEquals(p1a, sw.getPort(OFPort.of(1)));
         assertEquals(p1a, sw.getPort("port1"));
         assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2a, sw.getPort((short)2));
+        assertEquals(p2a, sw.getPort(OFPort.of(2)));
         assertEquals(p2a, sw.getPort("port2"));
         assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get
 
@@ -749,27 +580,27 @@ public class OFSwitchBaseTest {
         ports.add(p2a);
         ports.add(p1b);
 
-        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
-        ps.setDesc(p1b.toOFPhysicalPort());
+        builder.setReason(OFPortReason.MODIFY);
+        builder.setDesc(p1b);
 
         PortChangeEvent evP1bUp = new PortChangeEvent(p1b, PortChangeType.UP);
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         expectedChanges.clear();
         expectedChanges.add(evP1bUp);
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
-        List<ImmutablePort> enabledPorts = new ArrayList<ImmutablePort>();
+        List<OFPortDesc> enabledPorts = new ArrayList<OFPortDesc>();
         enabledPorts.add(p1b);
-        List<Short> enabledPortNumbers = new ArrayList<Short>();
-        enabledPortNumbers.add((short)1);
+        List<OFPort> enabledPortNumbers = new ArrayList<OFPort>();
+        enabledPortNumbers.add(OFPort.of(1));
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1b, sw.getPort((short)1));
+        assertEquals(p1b, sw.getPort(OFPort.of(1)));
         assertEquals(p1b, sw.getPort("port1"));
         assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2a, sw.getPort((short)2));
+        assertEquals(p2a, sw.getPort(OFPort.of(2)));
         assertEquals(p2a, sw.getPort("port2"));
         assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get
 
@@ -782,47 +613,47 @@ public class OFSwitchBaseTest {
         PortChangeEvent evP2bModified =
                 new PortChangeEvent(p2b, PortChangeType.OTHER_UPDATE);
 
-        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
-        ps.setDesc(p2b.toOFPhysicalPort());
+        builder.setReason(OFPortReason.MODIFY);
+        builder.setDesc(p2b);
 
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         expectedChanges.clear();
         expectedChanges.add(evP2bModified);
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
-        enabledPorts = new ArrayList<ImmutablePort>();
+        enabledPorts = new ArrayList<OFPortDesc>();
         enabledPorts.add(p1b);
-        enabledPortNumbers = new ArrayList<Short>();
-        enabledPortNumbers.add((short)1);
+        enabledPortNumbers = new ArrayList<OFPort>();
+        enabledPortNumbers.add(OFPort.of(1));
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1b, sw.getPort((short)1));
+        assertEquals(p1b, sw.getPort(OFPort.of(1)));
         assertEquals(p1b, sw.getPort("port1"));
         assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2b, sw.getPort((short)2));
+        assertEquals(p2b, sw.getPort(OFPort.of(2)));
         assertEquals(p2b, sw.getPort("port2"));
         assertEquals(p2b, sw.getPort("PoRt2")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)3));
+        assertEquals(null, sw.getPort(OFPort.of(3)));
         assertEquals(null, sw.getPort("port3"));
         assertEquals(null, sw.getPort("PoRt3")); // case insensitive get
 
 
         //----------------------------------------------------
-        // p1b -> p1a. Via an OFPPR_ADD, Should receive a port DOWN
+        // p1b -> p1a. Via an ADD, Should receive a port DOWN
         ports.clear();
         ports.add(p2b);
         ports.add(p1a);
 
         // we use an ADD here. We treat ADD and MODIFY the same way
-        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
-        ps.setDesc(p1a.toOFPhysicalPort());
+        builder.setReason(OFPortReason.ADD);
+        builder.setDesc(p1a);
 
         PortChangeEvent evP1aDown =
                 new PortChangeEvent(p1a, PortChangeType.DOWN);
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         expectedChanges.clear();
         expectedChanges.add(evP1aDown);
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
@@ -832,28 +663,28 @@ public class OFSwitchBaseTest {
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1a, sw.getPort((short)1));
+        assertEquals(p1a, sw.getPort(OFPort.of(1)));
         assertEquals(p1a, sw.getPort("port1"));
         assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2b, sw.getPort((short)2));
+        assertEquals(p2b, sw.getPort(OFPort.of(2)));
         assertEquals(p2b, sw.getPort("port2"));
         assertEquals(p2b, sw.getPort("PoRt2")); // case insensitive get
 
 
         //----------------------------------------------------
-        // p2b -> p2a. Via an OFPPR_ADD, Should receive a port MODIFY
+        // p2b -> p2a. Via an ADD, Should receive a port MODIFY
         ports.clear();
         ports.add(p2a);
         ports.add(p1a);
 
         // we use an ADD here. We treat ADD and MODIFY the same way
-        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
-        ps.setDesc(p2a.toOFPhysicalPort());
+        builder.setReason(OFPortReason.ADD);
+        builder.setDesc(p2a);
 
         PortChangeEvent evP2aModify =
                 new PortChangeEvent(p2a, PortChangeType.OTHER_UPDATE);
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         expectedChanges.clear();
         expectedChanges.add(evP2aModify);
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
@@ -863,11 +694,11 @@ public class OFSwitchBaseTest {
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1a, sw.getPort((short)1));
+        assertEquals(p1a, sw.getPort(OFPort.of(1)));
         assertEquals(p1a, sw.getPort("port1"));
         assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(p2a, sw.getPort((short)2));
+        assertEquals(p2a, sw.getPort(OFPort.of(2)));
         assertEquals(p2a, sw.getPort("port2"));
         assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get
 
@@ -877,12 +708,12 @@ public class OFSwitchBaseTest {
         ports.clear();
         ports.add(p1a);
 
-        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
-        ps.setDesc(p2a.toOFPhysicalPort());
+        builder.setReason(OFPortReason.DELETE);
+        builder.setDesc(p2a);
 
         PortChangeEvent evP2aDel =
                 new PortChangeEvent(p2a, PortChangeType.DELETE);
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         expectedChanges.clear();
         expectedChanges.add(evP2aDel);
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
@@ -892,11 +723,11 @@ public class OFSwitchBaseTest {
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1a, sw.getPort((short)1));
+        assertEquals(p1a, sw.getPort(OFPort.of(1)));
         assertEquals(p1a, sw.getPort("port1"));
         assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)2));
+        assertEquals(null, sw.getPort(OFPort.of(2)));
         assertEquals(null, sw.getPort("port2"));
         assertEquals(null, sw.getPort("PoRt2")); // case insensitive get
 
@@ -905,10 +736,10 @@ public class OFSwitchBaseTest {
         ports.clear();
         ports.add(p1a);
 
-        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
-        ps.setDesc(p2a.toOFPhysicalPort());
+        builder.setReason(OFPortReason.DELETE);
+        builder.setDesc(p2a);
 
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         expectedChanges.clear();
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
@@ -917,11 +748,11 @@ public class OFSwitchBaseTest {
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1a, sw.getPort((short)1));
+        assertEquals(p1a, sw.getPort(OFPort.of(1)));
         assertEquals(p1a, sw.getPort("port1"));
         assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)2));
+        assertEquals(null, sw.getPort(OFPort.of(2)));
         assertEquals(null, sw.getPort("port2"));
         assertEquals(null, sw.getPort("PoRt2")); // case insensitive get
 
@@ -930,12 +761,12 @@ public class OFSwitchBaseTest {
         // Remove p1a
         ports.clear();
 
-        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
-        ps.setDesc(p1a.toOFPhysicalPort());
+        builder.setReason(OFPortReason.DELETE);
+        builder.setDesc(p1a);
 
         PortChangeEvent evP1aDel =
                 new PortChangeEvent(p1a, PortChangeType.DELETE);
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         expectedChanges.clear();
         expectedChanges.add(evP1aDel);
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
@@ -945,11 +776,11 @@ public class OFSwitchBaseTest {
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(null, sw.getPort((short)1));
+        assertEquals(null, sw.getPort(OFPort.of(1)));
         assertEquals(null, sw.getPort("port1"));
         assertEquals(null, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)2));
+        assertEquals(null, sw.getPort(OFPort.of(2)));
         assertEquals(null, sw.getPort("port2"));
         assertEquals(null, sw.getPort("PoRt2")); // case insensitive get
 
@@ -964,28 +795,28 @@ public class OFSwitchBaseTest {
         expectedChanges.clear();
         expectedChanges.add(evP3Add);
 
-        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
-        ps.setDesc(p3.toOFPhysicalPort());
+        builder.setReason(OFPortReason.ADD);
+        builder.setDesc(p3);
 
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
         enabledPorts.clear();
         enabledPorts.add(p3);
         enabledPortNumbers.clear();
-        enabledPortNumbers.add((short)3);
+        enabledPortNumbers.add(OFPort.of(3));
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(null, sw.getPort((short)1));
+        assertEquals(null, sw.getPort(OFPort.of(1)));
         assertEquals(null, sw.getPort("port1"));
         assertEquals(null, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)2));
+        assertEquals(null, sw.getPort(OFPort.of(2)));
         assertEquals(null, sw.getPort("port2"));
         assertEquals(null, sw.getPort("PoRt2")); // case insensitive get
 
-        assertEquals(p3, sw.getPort((short)3));
+        assertEquals(p3, sw.getPort(OFPort.of(3)));
         assertEquals(p3, sw.getPort("port3"));
         assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get
 
@@ -1001,30 +832,30 @@ public class OFSwitchBaseTest {
         expectedChanges.add(evP1bAdd);
 
         // use a modify to add the port
-        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
-        ps.setDesc(p1b.toOFPhysicalPort());
+        builder.setReason(OFPortReason.MODIFY);
+        builder.setDesc(p1b);
 
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
         enabledPorts.clear();
         enabledPorts.add(p3);
         enabledPorts.add(p1b);
         enabledPortNumbers.clear();
-        enabledPortNumbers.add((short)3);
-        enabledPortNumbers.add((short)1);
+        enabledPortNumbers.add(OFPort.of(3));
+        enabledPortNumbers.add(OFPort.of(1));
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1b, sw.getPort((short)1));
+        assertEquals(p1b, sw.getPort(OFPort.of(1)));
         assertEquals(p1b, sw.getPort("port1"));
         assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)2));
+        assertEquals(null, sw.getPort(OFPort.of(2)));
         assertEquals(null, sw.getPort("port2"));
         assertEquals(null, sw.getPort("PoRt2")); // case insensitive get
 
-        assertEquals(p3, sw.getPort((short)3));
+        assertEquals(p3, sw.getPort(OFPort.of(3)));
         assertEquals(p3, sw.getPort("port3"));
         assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get
 
@@ -1037,30 +868,30 @@ public class OFSwitchBaseTest {
         expectedChanges.clear();
 
         // use a modify to add the port
-        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
-        ps.setDesc(p1b.toOFPhysicalPort());
+        builder.setReason(OFPortReason.MODIFY);
+        builder.setDesc(p1b);
 
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
         enabledPorts.clear();
         enabledPorts.add(p3);
         enabledPorts.add(p1b);
         enabledPortNumbers.clear();
-        enabledPortNumbers.add((short)3);
-        enabledPortNumbers.add((short)1);
+        enabledPortNumbers.add(OFPort.of(3));
+        enabledPortNumbers.add(OFPort.of(1));
         assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
         assertCollectionEqualsNoOrder(enabledPortNumbers,
                                    sw.getEnabledPortNumbers());
-        assertEquals(p1b, sw.getPort((short)1));
+        assertEquals(p1b, sw.getPort(OFPort.of(1)));
         assertEquals(p1b, sw.getPort("port1"));
         assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get
 
-        assertEquals(null, sw.getPort((short)2));
+        assertEquals(null, sw.getPort(OFPort.of(2)));
         assertEquals(null, sw.getPort("port2"));
         assertEquals(null, sw.getPort("PoRt2")); // case insensitive get
 
-        assertEquals(p3, sw.getPort((short)3));
+        assertEquals(p3, sw.getPort(OFPort.of(3)));
         assertEquals(p3, sw.getPort("port3"));
         assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get
     }
@@ -1073,107 +904,109 @@ public class OFSwitchBaseTest {
     public void testSetPortExceptions() {
         try {
             sw.setPorts(null);
-            fail("Excpeted exception not thrown");
+            fail("Expected exception not thrown");
         } catch (NullPointerException e) { };
 
         // two ports with same name
-        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();
-        ports.add(ImmutablePort.create("port1", (short)1));
-        ports.add(ImmutablePort.create("port1", (short)2));
+        List<OFPortDesc> ports = new ArrayList<OFPortDesc>();
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port1").setPortNo(OFPort.of(1)).build());
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port1").setPortNo(OFPort.of(2)).build());
         try {
             sw.setPorts(ports);
-            fail("Excpeted exception not thrown");
+            fail("Expected exception not thrown");
         } catch (IllegalArgumentException e) { };
 
         // two ports with same number
         ports.clear();
-        ports.add(ImmutablePort.create("port1", (short)1));
-        ports.add(ImmutablePort.create("port2", (short)1));
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port1").setPortNo(OFPort.of(1)).build());
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port2").setPortNo(OFPort.of(1)).build());
         try {
             sw.setPorts(ports);
-            fail("Excpeted exception not thrown");
+            fail("Expected exception not thrown");
         } catch (IllegalArgumentException e) { };
 
         // null port in list
         ports.clear();
-        ports.add(ImmutablePort.create("port1", (short)1));
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port1").setPortNo(OFPort.of(1)).build());
         ports.add(null);
         try {
             sw.setPorts(ports);
-            fail("Excpeted exception not thrown");
+            fail("Expected exception not thrown");
         } catch (NullPointerException e) { };
 
         // try getPort(null)
         try {
-            sw.getPort(null);
-            fail("Excpeted exception not thrown");
+            sw.getPort((String)null);
+            fail("Expected exception not thrown");
         } catch (NullPointerException e) { };
 
         //--------------------------
         // comparePorts()
         try {
             sw.comparePorts(null);
-            fail("Excpeted exception not thrown");
+            fail("Expected exception not thrown");
         } catch (NullPointerException e) { };
 
         // two ports with same name
-        ports = new ArrayList<ImmutablePort>();
-        ports.add(ImmutablePort.create("port1", (short)1));
-        ports.add(ImmutablePort.create("port1", (short)2));
+        ports = new ArrayList<OFPortDesc>();
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port1").setPortNo(OFPort.of(1)).build());
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port1").setPortNo(OFPort.of(2)).build());
         try {
             sw.comparePorts(ports);
-            fail("Excpeted exception not thrown");
+            fail("Expected exception not thrown");
         } catch (IllegalArgumentException e) { };
 
         // two ports with same number
         ports.clear();
-        ports.add(ImmutablePort.create("port1", (short)1));
-        ports.add(ImmutablePort.create("port2", (short)1));
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port1").setPortNo(OFPort.of(1)).build());
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port2").setPortNo(OFPort.of(1)).build());
         try {
             sw.comparePorts(ports);
-            fail("Excpeted exception not thrown");
+            fail("Expected exception not thrown");
         } catch (IllegalArgumentException e) { };
 
         // null port in list
         ports.clear();
-        ports.add(ImmutablePort.create("port1", (short)1));
+        ports.add(sw.getOFFactory().buildPortDesc().setName("port1").setPortNo(OFPort.of(1)).build());
         ports.add(null);
         try {
             sw.comparePorts(ports);
-            fail("Excpeted exception not thrown");
+            fail("Expected exception not thrown");
         } catch (NullPointerException e) { };
 
         // try getPort(null)
         try {
-            sw.getPort(null);
-            fail("Excpeted exception not thrown");
+            sw.getPort((String)null);
+            fail("Expected exception not thrown");
         } catch (NullPointerException e) { };
 
     }
 
     @Test
     public void testPortStatusExceptions() {
-        OFPortStatus ps = (OFPortStatus)
-                BasicFactory.getInstance().getMessage(OFType.PORT_STATUS);
+        OFPortStatus.Builder builder = sw.getOFFactory().buildPortStatus();
 
         try {
             sw.processOFPortStatus(null);
             fail("Expected exception not thrown");
         } catch (NullPointerException e)  { }
 
+        /* There's no way with the new LOXI openflowj to create messages with
+         * invalid fields.
         // illegal reason code
-        ps.setReason((byte)0x42);
-        ps.setDesc(ImmutablePort.create("p1", (short)1).toOFPhysicalPort());
+        builder.setReason((byte)0x42);
+        builder.setDesc(ImmutablePort.create("p1", OFPort.of(1)).toOFPortDesc(sw));
         try {
-            sw.processOFPortStatus(ps);
+            sw.processOFPortStatus(builder.build());
             fail("Expected exception not thrown");
         } catch (IllegalArgumentException e)  { }
+        */
 
         // null port
-        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
-        ps.setDesc(null);
+        builder.setReason(OFPortReason.ADD);
+        builder.setDesc(null);
         try {
-            sw.processOFPortStatus(ps);
+            sw.processOFPortStatus(builder.build());
             fail("Expected exception not thrown");
         } catch (NullPointerException e)  { }
     }
@@ -1198,7 +1031,7 @@ public class OFSwitchBaseTest {
                                       Collection<PortChangeEvent> actualEvents) {
         String inputDesc = String.format("earlyEvents=%s, lateEvents=%s, " +
                 "anytimeEvents=%s, actualEvents=%s",
-                earlyEvents, lateEvents, anytimeEvents, actualEvents);
+                earlyEvents.toString(), lateEvents.toString(), anytimeEvents.toString(), actualEvents.toString());
         // Make copies of expected lists, so we can modify them
         Collection<PortChangeEvent> early =
                 new ArrayList<PortChangeEvent>(earlyEvents);
@@ -1260,7 +1093,7 @@ public class OFSwitchBaseTest {
     @Test
     public void testSetPortNameNumberMappingChange() {
 
-        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();
+        List<OFPortDesc> ports = new ArrayList<OFPortDesc>();
         Collection<PortChangeEvent> early = new ArrayList<PortChangeEvent>();
         Collection<PortChangeEvent> late = new ArrayList<PortChangeEvent>();
         Collection<PortChangeEvent> anytime = new ArrayList<PortChangeEvent>();
@@ -1364,7 +1197,7 @@ public class OFSwitchBaseTest {
 
     @Test
     public void testPortStatusNameNumberMappingChange() {
-        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();
+        List<OFPortDesc> ports = new ArrayList<OFPortDesc>();
         Collection<PortChangeEvent> early = new ArrayList<PortChangeEvent>();
         Collection<PortChangeEvent> late = new ArrayList<PortChangeEvent>();
         Collection<PortChangeEvent> anytime = new ArrayList<PortChangeEvent>();
@@ -1376,34 +1209,33 @@ public class OFSwitchBaseTest {
         sw.setPorts(ports);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
 
-        OFPortStatus ps = (OFPortStatus)
-                BasicFactory.getInstance().getMessage(OFType.PORT_STATUS);
+        OFPortStatus.Builder builder = sw.getOFFactory().buildPortStatus();
 
         // portFoo1 -> portFoo2 via MODIFY : name collision
-        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
-        ps.setDesc(portFoo2.toOFPhysicalPort());
+        builder.setReason(OFPortReason.MODIFY);
+        builder.setDesc(portFoo2);
         ports.clear();
         ports.add(portFoo2);
         ports.add(p1a);
         early.clear();
         late.clear();
         anytime.clear();
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         early.add(portFoo1Del);
         late.add(portFoo2Add);
         assertChangeEvents(early, late, anytime, actualChanges);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
 
         // portFoo2 -> portBar2 via ADD number collision
-        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
-        ps.setDesc(portBar2.toOFPhysicalPort());
+        builder.setReason(OFPortReason.ADD);
+        builder.setDesc(portBar2);
         ports.clear();
         ports.add(portBar2);
         ports.add(p1a);
         early.clear();
         late.clear();
         anytime.clear();
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         early.add(portFoo2Del);
         late.add(portBar2Add);
         assertChangeEvents(early, late, anytime, actualChanges);
@@ -1417,14 +1249,14 @@ public class OFSwitchBaseTest {
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
 
         // portFoo1 + portBar2 -> portFoo2: name and number collision
-        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
-        ps.setDesc(portFoo2.toOFPhysicalPort());
+        builder.setReason(OFPortReason.MODIFY);
+        builder.setDesc(portFoo2);
         ports.clear();
         ports.add(portFoo2);
         early.clear();
         late.clear();
         anytime.clear();
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         early.add(portFoo1Del);
         early.add(portBar2Del);
         late.add(portFoo2Add);
@@ -1435,13 +1267,13 @@ public class OFSwitchBaseTest {
         // Test DELETEs
 
         // del portFoo1: name exists (portFoo2), but number doesn't.
-        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
-        ps.setDesc(portFoo1.toOFPhysicalPort());
+        builder.setReason(OFPortReason.DELETE);
+        builder.setDesc(portFoo1);
         ports.clear();
         early.clear();
         late.clear();
         anytime.clear();
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         anytime.add(portFoo2Del);
         assertChangeEvents(early, late, anytime, actualChanges);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
@@ -1453,13 +1285,13 @@ public class OFSwitchBaseTest {
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
 
         // del portBar1: number exists (portFoo1), but name doesn't.
-        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
-        ps.setDesc(portBar1.toOFPhysicalPort());
+        builder.setReason(OFPortReason.DELETE);
+        builder.setDesc(portBar1);
         ports.clear();
         early.clear();
         late.clear();
         anytime.clear();
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         anytime.add(portFoo1Del);
         assertChangeEvents(early, late, anytime, actualChanges);
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
@@ -1473,13 +1305,13 @@ public class OFSwitchBaseTest {
         assertCollectionEqualsNoOrder(ports, sw.getPorts());
 
         // del portFoo2: name and number exists
-        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
-        ps.setDesc(portFoo2.toOFPhysicalPort());
+        builder.setReason(OFPortReason.DELETE);
+        builder.setDesc(portFoo2);
         ports.clear();
         early.clear();
         late.clear();
         anytime.clear();
-        actualChanges = sw.processOFPortStatus(ps);
+        actualChanges = sw.processOFPortStatus(builder.build());
         anytime.add(portFoo1Del);
         anytime.add(portBar2Del);
         assertChangeEvents(early, late, anytime, actualChanges);
@@ -1488,7 +1320,10 @@ public class OFSwitchBaseTest {
 
     @Test
     public void testSubHandshake() {
-        OFMessage m = BasicFactory.getInstance().getMessage(OFType.VENDOR);
+        OFMessage m = sw.getOFFactory().buildRoleReply()
+                .setXid(1)
+                .setRole(OFControllerRole.ROLE_MASTER)
+                .build();
         // test execptions before handshake is started
         try {
             sw.processDriverHandshakeMessage(m);
@@ -1515,4 +1350,55 @@ public class OFSwitchBaseTest {
         } catch (SwitchDriverSubHandshakeAlreadyStarted e) { /* expected */ }
     }
 
+    // This should throw an error
+    @Test
+    public void testMissingConnection() {
+
+        // Just to make sure so this test is worth it
+       assertFalse("Switch should not have a connection with auxId 5", sw.getConnections().contains(OFAuxId.of(5)));
+
+       try{
+           sw.getConnection(OFAuxId.of(5));
+           fail("Expected exception not thrown");
+       }
+       catch(IllegalArgumentException e){ /* expected */ }
+    }
+
+
+    // This should throw an error
+    @Test
+    public void testInvalidLogicalOFMessageCategory() {
+
+        LogicalOFMessageCategory bad = new LogicalOFMessageCategory("bad", 2);
+        assertFalse("Controller should not any logical OFMessage categories", switchManager.isCategoryRegistered(bad));
+
+        reset(switchManager);
+        expect(switchManager.isCategoryRegistered(bad)).andReturn(false);
+        replay(switchManager);
+
+       try{
+           sw.write(testMessage, bad);
+           fail("Expected exception not thrown");
+       }
+       catch(IllegalArgumentException e){ /* expected */ }
+
+       verify(switchManager);
+    }
+
+    // This should not throw an error
+    @Test
+    public void testValidLogicalOFMessageCategory() {
+
+        LogicalOFMessageCategory category = new LogicalOFMessageCategory("test", 1);
+        assertFalse("Controller should not have any logical OFMessage categories", switchManager.isCategoryRegistered(category));
+
+        reset(switchManager);
+        expect(switchManager.isCategoryRegistered(category)).andReturn(true);
+        replay(switchManager);
+
+        sw.write(testMessage, category);
+
+        verify(switchManager);
+    }
+
 }
diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
index b06589a30a6493bd22d7da347a7bab7e6d4fd642..2148b14df8e3299728d094e332243e0361a541ac 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
@@ -18,44 +18,30 @@
 package net.floodlightcontroller.core.internal;
 
 import static org.easymock.EasyMock.*;
-
 import static org.junit.Assert.*;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
+import org.junit.Before;
+import org.junit.Test;
+
+import net.floodlightcontroller.test.FloodlightTestCase;
+
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+
 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.IListener;
 import net.floodlightcontroller.core.IListener.Command;
-import net.floodlightcontroller.core.IOFMessageFilterManagerService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
-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.OFMessageFilterManager;
 import net.floodlightcontroller.core.RoleInfo;
-import net.floodlightcontroller.core.SwitchSyncRepresentation;
+import net.floodlightcontroller.core.SwitchDescription;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
-import net.floodlightcontroller.core.test.MockFloodlightProvider;
 import net.floodlightcontroller.core.test.MockThreadPoolService;
-import net.floodlightcontroller.counter.CounterStore;
-import net.floodlightcontroller.counter.ICounterStoreService;
-import net.floodlightcontroller.debugcounter.DebugCounter;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import net.floodlightcontroller.debugevent.DebugEvent;
+import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
+import net.floodlightcontroller.debugevent.DebugEventService;
 import net.floodlightcontroller.debugevent.IDebugEventService;
 import net.floodlightcontroller.packet.ARP;
 import net.floodlightcontroller.packet.Ethernet;
@@ -67,53 +53,61 @@ import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.restserver.RestApiServer;
 import net.floodlightcontroller.storage.IStorageSourceService;
 import net.floodlightcontroller.storage.memory.MemoryStorageSource;
-import net.floodlightcontroller.test.FloodlightTestCase;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.threadpool.ThreadPool;
 
 import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.openflow.protocol.OFFeaturesReply;
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPacketIn.OFPacketInReason;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFPhysicalPort;
-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.protocol.factory.BasicFactory;
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
-import org.openflow.util.HexString;
-import org.sdnplatform.sync.IStoreClient;
+
+import net.floodlightcontroller.core.IShutdownListener;
+import net.floodlightcontroller.core.IShutdownService;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
+import net.floodlightcontroller.core.test.MockSwitchManager;
+
+import net.floodlightcontroller.core.IOFSwitchBackend;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketInReason;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.sdnplatform.sync.ISyncService;
-import org.sdnplatform.sync.IStoreListener.UpdateType;
 import org.sdnplatform.sync.test.MockSyncService;
 
+import com.google.common.collect.ImmutableList;
+
 
 public class ControllerTest extends FloodlightTestCase {
 
     private Controller controller;
     private MockThreadPoolService tp;
     private MockSyncService syncService;
-    private IStoreClient<Long, SwitchSyncRepresentation> storeClient;
     private IPacket testPacket;
     private OFPacketIn pi;
+    
+    // FIXME:LOJI: For now just work with OF 1.0
+    private final OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
+    private static DatapathId DATAPATH_ID_0 = DatapathId.of(0);
 
     @Override
     @Before
     public void setUp() throws Exception {
-        doSetUp(Role.MASTER);
+        doSetUp(HARole.ACTIVE);
     }
 
 
-    public void doSetUp(Role role) throws Exception {
+    public void doSetUp(HARole role) throws Exception {
         super.setUp();
         FloodlightModuleContext fmc = new FloodlightModuleContext();
-
         FloodlightProvider cm = new FloodlightProvider();
+        
         fmc.addConfigParam(cm, "role", role.toString());
         controller = (Controller)cm.getServiceImpls().get(IFloodlightProviderService.class);
         fmc.addService(IFloodlightProviderService.class, controller);
@@ -123,31 +117,40 @@ public class ControllerTest extends FloodlightTestCase {
 
         RestApiServer restApi = new RestApiServer();
         fmc.addService(IRestApiService.class, restApi);
-
-        CounterStore cs = new CounterStore();
-        fmc.addService(ICounterStoreService.class, cs);
+        
+        ThreadPool threadPool = new ThreadPool();
+        fmc.addService(IThreadPoolService.class, threadPool);
+        
+        MockSwitchManager switchService = new MockSwitchManager();
+        fmc.addService(IOFSwitchService.class, switchService);
 
         PktInProcessingTime ppt = new PktInProcessingTime();
         fmc.addService(IPktInProcessingTimeService.class, ppt);
 
         // TODO: should mock IDebugCounterService and make sure
         // the expected counters are updated.
-        DebugCounter debugCounterService = new DebugCounter();
+        DebugCounterServiceImpl debugCounterService = new DebugCounterServiceImpl();
         fmc.addService(IDebugCounterService.class, debugCounterService);
 
-        DebugEvent debugEventService = new DebugEvent();
+        DebugEventService debugEventService = new DebugEventService();
         fmc.addService(IDebugEventService.class, debugEventService);
 
+        IShutdownService shutdownService = createMock(IShutdownService.class);
+        shutdownService.registerShutdownListener(anyObject(IShutdownListener.class));
+        expectLastCall().anyTimes();
+        replay(shutdownService);
+        fmc.addService(IShutdownService.class, shutdownService);
+        verify(shutdownService);
+        
         tp = new MockThreadPoolService();
         fmc.addService(IThreadPoolService.class, tp);
 
         syncService = new MockSyncService();
         fmc.addService(ISyncService.class, syncService);
 
-
-
         ppt.init(fmc);
         restApi.init(fmc);
+        threadPool.init(fmc);
         memstorage.init(fmc);
         tp.init(fmc);
         debugCounterService.init(fmc);
@@ -157,6 +160,7 @@ public class ControllerTest extends FloodlightTestCase {
 
         ppt.startUp(fmc);
         restApi.startUp(fmc);
+        threadPool.startUp(fmc);
         memstorage.startUp(fmc);
         tp.startUp(fmc);
         debugCounterService.startUp(fmc);
@@ -164,11 +168,6 @@ public class ControllerTest extends FloodlightTestCase {
         syncService.startUp(fmc);
         cm.startUp(fmc);
 
-        storeClient =
-                syncService.getStoreClient(Controller.SWITCH_SYNC_STORE_NAME,
-                                           Long.class,
-                                           SwitchSyncRepresentation.class);
-
         testPacket = new Ethernet()
         .setSourceMACAddress("00:44:33:22:11:00")
         .setDestinationMACAddress("00:11:22:33:44:55")
@@ -186,16 +185,17 @@ public class ControllerTest extends FloodlightTestCase {
                 .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
         byte[] testPacketSerialized = testPacket.serialize();
 
-        pi = ((OFPacketIn) BasicFactory.getInstance().getMessage(OFType.PACKET_IN))
-                .setBufferId(-1)
-                .setInPort((short) 1)
-                .setPacketData(testPacketSerialized)
+        //TODO @Ryan should this be for any version? Should 1.0 and 1.3 be tested here?
+        // The specific factory can be obtained from the switch, but we don't have one
+        pi = (OFPacketIn) factory.buildPacketIn()
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setInPort(OFPort.of(1))
+                .setData(testPacketSerialized)
                 .setReason(OFPacketInReason.NO_MATCH)
-                .setTotalLength((short) testPacketSerialized.length);
+                .setTotalLen(testPacketSerialized.length).build();
 
     }
 
-    @Override
     @After
     public void tearDown() {
         tp.getScheduledExecutor().shutdownNow();
@@ -208,19 +208,16 @@ public class ControllerTest extends FloodlightTestCase {
         return controller;
     }
 
-    private static OFDescriptionStatistics createOFDescriptionStatistics() {
-        OFDescriptionStatistics desc = new OFDescriptionStatistics();
-        desc.setDatapathDescription("");
-        desc.setHardwareDescription("");
-        desc.setManufacturerDescription("");
-        desc.setSerialNumber("");
-        desc.setSoftwareDescription("");
-        return desc;
+    private static SwitchDescription createSwitchDescription() {
+        return new SwitchDescription();
     }
 
-    private static OFFeaturesReply createOFFeaturesReply() {
-        OFFeaturesReply fr = new OFFeaturesReply();
-        fr.setPorts(Collections.<OFPhysicalPort>emptyList());
+    private OFFeaturesReply createOFFeaturesReply(DatapathId datapathId) {
+        OFFeaturesReply fr = factory.buildFeaturesReply()
+                .setXid(0)
+                .setDatapathId(datapathId)
+                .setPorts(ImmutableList.<OFPortDesc>of())
+                .build();
         return fr;
     }
 
@@ -228,28 +225,26 @@ public class ControllerTest extends FloodlightTestCase {
     /** Set the mock expectations for sw when sw is passed to addSwitch
      * The same expectations can be used when a new SwitchSyncRepresentation
      * is created from the given mocked switch */
-    protected void setupSwitchForAddSwitch(IOFSwitch sw, long dpid,
-                                           OFDescriptionStatistics desc,
+    protected void setupSwitchForAddSwitch(IOFSwitch sw, DatapathId datapathId,
+                                           SwitchDescription description,
                                            OFFeaturesReply featuresReply) {
-        String dpidString = HexString.toHexString(dpid);
-
-        if (desc == null) {
-            desc = createOFDescriptionStatistics();
+    	String dpidString = datapathId.toString();
+        if (description == null) {
+            description = createSwitchDescription();
         }
         if (featuresReply == null) {
-            featuresReply = createOFFeaturesReply();
-            featuresReply.setDatapathId(dpid);
+            featuresReply = createOFFeaturesReply(datapathId);
         }
-        List<ImmutablePort> ports =
-                ImmutablePort.immutablePortListOf(featuresReply.getPorts());
+        List<OFPortDesc> ports = featuresReply.getPorts();
 
-        expect(sw.getId()).andReturn(dpid).anyTimes();
+        expect(sw.getOFFactory()).andReturn(OFFactories.getFactory(OFVersion.OF_10)).anyTimes();
+        expect(sw.getId()).andReturn(datapathId).anyTimes();
         expect(sw.getStringId()).andReturn(dpidString).anyTimes();
-        expect(sw.getDescriptionStatistics()) .andReturn(desc).atLeastOnce();
+        expect(sw.getSwitchDescription()).andReturn(description).atLeastOnce();
         expect(sw.getBuffers())
-                .andReturn(featuresReply.getBuffers()).atLeastOnce();
+                .andReturn(featuresReply.getNBuffers()).atLeastOnce();
         expect(sw.getTables())
-                .andReturn(featuresReply.getTables()).atLeastOnce();
+                .andReturn(featuresReply.getNTables()).atLeastOnce();
         expect(sw.getCapabilities())
                 .andReturn(featuresReply.getCapabilities()).atLeastOnce();
         expect(sw.getActions())
@@ -274,9 +269,9 @@ public class ControllerTest extends FloodlightTestCase {
 
     @Test
     public void testHandleMessagesNoListeners() throws Exception {
-        IOFSwitch sw = createMock(IOFSwitch.class);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
+    	IOFSwitch sw = createMock(IOFSwitch.class);
+        expect(sw.getId()).andReturn(DatapathId.NONE).anyTimes();
+        expect(sw.getStringId()).andReturn(DATAPATH_ID_0.toString()).anyTimes();
         replay(sw);
         controller.handleMessage(sw, pi, null);
         verify(sw);
@@ -296,7 +291,7 @@ public class ControllerTest extends FloodlightTestCase {
         controller.removeOFMessageListeners(OFType.PACKET_IN);
 
         IOFSwitch sw = createMock(IOFSwitch.class);
-        expect(sw.getId()).andReturn(0L).anyTimes();
+        expect(sw.getId()).andReturn(DatapathId.NONE).anyTimes();
         expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
 
         // Setup listener orderings
@@ -390,8 +385,7 @@ public class ControllerTest extends FloodlightTestCase {
         verify(test2);
         verify(test3);
 
-        OFFlowMod fm = (OFFlowMod)
-                BasicFactory.getInstance().getMessage(OFType.FLOW_MOD);
+        OFFlowMod fm = (OFFlowMod) factory.buildFlowModify().build();
 
         //------------------
         // Test FlowMod handling: all listeners return CONTINUE
@@ -425,10 +419,10 @@ public class ControllerTest extends FloodlightTestCase {
 
     @Test
     public void testHandleMessagesSlave() throws Exception {
-        doSetUp(Role.SLAVE);
+        doSetUp(HARole.STANDBY);
         IOFSwitch sw = createMock(IOFSwitch.class);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
+        expect(sw.getId()).andReturn(DatapathId.NONE).anyTimes();
+        expect(sw.getStringId()).andReturn(DatapathId.NONE.toString()).anyTimes();
 
         IOFMessageListener test1 = createMock(IOFMessageListener.class);
         expect(test1.getName()).andReturn("test1").atLeastOnce();
@@ -448,7 +442,7 @@ public class ControllerTest extends FloodlightTestCase {
         //---------------------------------
         // transition to Master
         //--------------------------------
-        controller.setRole(Role.MASTER, "FooBar");
+        controller.setRole(HARole.ACTIVE, "FooBar");
 
         // transitioned but HA listeneres not yet notified.
         // message should not be dispatched
@@ -473,8 +467,8 @@ public class ControllerTest extends FloodlightTestCase {
     @Test
     public void testHandleMessageWithContext() throws Exception {
         IOFSwitch sw = createMock(IOFSwitch.class);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
+        expect(sw.getId()).andReturn(DatapathId.NONE).anyTimes();
+        expect(sw.getStringId()).andReturn(DatapathId.NONE.toString()).anyTimes();
 
         IOFMessageListener test1 = createMock(IOFMessageListener.class);
         expect(test1.getName()).andReturn("test1").anyTimes();
@@ -509,129 +503,16 @@ public class ControllerTest extends FloodlightTestCase {
         assertArrayEquals(testPacket.serialize(), eth.serialize());
     }
 
-
-    /**
-     * Test injectMessage and also do some more tests for listener ordering
-     * and handling of Command.STOP
-     * @throws Exception
-     */
-    @Test
-    public void testInjectMessage() throws Exception {
-        FloodlightContext cntx = new FloodlightContext();
-        IOFSwitch sw = createMock(IOFSwitch.class);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
-
-        // Add listeners
-        IOFMessageListener test1 = createMock(IOFMessageListener.class);
-        expect(test1.getName()).andReturn("test1").anyTimes();
-        setupListenerOrdering(test1);
-
-        IOFMessageListener test2 = createMock(IOFMessageListener.class);
-        expect(test2.getName()).andReturn("test2").anyTimes();
-        test2.isCallbackOrderingPostreq(OFType.PACKET_IN, "test1");
-        expectLastCall().andReturn(true).atLeastOnce();
-        setupListenerOrdering(test2);
-        replay(test1, test2);
-        controller.addOFMessageListener(OFType.PACKET_IN, test1);
-        controller.addOFMessageListener(OFType.PACKET_IN, test2);
-        verify(test1);
-        verify(test2);
-
-        // Test inject with null switch and no message. Should not work.
-        reset(test1, test2);
-        replay(test1, test2, sw);
-        try {
-            controller.injectOfMessage(null, pi);
-            fail("InjectOfMessage should have thrown a NPE");
-        } catch (NullPointerException e) {
-            // expected
-        }
-        try {
-            controller.injectOfMessage(null, pi, cntx);
-            fail("InjectOfMessage should have thrown a NPE");
-        } catch (NullPointerException e) {
-            // expected
-        }
-        try {
-            controller.injectOfMessage(sw, null);
-            fail("InjectOfMessage should have thrown a NPE");
-        } catch (NullPointerException e) {
-            // expected
-        }
-        try {
-            controller.injectOfMessage(sw, null, cntx);
-            fail("InjectOfMessage should have thrown a NPE");
-        } catch (NullPointerException e) {
-            // expected
-        }
-        verify(test1);
-        verify(test2);
-        verify(sw);
-
-        //
-        // Test inject with inActive switch. Should not work.
-        reset(test1, test2, sw);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
-        expect(sw.isActive()).andReturn(false).atLeastOnce();
-        replay(test1, test2, sw);
-        assertFalse("Inject should have failed",
-                    controller.injectOfMessage(sw, pi));
-        assertFalse("Inject should have failed",
-                    controller.injectOfMessage(sw, pi, cntx));
-        verify(test1);
-        verify(test2);
-        verify(sw);
-
-
-        // Test inject in the "normal" case without context
-        reset(test1, test2, sw);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
-        expect(sw.isActive()).andReturn(true).atLeastOnce();
-        expect(test2.receive(same(sw), same(pi) , isA(FloodlightContext.class)))
-                .andReturn(Command.STOP);
-        // test1 will not receive any message!
-        replay(test1, test2, sw);
-        assertTrue("Inject should have worked",
-                    controller.injectOfMessage(sw, pi));
-        verify(test1);
-        verify(test2);
-        verify(sw);
-
-        // Test inject in the "normal" case with context
-        reset(test1, test2, sw);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
-        expect(sw.isActive()).andReturn(true).atLeastOnce();
-        expect(test2.receive(same(sw), same(pi) , same(cntx)))
-                .andReturn(Command.STOP);
-        // test1 will not receive any message!
-        replay(test1, test2, sw);
-        assertTrue("Inject should have worked",
-                    controller.injectOfMessage(sw, pi, cntx));
-        verify(test1);
-        verify(test2);
-        verify(sw);
-
-        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
-                IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-        assertArrayEquals(testPacket.serialize(), eth.serialize());
-    }
-
-
     /**
      * Test handleOutgoingMessage and also test listener ordering
      * @throws Exception
      */
     @Test
     public void testHandleOutgoingMessage() throws Exception {
-        OFMessage m = BasicFactory.getInstance().getMessage(OFType.ECHO_REQUEST);
-        FloodlightContext cntx = new FloodlightContext();
-        IOFSwitch sw = createMock(IOFSwitch.class);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
+        OFMessage m = factory.buildEchoRequest().build();
+        IOFSwitchBackend sw = createMock(IOFSwitchBackend.class);
+        expect(sw.getId()).andReturn(DATAPATH_ID_0).anyTimes();
+        expect(sw.getStringId()).andReturn(DATAPATH_ID_0.toString()).anyTimes();
 
         // Add listeners
         IOFMessageListener test1 = createMock(IOFMessageListener.class);
@@ -664,13 +545,13 @@ public class ControllerTest extends FloodlightTestCase {
         reset(test1, test2, test3);
         replay(test1, test2, test3, sw);
         try {
-            controller.handleOutgoingMessage(null, pi, cntx);
+            controller.handleOutgoingMessage(null, pi);
             fail("handleOutgoindMessage should have thrown a NPE");
         } catch (NullPointerException e) {
             // expected
         }
         try {
-            controller.handleOutgoingMessage(sw, null, cntx);
+            controller.handleOutgoingMessage(sw, null);
             fail("handleOutgoingMessage should have thrown a NPE");
         } catch (NullPointerException e) {
             // expected
@@ -682,15 +563,15 @@ public class ControllerTest extends FloodlightTestCase {
 
         // Test the handleOutgoingMessage
         reset(test1, test2, test3, sw);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
-        expect(test2.receive(same(sw), same(m) , same(cntx)))
+        expect(sw.getId()).andReturn(DATAPATH_ID_0).anyTimes();
+        expect(sw.getStringId()).andReturn(DATAPATH_ID_0.toString()).anyTimes();
+        expect(test2.receive(same(sw), same(m) , isA(FloodlightContext.class)))
                 .andReturn(Command.STOP);
-        expect(test3.receive(same(sw), same(m) , same(cntx)))
+        expect(test3.receive(same(sw), same(m) , isA(FloodlightContext.class)))
                 .andReturn(Command.CONTINUE);
         // test1 will not receive any message!
         replay(test1, test2, test3, sw);
-        controller.handleOutgoingMessage(sw, m, cntx);
+        controller.handleOutgoingMessage(sw, m);
         verify(test1);
         verify(test2);
         verify(test3);
@@ -698,15 +579,15 @@ public class ControllerTest extends FloodlightTestCase {
 
         // Test the handleOutgoingMessage with null context
         reset(test1, test2, test3, sw);
-        expect(sw.getId()).andReturn(0L).anyTimes();
-        expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
+        expect(sw.getId()).andReturn(DATAPATH_ID_0).anyTimes();
+        expect(sw.getStringId()).andReturn(DATAPATH_ID_0.toString()).anyTimes();
         expect(test2.receive(same(sw), same(m) , isA(FloodlightContext.class)))
                 .andReturn(Command.STOP);
         expect(test3.receive(same(sw), same(m) , isA(FloodlightContext.class)))
                 .andReturn(Command.CONTINUE);
         // test1 will not receive any message!
         replay(test1, test2, test3, sw);
-        controller.handleOutgoingMessage(sw, m, null);
+        controller.handleOutgoingMessage(sw, m);
         verify(test1);
         verify(test2);
         verify(test3);
@@ -715,141 +596,20 @@ public class ControllerTest extends FloodlightTestCase {
         // Test for message without listeners
         reset(test1, test2, test3, sw);
         replay(test1, test2, test3, sw);
-        m = BasicFactory.getInstance().getMessage(OFType.ECHO_REPLY);
-        controller.handleOutgoingMessage(sw, m, cntx);
+        m = factory.buildEchoReply().build();
+        controller.handleOutgoingMessage(sw, m);
         verify(test1);
         verify(test2);
         verify(test3);
         verify(sw);
     }
 
-
-    @Test
-    public void testMessageFilterManager() throws Exception {
-        class MyOFMessageFilterManager extends OFMessageFilterManager {
-            public MyOFMessageFilterManager(int timer_interval) {
-                super();
-                TIMER_INTERVAL = timer_interval;
-            }
-        }
-        FloodlightModuleContext fmCntx = new FloodlightModuleContext();
-        MockFloodlightProvider mfp = new MockFloodlightProvider();
-        OFMessageFilterManager mfm = new MyOFMessageFilterManager(100);
-        MockThreadPoolService mtp = new MockThreadPoolService();
-        fmCntx.addService(IOFMessageFilterManagerService.class, mfm);
-        fmCntx.addService(IFloodlightProviderService.class, mfp);
-        fmCntx.addService(IThreadPoolService.class, mtp);
-        String sid = null;
-
-        mfm.init(fmCntx);
-        mfm.startUp(fmCntx);
-
-        ConcurrentHashMap <String, String> filter;
-        int i;
-
-        //Adding the filter works -- adds up to the maximum filter size.
-        for(i=mfm.getMaxFilterSize(); i > 0; --i) {
-            filter = new ConcurrentHashMap<String,String>();
-            filter.put("mac", String.format("00:11:22:33:44:%d%d", i,i));
-            sid = mfm.setupFilter(null, filter, 60);
-            assertTrue(mfm.getNumberOfFilters() == mfm.getMaxFilterSize() - i +1);
-        }
-
-        // Add one more to see if you can't
-        filter = new ConcurrentHashMap<String,String>();
-        filter.put("mac", "mac2");
-        mfm.setupFilter(null, filter, 10*1000);
-
-        assertTrue(mfm.getNumberOfFilters() == mfm.getMaxFilterSize());
-
-        // Deleting the filter works.
-        mfm.setupFilter(sid, null, -1);
-        assertTrue(mfm.getNumberOfFilters() == mfm.getMaxFilterSize()-1);
-
-        // Creating mock switch to which we will send packet out and
-        IOFSwitch sw = createMock(IOFSwitch.class);
-        expect(sw.getId()).andReturn(new Long(0));
-
-        // Mock Packet-in
-        IPacket testPacket = new Ethernet()
-        .setSourceMACAddress("00:44:33:22:11:00")
-        .setDestinationMACAddress("00:11:22:33:44:55")
-        .setEtherType(Ethernet.TYPE_ARP)
-        .setPayload(
-                new ARP()
-                .setHardwareType(ARP.HW_TYPE_ETHERNET)
-                .setProtocolType(ARP.PROTO_TYPE_IP)
-                .setHardwareAddressLength((byte) 6)
-                .setProtocolAddressLength((byte) 4)
-                .setOpCode(ARP.OP_REPLY)
-                .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00"))
-                .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
-                .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
-                .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
-        byte[] testPacketSerialized = testPacket.serialize();
-
-        // Build the PacketIn
-        OFPacketIn pi = ((OFPacketIn) BasicFactory.getInstance().getMessage(OFType.PACKET_IN))
-                .setBufferId(-1)
-                .setInPort((short) 1)
-                .setPacketData(testPacketSerialized)
-                .setReason(OFPacketInReason.NO_MATCH)
-                .setTotalLength((short) testPacketSerialized.length);
-
-        // Mock Packet-out
-        OFPacketOut packetOut =
-                (OFPacketOut) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
-        packetOut.setBufferId(pi.getBufferId())
-        .setInPort(pi.getInPort());
-        List<OFAction> poactions = new ArrayList<OFAction>();
-        poactions.add(new OFActionOutput(OFPort.OFPP_TABLE.getValue(), (short) 0));
-        packetOut.setActions(poactions)
-        .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
-        .setPacketData(testPacketSerialized)
-        .setLengthU(OFPacketOut.MINIMUM_LENGTH+packetOut.getActionsLength()+testPacketSerialized.length);
-
-        FloodlightContext cntx = new FloodlightContext();
-        IFloodlightProviderService.bcStore.put(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD, (Ethernet) testPacket);
-
-
-        // Let's check the listeners.
-        List <IOFMessageListener> lm;
-
-        // Check to see if all the listeners are active.
-        lm = mfp.getListeners().get(OFType.PACKET_OUT);
-        assertTrue(lm.size() == 1);
-        assertTrue(lm.get(0).equals(mfm));
-
-        lm = mfp.getListeners().get(OFType.FLOW_MOD);
-        assertTrue(lm.size() == 1);
-        assertTrue(lm.get(0).equals(mfm));
-
-        lm = mfp.getListeners().get(OFType.PACKET_IN);
-        assertTrue(lm.size() == 1);
-        assertTrue(lm.get(0).equals(mfm));
-
-        HashSet<String> matchedFilters;
-
-        // Send a packet in and check if it matches a filter.
-        matchedFilters = mfm.getMatchedFilters(pi, cntx);
-        assertTrue(matchedFilters.size() == 1);
-
-        // Send a packet out and check if it matches a filter
-        matchedFilters = mfm.getMatchedFilters(packetOut, cntx);
-        assertTrue(matchedFilters.size() == 1);
-
-        // Wait for all filters to be timed out.
-        Thread.sleep(150);
-        assertEquals(0, mfm.getNumberOfFilters());
-    }
-
-
     @Test
     public void testGetRoleInfoDefault() {
         RoleInfo info = controller.getRoleInfo();
-        assertEquals(Role.MASTER.toString(), info.getRole());
+        assertEquals(HARole.ACTIVE, info.getRole());
         assertNotNull(info.getRoleChangeDescription());
-        assertEquals(Role.MASTER, controller.getRole());
+        assertEquals(HARole.ACTIVE, controller.getRole());
         // FIXME: RoleInfo's date. but the format is kinda broken
     }
 
@@ -859,26 +619,19 @@ public class ControllerTest extends FloodlightTestCase {
      */
     @Test
     public void testChannelHandlerMaster() {
-        OFChannelHandler h = createMock(OFChannelHandler.class);
-
-        // Add the handler. The controller should call sendRoleRequest
-        h.sendRoleRequest(Role.MASTER);
-        expectLastCall().once();
-        replay(h);
-        controller.addSwitchChannelAndSendInitialRole(h);
-        verify(h);
+    	OFSwitchHandshakeHandler h = createMock(OFSwitchHandshakeHandler.class);
 
         // Reassert the role.
         reset(h);
-        h.sendRoleRequestIfNotPending(Role.MASTER);
+        h.sendRoleRequestIfNotPending(OFControllerRole.ROLE_MASTER);
         replay(h);
-        controller.reassertRole(h, Role.MASTER);
+        controller.reassertRole(h, HARole.ACTIVE);
         verify(h);
 
         // reassert a different role: no-op
         reset(h);
         replay(h);
-        controller.reassertRole(h, Role.SLAVE);
+        controller.reassertRole(h, HARole.STANDBY);
         verify(h);
     }
 
@@ -889,56 +642,41 @@ public class ControllerTest extends FloodlightTestCase {
      */
     @Test
     public void testSetRole() throws Exception {
-        doSetUp(Role.SLAVE);
+    	doSetUp(HARole.STANDBY);
         RoleInfo info = controller.getRoleInfo();
-        assertEquals(Role.SLAVE.toString(), info.getRole());
-        assertEquals(Role.SLAVE, controller.getRole());
+        assertEquals(HARole.STANDBY, info.getRole());
+        assertEquals(HARole.STANDBY, controller.getRole());
 
 
-        OFChannelHandler h = createMock(OFChannelHandler.class);
-
-        // Add the channel handler. The controller should call sendRoleRequest
-        h.sendRoleRequest(Role.SLAVE);
-        expectLastCall().once();
-        replay(h);
-        controller.addSwitchChannelAndSendInitialRole(h);
-        verify(h);
+        OFSwitchHandshakeHandler h = createMock(OFSwitchHandshakeHandler.class);
 
         // Reassert the role.
         reset(h);
-        h.sendRoleRequestIfNotPending(Role.SLAVE);
+        h.sendRoleRequestIfNotPending(OFControllerRole.ROLE_SLAVE);
         replay(h);
-        controller.reassertRole(h, Role.SLAVE);
+        controller.reassertRole(h, HARole.STANDBY);
         verify(h);
 
         // reassert a different role: no-op
         reset(h);
         replay(h);
-        controller.reassertRole(h, Role.MASTER);
+        controller.reassertRole(h, HARole.ACTIVE);
         verify(h);
 
-        // Change role to MASTER
-        reset(h);
-        h.sendRoleRequest(Role.MASTER);
-        expectLastCall().once();
         IHAListener listener = createMock(IHAListener.class);
         expect(listener.getName()).andReturn("foo").anyTimes();
         setupListenerOrdering(listener);
-        listener.transitionToMaster();
+        listener.transitionToActive();
         expectLastCall().once();
         replay(listener);
-        replay(h);
         controller.addHAListener(listener);
-        controller.setRole(Role.MASTER, "FooBar");
+        controller.setRole(HARole.ACTIVE, "FooBar");
         controller.processUpdateQueueForTesting();
-        verify(h);
         verify(listener);
         info = controller.getRoleInfo();
-        assertEquals(Role.MASTER.toString(), info.getRole());
+        assertEquals(HARole.ACTIVE, info.getRole());
         assertEquals("FooBar", info.getRoleChangeDescription());
-        assertEquals(Role.MASTER, controller.getRole());
-
-
+        assertEquals(HARole.ACTIVE, controller.getRole());
     }
 
     /** Test other setRole cases: re-setting role to the current role,
@@ -946,21 +684,7 @@ public class ControllerTest extends FloodlightTestCase {
      */
     @Test
     public void testSetRoleOthercases() throws Exception {
-        doSetUp(Role.SLAVE);
-
-        OFChannelHandler h = createMock(OFChannelHandler.class);
-
-        // Add the channel handler. The controller should call sendRoleRequest
-        h.sendRoleRequest(Role.SLAVE);
-        expectLastCall().once();
-        replay(h);
-        controller.addSwitchChannelAndSendInitialRole(h);
-        verify(h);
-
-        // remove the channel. Nothing should
-        reset(h);
-        replay(h);
-        controller.removeSwitchChannel(h);
+    	doSetUp(HARole.STANDBY);
 
         // Create and add the HA listener
         IHAListener listener = createMock(IHAListener.class);
@@ -970,30 +694,17 @@ public class ControllerTest extends FloodlightTestCase {
         controller.addHAListener(listener);
 
         // Set role to slave again. Nothing should happen
-        controller.setRole(Role.SLAVE, "FooBar");
+        controller.setRole(HARole.STANDBY, "FooBar");
         controller.processUpdateQueueForTesting();
         verify(listener);
 
         reset(listener);
-        listener.transitionToMaster();
+        expect(listener.getName()).andReturn("foo").anyTimes();
+        listener.transitionToActive();
         expectLastCall().once();
         replay(listener);
-
-        // set role to equal. Should set to master internally
-        controller.setRole(Role.EQUAL, "ToEqual");
-        controller.processUpdateQueueForTesting();
-        verify(listener);
-        RoleInfo info = controller.getRoleInfo();
-        assertEquals(Role.MASTER.toString(), info.getRole());
-        assertEquals("ToEqual", info.getRoleChangeDescription());
-        assertEquals(Role.MASTER, controller.getRole());
-
-
-        verify(h); // no calls should have happened on h
     }
 
-
-
     @Test
     public void testSetRoleNPE() {
         try {
@@ -1004,1432 +715,11 @@ public class ControllerTest extends FloodlightTestCase {
             //exptected
         }
         try {
-            controller.setRole(Role.MASTER, null);
+            controller.setRole(HARole.ACTIVE, null);
             fail("Should have thrown an Exception");
         }
         catch (NullPointerException e) {
             //exptected
         }
     }
-
-
-
-
-
-    @Test
-    /**
-     * Test switchActivated for a new switch, i.e., a switch that was not
-     * previously known to the controller cluser. We expect that all
-     * flow mods are cleared and we expect a switchAdded
-     */
-    public void testNewSwitchActivated() throws Exception {
-        // We set AlwaysClearFlowsOnSwActivate to false but we still
-        // expect a clearAllFlowMods() because the AlwaysClearFlowsOnSwActivate
-        // is only relevant if a switch that was previously known is activated!!
-        controller.setAlwaysClearFlowsOnSwActivate(false);
-
-        IOFSwitch sw = createMock(IOFSwitch.class);
-        setupSwitchForAddSwitch(sw, 0L, null, null);
-        sw.clearAllFlowMods();
-        expectLastCall().once();
-
-        // strict mock. Order of events matters!
-        IOFSwitchListener listener = createStrictMock(IOFSwitchListener.class);
-        listener.switchAdded(0L);
-        expectLastCall().once();
-        listener.switchActivated(0L);
-        expectLastCall().once();
-        replay(listener);
-        controller.addOFSwitchListener(listener);
-
-        replay(sw);
-        controller.switchActivated(sw);
-        verify(sw);
-        assertEquals(sw, controller.getSwitch(0L));
-        controller.processUpdateQueueForTesting();
-        verify(listener);
-
-        SwitchSyncRepresentation storedSwitch = storeClient.getValue(0L);
-        assertEquals(createOFFeaturesReply(), storedSwitch.getFeaturesReply());
-        assertEquals(createOFDescriptionStatistics(),
-                     storedSwitch.getDescription());
-    }
-
-    /**
-     * Test switchActivated for a new switch while in slave: a no-op
-     */
-    @Test
-    public void testNewSwitchActivatedWhileSlave() throws Exception {
-        doSetUp(Role.SLAVE);
-        IOFSwitch sw = createMock(IOFSwitch.class);
-
-        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
-        controller.addOFSwitchListener(listener);
-
-        replay(sw, listener); // nothing recorded
-        controller.switchActivated(sw);
-        verify(sw);
-        verify(listener);
-    }
-
-
-    /**
-     * Create and activate a switch, either completely new or reconnected
-     * The mocked switch instance will be returned. It wil be reset.
-     */
-    private IOFSwitch doActivateSwitchInt(long dpid,
-                                          OFDescriptionStatistics desc,
-                                          OFFeaturesReply featuresReply,
-                                          boolean clearFlows)
-                                          throws Exception {
-        controller.setAlwaysClearFlowsOnSwActivate(true);
-
-        IOFSwitch sw = createMock(IOFSwitch.class);
-        if (featuresReply == null) {
-            featuresReply = createOFFeaturesReply();
-            featuresReply.setDatapathId(dpid);
-        }
-        if (desc == null) {
-            desc = createOFDescriptionStatistics();
-        }
-        setupSwitchForAddSwitch(sw, dpid, desc, featuresReply);
-        if (clearFlows) {
-            sw.clearAllFlowMods();
-            expectLastCall().once();
-        }
-
-        replay(sw);
-        controller.switchActivated(sw);
-        verify(sw);
-        assertEquals(sw, controller.getSwitch(dpid));
-        // drain updates and ignore
-        controller.processUpdateQueueForTesting();
-
-        SwitchSyncRepresentation storedSwitch = storeClient.getValue(dpid);
-        assertEquals(featuresReply, storedSwitch.getFeaturesReply());
-        assertEquals(desc, storedSwitch.getDescription());
-        reset(sw);
-        return sw;
-    }
-
-    /**
-     * Create and activate a new switch with the given dpid, features reply
-     * and description. If description and/or features reply are null we'll
-     * allocate the default one
-     * The mocked switch instance will be returned. It wil be reset.
-     */
-    private IOFSwitch doActivateNewSwitch(long dpid,
-                                          OFDescriptionStatistics desc,
-                                          OFFeaturesReply featuresReply)
-                                          throws Exception {
-        return doActivateSwitchInt(dpid, desc, featuresReply, true);
-    }
-
-    /**
-     * Create and activate a switch that's just been disconnected.
-     * The mocked switch instance will be returned. It wil be reset.
-     */
-    private IOFSwitch doActivateOldSwitch(long dpid,
-                                          OFDescriptionStatistics desc,
-                                          OFFeaturesReply featuresReply)
-                                          throws Exception {
-        return doActivateSwitchInt(dpid, desc, featuresReply, false);
-    }
-
-
-    /**
-     * Create a switch sync representation and add it to the store and
-     * notify the store listener.
-     * If the description and/or features reply are null, we'll allocate
-     * the default one
-     */
-    public void doAddSwitchToStore(long dpid,
-                                   OFDescriptionStatistics desc,
-                                   OFFeaturesReply featuresReply)
-                                   throws Exception {
-        if (featuresReply == null) {
-            featuresReply = createOFFeaturesReply();
-            featuresReply.setDatapathId(dpid);
-        }
-        if (desc == null) {
-            desc = createOFDescriptionStatistics();
-        }
-
-        SwitchSyncRepresentation ssr =
-                new SwitchSyncRepresentation(featuresReply, desc);
-        storeClient.put(dpid, ssr);
-
-        Iterator<Long> keysToNotify = Collections.singletonList(dpid).iterator();
-        controller.getStoreListener().keysModified(keysToNotify,
-                                                   UpdateType.REMOTE);
-    }
-
-    /**
-     * Remove a switch from the sync store and
-     * notify the store listener.
-     */
-    public void doRemoveSwitchFromStore(long dpid) throws Exception {
-        storeClient.delete(dpid);
-
-        Iterator<Long> keysToNotify = Collections.singletonList(dpid).iterator();
-        controller.getStoreListener().keysModified(keysToNotify,
-                                                   UpdateType.REMOTE);
-    }
-
-
-    /** (remotely) add switch to store and then remove while master. no-op */
-    @Test
-    public void testAddSwitchToStoreMaster() throws Exception {
-        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
-        controller.addOFSwitchListener(listener);
-        replay(listener);
-
-        //--------------
-        // add switch
-        doAddSwitchToStore(1L, null, null);
-        controller.processUpdateQueueForTesting();
-        IOFSwitch sw = controller.getSwitch(1L);
-        assertNull("There shouldn't be a switch", sw);
-        verify(listener);
-
-        //--------------
-        // add a real switch
-        controller.setAlwaysClearFlowsOnSwActivate(true);
-        sw = createMock(IOFSwitch.class);
-        setupSwitchForAddSwitch(sw, 1L, null, null);
-        sw.clearAllFlowMods();
-        expectLastCall().once();
-        reset(listener);
-        listener.switchAdded(1L);
-        expectLastCall().once();
-        listener.switchActivated(1L);
-        expectLastCall().once();
-        replay(listener);
-        replay(sw);
-        controller.switchActivated(sw);
-        verify(sw);
-        assertEquals(sw, controller.getSwitch(1L));
-        controller.processUpdateQueueForTesting();
-        verify(listener);
-
-        //-----------
-        // remove switch from store.
-        reset(listener);
-        replay(listener);
-        doRemoveSwitchFromStore(1L);
-        controller.processUpdateQueueForTesting();
-        verify(listener);
-        assertEquals(sw, controller.getSwitch(1L));
-    }
-
-
-    /**
-     * add switch to store then remove it again while slave.
-     * should get notification and switch should be added and then removed
-     */
-    @Test
-    public void testAddSwitchRemoveSwitchStoreSlave() throws Exception {
-        doSetUp(Role.SLAVE);
-
-        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
-        controller.addOFSwitchListener(listener);
-
-        //------
-        // Add switch
-        listener.switchAdded(1L);
-        expectLastCall().once();
-        replay(listener);
-
-        OFDescriptionStatistics desc = createOFDescriptionStatistics();
-        desc.setDatapathDescription("The Switch");
-        doAddSwitchToStore(1L, desc, null);
-        controller.processUpdateQueueForTesting();
-        verify(listener);
-
-        IOFSwitch sw = controller.getSwitch(1L);
-        assertNotNull("Switch should be present", sw);
-        assertEquals(1L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-        assertEquals("The Switch",
-                     sw.getDescriptionStatistics().getDatapathDescription());
-
-        //------
-        // remove switch
-        reset(listener);
-        listener.switchRemoved(1L);
-        replay(listener);
-        doRemoveSwitchFromStore(1L);
-        controller.processUpdateQueueForTesting();
-        verify(listener);
-        assertNull("Switch should not exist anymore", controller.getSwitch(1L));
-    }
-
-    /** Add switch to store with inconsistent DPID
-     * @throws Exception
-     */
-    @Test
-    public void testInconsistentStoreDpid() throws Exception {
-        doSetUp(Role.SLAVE);
-
-        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
-        controller.addOFSwitchListener(listener);
-        replay(listener);
-
-
-        OFFeaturesReply featuresReply = createOFFeaturesReply();
-        featuresReply.setDatapathId(42L);
-        OFDescriptionStatistics desc = createOFDescriptionStatistics();
-        SwitchSyncRepresentation ssr =
-                new SwitchSyncRepresentation(featuresReply, desc);
-        storeClient.put(1L, ssr);
-
-        Iterator<Long> keysToNotify = Collections.singletonList(1L).iterator();
-        controller.getStoreListener().keysModified(keysToNotify,
-                                                   UpdateType.REMOTE);
-        controller.processUpdateQueueForTesting();
-        verify(listener);
-
-        assertNull("Switch should not have been added",
-                   controller.getSwitch(1L));
-        assertNull("Switch should not have been added",
-                   controller.getSwitch(42L));
-    }
-
-
-    /**
-     * This test goes through the SLAVE->MASTER program flow. We'll start as
-     * SLAVE. Add switches to the store while slave, update these switches
-     * then transition to master, make most (but not all switches) "connect"
-     * We also check correct behavior of getAllSwitchDpids() and
-     * getAllSwitchMap()
-     *
-     * We also change ports to verify that we receive port changed notifications
-     * if ports are changes in the sync store or when we transition from
-     * inactive to active
-     */
-    @Test
-    public void testSwitchAddWithRoleChangeSomeReconnect() throws Exception {
-        int consolidateStoreDelayMs = 50;
-        doSetUp(Role.SLAVE);
-
-        // Add HA Listener
-        IHAListener haListener = createMock(IHAListener.class);
-        expect(haListener.getName()).andReturn("foo").anyTimes();
-        setupListenerOrdering(haListener);
-        replay(haListener);
-        controller.addHAListener(haListener);
-        verify(haListener);
-        reset(haListener);
-
-        // Add switch listener
-        IOFSwitchListener switchListener = createMock(IOFSwitchListener.class);
-        controller.addOFSwitchListener(switchListener);
-
-        // Add readyForReconcile listener
-        IReadyForReconcileListener readyForReconcileListener =
-                createMock(IReadyForReconcileListener.class);
-        controller.addReadyForReconcileListener(readyForReconcileListener);
-
-        //---------------------------------------
-        // Initialization
-        //---------------------------------------
-
-        // Switch 1
-        // no actual IOFSwitch here because we simply add features reply
-        // and desc stats to store
-        OFFeaturesReply fr1a = createOFFeaturesReply();
-        fr1a.setDatapathId(1L);
-        OFPhysicalPort p = createOFPhysicalPort("P1", 1);
-        ImmutablePort sw1p1 = ImmutablePort.fromOFPhysicalPort(p);
-        List<OFPhysicalPort> ports1a = Collections.singletonList(p);
-        fr1a.setPorts(ports1a);
-        List<ImmutablePort> ports1aImmutable =
-                ImmutablePort.immutablePortListOf(ports1a);
-        // an alternative featuers reply
-        OFFeaturesReply fr1b = createOFFeaturesReply();
-        fr1b.setDatapathId(1L);
-        p = new OFPhysicalPort();
-        p = createOFPhysicalPort("P1", 1); // same port as above
-        List<OFPhysicalPort> ports1b = new ArrayList<OFPhysicalPort>();
-        ports1b.add(p);
-        p = createOFPhysicalPort("P2", 42000);
-        ImmutablePort sw1p2 = ImmutablePort.fromOFPhysicalPort(p);
-        ports1b.add(p);
-        fr1b.setPorts(ports1b);
-        List<ImmutablePort> ports1bImmutable =
-                ImmutablePort.immutablePortListOf(ports1b);
-
-        // Switch 2
-        // no actual IOFSwitch here because we simply add features reply
-        // and desc stats to store
-        OFFeaturesReply fr2a = createOFFeaturesReply();
-        fr2a.setDatapathId(2L);
-        ImmutablePort sw2p1 = sw1p1;
-        List<OFPhysicalPort> ports2a = new ArrayList<OFPhysicalPort>(ports1a);
-        fr2a.setPorts(ports2a);
-        List<ImmutablePort> ports2aImmutable =
-                ImmutablePort.immutablePortListOf(ports2a);
-        // an alternative features reply
-        OFFeaturesReply fr2b = createOFFeaturesReply();
-        fr2b.setDatapathId(2L);
-        p = new OFPhysicalPort();
-        p = createOFPhysicalPort("P1", 2); // port number changed
-        ImmutablePort sw2p1Changed = ImmutablePort.fromOFPhysicalPort(p);
-        List<OFPhysicalPort> ports2b = Collections.singletonList(p);
-        fr2b.setPorts(ports2b);
-
-        // Switches 3 and 4 are create with default features reply and desc
-        // so nothing to do here
-
-        //---------------------------------------
-        // Adding switches to store
-        //---------------------------------------
-
-        replay(haListener); // nothing should happen to haListener
-        replay(readyForReconcileListener); // nothing should happen to
-                                           // readyForReconcileListener
-
-        // add switch1 with fr1a to store
-        reset(switchListener);
-        switchListener.switchAdded(1L);
-        expectLastCall().once();
-        replay(switchListener);
-        doAddSwitchToStore(1L, null, fr1a);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        reset(switchListener);
-
-        IOFSwitch sw = controller.getSwitch(1L);
-        assertNotNull("Switch should be present", sw);
-        assertEquals(1L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-        assertEquals(new HashSet<ImmutablePort>(ports1aImmutable),
-                     new HashSet<ImmutablePort>(sw.getPorts()));
-
-        // add switch 2 with fr2a to store
-        reset(switchListener);
-        switchListener.switchAdded(2L);
-        expectLastCall().once();
-        replay(switchListener);
-        doAddSwitchToStore(2L, null, fr2a);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        reset(switchListener);
-
-        sw = controller.getSwitch(2L);
-        assertNotNull("Switch should be present", sw);
-        assertEquals(2L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-        assertEquals(new HashSet<ImmutablePort>(ports2aImmutable),
-                     new HashSet<ImmutablePort>(sw.getPorts()));
-
-        // add switch 3 to store
-        reset(switchListener);
-        switchListener.switchAdded(3L);
-        expectLastCall().once();
-        replay(switchListener);
-        doAddSwitchToStore(3L, null, null);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        reset(switchListener);
-
-        sw = controller.getSwitch(3L);
-        assertNotNull("Switch should be present", sw);
-        assertEquals(3L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-
-        // add switch 4 to store
-        reset(switchListener);
-        switchListener.switchAdded(4L);
-        expectLastCall().once();
-        replay(switchListener);
-        doAddSwitchToStore(4L, null, null);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        reset(switchListener);
-
-        sw = controller.getSwitch(4L);
-        assertNotNull("Switch should be present", sw);
-        assertEquals(4L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-
-        // update switch 1 with fr1b
-        reset(switchListener);
-        switchListener.switchPortChanged(1L, sw1p2, PortChangeType.ADD);
-        expectLastCall().once();
-        replay(switchListener);
-        doAddSwitchToStore(1L, null, fr1b);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        reset(switchListener);
-
-        sw = controller.getSwitch(1L);
-        assertNotNull("Switch should be present", sw);
-        assertEquals(1L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-        assertEquals(new HashSet<ImmutablePort>(ports1bImmutable),
-                     new HashSet<ImmutablePort>(sw.getPorts()));
-
-        // Check getAllSwitchDpids() and getAllSwitchMap()
-        Set<Long> expectedDpids = new HashSet<Long>();
-        expectedDpids.add(1L);
-        expectedDpids.add(2L);
-        expectedDpids.add(3L);
-        expectedDpids.add(4L);
-        assertEquals(expectedDpids, controller.getAllSwitchDpids());
-        Map<Long, IOFSwitch> expectedSwitchMap = new HashMap<Long, IOFSwitch>();
-        expectedSwitchMap.put(1L, controller.getSwitch(1L));
-        expectedSwitchMap.put(2L, controller.getSwitch(2L));
-        expectedSwitchMap.put(3L, controller.getSwitch(3L));
-        expectedSwitchMap.put(4L, controller.getSwitch(4L));
-        assertEquals(expectedSwitchMap, controller.getAllSwitchMap());
-
-        verify(haListener);
-        //--------------------------------------
-        // Transition to master
-        //--------------------------------------
-        reset(haListener);
-        haListener.transitionToMaster();
-        expectLastCall().once();
-        replay(haListener);
-        controller.setConsolidateStoreTaskDelay(consolidateStoreDelayMs);
-        controller.setRole(Role.MASTER, "FooBar");
-        controller.processUpdateQueueForTesting();
-        verify(haListener);
-        reset(haListener);
-        replay(haListener);
-
-        //--------------------------------------
-        // Activate switches
-        //--------------------------------------
-
-        // Activate switch 1
-        IOFSwitch sw1 = createMock(IOFSwitch.class);
-        setupSwitchForAddSwitch(sw1, 1L, null, fr1b);
-        reset(switchListener);
-        switchListener.switchActivated(1L);
-        expectLastCall().once();
-        replay(sw1);
-        replay(switchListener);
-        controller.switchActivated(sw1);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        verify(sw1);
-
-        sw = controller.getSwitch(1L);
-        assertNotNull("Switch should be present", sw);
-        assertSame(sw1, sw);   // the mock switch should be returned
-
-        // Activate switch 2 with different features reply
-        // should get portChanged
-        // also set alwaysClearFlorModOnSwAcitvate to true;
-        controller.setAlwaysClearFlowsOnSwActivate(true);
-        IOFSwitch sw2 = createMock(IOFSwitch.class);
-        setupSwitchForAddSwitch(sw2, 2L, null, fr2b);
-        sw2.clearAllFlowMods();
-        expectLastCall().once();
-        reset(switchListener);
-        switchListener.switchActivated(2L);
-        expectLastCall().once();
-        switchListener.switchPortChanged(2L, sw2p1, PortChangeType.DELETE);
-        switchListener.switchPortChanged(2L, sw2p1Changed, PortChangeType.ADD);
-        expectLastCall().once();
-        replay(sw2);
-        replay(switchListener);
-        controller.switchActivated(sw2);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        verify(sw2);
-
-        sw = controller.getSwitch(2L);
-        assertNotNull("Switch should be present", sw);
-        assertSame(sw2, sw); // the mock switch should be returned
-
-
-        // Do not activate switch 3, but it should still be present
-        sw = controller.getSwitch(3L);
-        IOFSwitch sw3 = sw;
-        assertNotNull("Switch should be present", sw);
-        assertEquals(3L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-
-        // Do not activate switch 4, but it should still be present
-        sw = controller.getSwitch(4L);
-        IOFSwitch sw4 = sw;
-        assertNotNull("Switch should be present", sw);
-        assertEquals(4L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-
-        // Check getAllSwitchDpids() and getAllSwitchMap()
-        expectedDpids = new HashSet<Long>();
-        expectedDpids.add(1L);
-        expectedDpids.add(2L);
-        expectedDpids.add(3L);
-        expectedDpids.add(4L);
-        assertEquals(expectedDpids, controller.getAllSwitchDpids());
-        expectedSwitchMap = new HashMap<Long, IOFSwitch>();
-        expectedSwitchMap.put(1L, sw1);
-        expectedSwitchMap.put(2L, sw2);
-        expectedSwitchMap.put(3L, sw3);
-        expectedSwitchMap.put(4L, sw4);
-        assertEquals(expectedSwitchMap, controller.getAllSwitchMap());
-
-        // silently remove switch 4 from the store and notify the
-        // store listener. Since the controller is MASTER it will ignore
-        // this notification.
-        reset(switchListener);
-        replay(switchListener);
-        doRemoveSwitchFromStore(4L);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        // Switch should still be queryable
-        sw = controller.getSwitch(4L);
-        assertNotNull("Switch should be present", sw);
-        assertEquals(4L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-
-        //--------------------------------
-        // Wait for consolidateStore
-        //--------------------------------
-        verify(readyForReconcileListener);
-        reset(readyForReconcileListener);
-        readyForReconcileListener.readyForReconcile();
-        replay(readyForReconcileListener);
-        reset(switchListener);
-        switchListener.switchRemoved(3L);
-        switchListener.switchRemoved(4L);
-        replay(switchListener);
-        Thread.sleep(2*consolidateStoreDelayMs);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        verify(readyForReconcileListener);
-        reset(readyForReconcileListener);
-        replay(readyForReconcileListener);
-
-        // Verify the expected switches are all there. no more no less
-        sw = controller.getSwitch(1L);
-        assertNotNull("Switch should be present", sw);
-        assertSame(sw1, sw);   // the mock switch should be returned
-
-        sw = controller.getSwitch(2L);
-        assertNotNull("Switch should be present", sw);
-        assertSame(sw2, sw); // the mock switch should be returned
-
-        // Do not activate switch 3, but it should still be present
-        sw = controller.getSwitch(3L);
-        assertNull("Switch should NOT be present", sw);
-
-        // Check getAllSwitchDpids() and getAllSwitchMap()
-        expectedDpids = new HashSet<Long>();
-        expectedDpids.add(1L);
-        expectedDpids.add(2L);
-        assertEquals(expectedDpids, controller.getAllSwitchDpids());
-        expectedSwitchMap = new HashMap<Long, IOFSwitch>();
-        expectedSwitchMap.put(1L, sw1);
-        expectedSwitchMap.put(2L, sw2);
-        assertEquals(expectedSwitchMap, controller.getAllSwitchMap());
-
-        verify(haListener);
-        verify(readyForReconcileListener);
-    }
-
-    /**
-     * This test goes through the SLAVE->MASTER program flow. We'll start as
-     * SLAVE. Add switches to the store while slave, update these switches
-     * then transition to master, make all "connect"
-     *
-     * Supplements testSwitchAddWithRoleChangeSomeReconnect() and thus does
-     * less extensive testing. We are really only interested in verifying
-     * that we get the readyForReconciliation event before
-     * consolidateStore runs.
-     */
-    @Test
-    public void testSwitchAddWithRoleChangeAllReconnect() throws Exception {
-        int consolidateStoreDelayMs = 50;
-        doSetUp(Role.SLAVE);
-
-        // Add HA Listener
-        IHAListener haListener = createMock(IHAListener.class);
-        expect(haListener.getName()).andReturn("foo").anyTimes();
-        setupListenerOrdering(haListener);
-        replay(haListener);
-        controller.addHAListener(haListener);
-        verify(haListener);
-        reset(haListener);
-
-        // Add switch listener
-        IOFSwitchListener switchListener = createMock(IOFSwitchListener.class);
-        controller.addOFSwitchListener(switchListener);
-
-        // Add readyForReconcile listener
-        IReadyForReconcileListener readyForReconcileListener =
-                createMock(IReadyForReconcileListener.class);
-        controller.addReadyForReconcileListener(readyForReconcileListener);
-
-        //---------------------------------------
-        // Adding switches to store
-        //---------------------------------------
-
-        replay(haListener); // nothing should happen to haListener
-        replay(readyForReconcileListener); // nothing should happen to
-                                           // readyForReconcileListener
-
-        // add switch 1 to store
-        reset(switchListener);
-        switchListener.switchAdded(1L);
-        expectLastCall().once();
-        replay(switchListener);
-        doAddSwitchToStore(1L, null, null);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        reset(switchListener);
-
-        IOFSwitch sw = controller.getSwitch(1L);
-        assertNotNull("Switch should be present", sw);
-        assertEquals(1L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-
-        // add switch 2 to store
-        reset(switchListener);
-        switchListener.switchAdded(2L);
-        expectLastCall().once();
-        replay(switchListener);
-        doAddSwitchToStore(2L, null, null);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        reset(switchListener);
-
-        sw = controller.getSwitch(2L);
-        assertNotNull("Switch should be present", sw);
-        assertEquals(2L, sw.getId());
-        assertFalse("Switch should be inactive", sw.isActive());
-
-        // Check getAllSwitchDpids() and getAllSwitchMap()
-        Set<Long> expectedDpids = new HashSet<Long>();
-        expectedDpids.add(1L);
-        expectedDpids.add(2L);
-        assertEquals(expectedDpids, controller.getAllSwitchDpids());
-        Map<Long, IOFSwitch> expectedSwitchMap = new HashMap<Long, IOFSwitch>();
-        expectedSwitchMap.put(1L, controller.getSwitch(1L));
-        expectedSwitchMap.put(2L, controller.getSwitch(2L));
-        assertEquals(expectedSwitchMap, controller.getAllSwitchMap());
-
-        verify(haListener);
-        //--------------------------------------
-        // Transition to master
-        //--------------------------------------
-        reset(haListener);
-        haListener.transitionToMaster();
-        expectLastCall().once();
-        replay(haListener);
-        controller.setConsolidateStoreTaskDelay(consolidateStoreDelayMs);
-        controller.setRole(Role.MASTER, "FooBar");
-        controller.processUpdateQueueForTesting();
-        verify(haListener);
-        reset(haListener);
-        replay(haListener);
-
-        //--------------------------------------
-        // Activate switches
-        //--------------------------------------
-
-        // Activate switch 1
-        IOFSwitch sw1 = createMock(IOFSwitch.class);
-        setupSwitchForAddSwitch(sw1, 1L, null, null);
-        reset(switchListener);
-        switchListener.switchActivated(1L);
-        expectLastCall().once();
-        replay(sw1);
-        replay(switchListener);
-        controller.switchActivated(sw1);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        verify(sw1);
-
-        sw = controller.getSwitch(1L);
-        assertNotNull("Switch should be present", sw);
-        assertSame(sw1, sw);   // the mock switch should be returned
-
-        // Activate switch 2
-        // Since this is the last inactive switch to activate we should
-        // get the readyForReconcile notifiction
-        verify(readyForReconcileListener);
-        reset(readyForReconcileListener);
-        readyForReconcileListener.readyForReconcile();
-        replay(readyForReconcileListener);
-        controller.setAlwaysClearFlowsOnSwActivate(true);
-        IOFSwitch sw2 = createMock(IOFSwitch.class);
-        setupSwitchForAddSwitch(sw2, 2L, null, null);
-        sw2.clearAllFlowMods();
-        expectLastCall().once();
-        reset(switchListener);
-        switchListener.switchActivated(2L);
-        expectLastCall().once();
-        replay(sw2);
-        replay(switchListener);
-        controller.switchActivated(sw2);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        verify(sw2);
-        verify(readyForReconcileListener);
-
-
-        sw = controller.getSwitch(2L);
-        assertNotNull("Switch should be present", sw);
-        assertSame(sw2, sw); // the mock switch should be returned
-
-
-        // Check getAllSwitchDpids() and getAllSwitchMap()
-        expectedDpids = new HashSet<Long>();
-        expectedDpids.add(1L);
-        expectedDpids.add(2L);
-        assertEquals(expectedDpids, controller.getAllSwitchDpids());
-        expectedSwitchMap = new HashMap<Long, IOFSwitch>();
-        expectedSwitchMap.put(1L, sw1);
-        expectedSwitchMap.put(2L, sw2);
-        assertEquals(expectedSwitchMap, controller.getAllSwitchMap());
-
-        //--------------------------------
-        // Wait for consolidateStore: a no-op
-        //--------------------------------
-        reset(switchListener);
-        replay(switchListener);
-        reset(readyForReconcileListener);
-        replay(readyForReconcileListener);
-        Thread.sleep(2*consolidateStoreDelayMs);
-        controller.processUpdateQueueForTesting();
-        verify(switchListener);
-        verify(readyForReconcileListener);
-
-        // Verify the expected switches are all there. no more no less
-        sw = controller.getSwitch(1L);
-        assertNotNull("Switch should be present", sw);
-        assertSame(sw1, sw);   // the mock switch should be returned
-
-        sw = controller.getSwitch(2L);
-        assertNotNull("Switch should be present", sw);
-        assertSame(sw2, sw); // the mock switch should be returned
-
-        // Check getAllSwitchDpids() and getAllSwitchMap()
-        expectedDpids = new HashSet<Long>();
-        expectedDpids.add(1L);
-        expectedDpids.add(2L);
-        assertEquals(expectedDpids, controller.getAllSwitchDpids());
-        expectedSwitchMap = new HashMap<Long, IOFSwitch>();
-        expectedSwitchMap.put(1L, sw1);
-        expectedSwitchMap.put(2L, sw2);
-        assertEquals(expectedSwitchMap, controller.getAllSwitchMap());
-
-        verify(haListener);
-    }
-
-    /**
-     * Disconnect a switch. normal program flow
-     */
-    @Test
-    private void doTestSwitchConnectReconnect(boolean reconnect)
-            throws Exception {
-        IOFSwitch sw = doActivateNewSwitch(1L, null, null);
-        expect(sw.getId()).andReturn(1L).anyTimes();
-        expect(sw.getStringId()).andReturn(HexString.toHexString(1L)).anyTimes();
-        sw.cancelAllStatisticsReplies();
-        expectLastCall().once();
-        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
-        listener.switchRemoved(1L);
-        expectLastCall().once();
-        controller.addOFSwitchListener(listener);
-        replay(sw, listener);
-        controller.switchDisconnected(sw);
-        controller.processUpdateQueueForTesting();
-        verify(sw, listener);
-
-        assertNull(controller.getSwitch(1L));
-        assertNull(storeClient.getValue(1L));
-        if (reconnect) {
-            controller.removeOFSwitchListener(listener);
-            sw = doActivateOldSwitch(1L, null, null);
-        }
-    }
-
-    @Test
-    public void testSwitchDisconnected() throws Exception {
-        doTestSwitchConnectReconnect(false);
-    }
-
-    /**
-     * Disconnect a switch and reconnect, verify no clearAllFlowmods()
-     */
-    @Test
-    public void testSwitchReconnect() throws Exception {
-        doTestSwitchConnectReconnect(true);
-    }
-
-    /**
-     * Remove a nonexisting switch. should be ignored
-     */
-    @Test
-    public void testNonexistingSwitchDisconnected() throws Exception {
-        IOFSwitch sw = createMock(IOFSwitch.class);
-        expect(sw.getId()).andReturn(1L).anyTimes();
-        expect(sw.getStringId()).andReturn(HexString.toHexString(1L)).anyTimes();
-        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
-        controller.addOFSwitchListener(listener);
-        replay(sw, listener);
-        controller.switchDisconnected(sw);
-        controller.processUpdateQueueForTesting();
-        verify(sw, listener);
-
-        assertNull(controller.getSwitch(1L));
-        assertNull(storeClient.getValue(1L));
-    }
-
-    /**
-     * Try to remove a switch that's different from what's in the active
-     * switch map. Should be ignored
-     */
-    @Test
-    public void testSwitchDisconnectedOther() throws Exception {
-        IOFSwitch origSw = doActivateNewSwitch(1L, null, null);
-        // create a new mock switch
-        IOFSwitch sw = createMock(IOFSwitch.class);
-        expect(sw.getId()).andReturn(1L).anyTimes();
-        expect(sw.getStringId()).andReturn(HexString.toHexString(1L)).anyTimes();
-        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
-        controller.addOFSwitchListener(listener);
-        replay(sw, listener);
-        controller.switchDisconnected(sw);
-        controller.processUpdateQueueForTesting();
-        verify(sw, listener);
-
-        assertSame(origSw, controller.getSwitch(1L));
-        assertNotNull(storeClient.getValue(1L));
-    }
-
-
-
-    /**
-     * Try to activate a switch that's already active (which can happen if
-     * two different switches have the same DPIP or if a switch reconnects
-     * while the old TCP connection is still alive
-     */
-    @Test
-    public void testSwitchActivatedWithAlreadyActiveSwitch() throws Exception {
-        OFDescriptionStatistics oldDesc = createOFDescriptionStatistics();
-        oldDesc.setDatapathDescription("Ye Olde Switch");
-        OFDescriptionStatistics newDesc = createOFDescriptionStatistics();
-        newDesc.setDatapathDescription("The new Switch");
-        OFFeaturesReply featuresReply = createOFFeaturesReply();
-
-
-        // Setup: add a switch to the controller
-        IOFSwitch oldsw = createMock(IOFSwitch.class);
-        setupSwitchForAddSwitch(oldsw, 0L, oldDesc, featuresReply);
-        oldsw.clearAllFlowMods();
-        expectLastCall().once();
-        replay(oldsw);
-        controller.switchActivated(oldsw);
-        verify(oldsw);
-        // drain the queue, we don't care what's in it
-        controller.processUpdateQueueForTesting();
-        assertEquals(oldsw, controller.getSwitch(0L));
-
-        // Now the actual test: add a new switch with the same dpid to
-        // the controller
-        reset(oldsw);
-        expect(oldsw.getId()).andReturn(0L).anyTimes();
-        oldsw.cancelAllStatisticsReplies();
-        expectLastCall().once();
-        oldsw.disconnectOutputStream();
-        expectLastCall().once();
-
-
-        IOFSwitch newsw = createMock(IOFSwitch.class);
-        setupSwitchForAddSwitch(newsw, 0L, newDesc, featuresReply);
-        newsw.clearAllFlowMods();
-        expectLastCall().once();
-
-        // Strict mock. We need to get the removed notification before the
-        // add notification
-        IOFSwitchListener listener = createStrictMock(IOFSwitchListener.class);
-        listener.switchRemoved(0L);
-        listener.switchAdded(0L);
-        listener.switchActivated(0L);
-        replay(listener);
-        controller.addOFSwitchListener(listener);
-
-
-        replay(newsw, oldsw);
-        controller.switchActivated(newsw);
-        verify(newsw, oldsw);
-
-        assertEquals(newsw, controller.getSwitch(0L));
-        controller.processUpdateQueueForTesting();
-        verify(listener);
-    }
-
-
-
-    /**
-    * Tests that you can't remove a switch from the map returned by
-    * getSwitches() (because getSwitches should return an unmodifiable
-    * map)
-    */
-   @Test
-   public void testRemoveActiveSwitch() {
-       IOFSwitch sw = createNiceMock(IOFSwitch.class);
-       setupSwitchForAddSwitch(sw, 1L, null, null);
-       replay(sw);
-       getController().switchActivated(sw);
-       assertEquals(sw, getController().getSwitch(1L));
-       getController().getAllSwitchMap().remove(1L);
-       assertEquals(sw, getController().getSwitch(1L));
-       verify(sw);
-       // we don't care for updates. drain queue.
-       controller.processUpdateQueueForTesting();
-   }
-
-
-
-   /**
-    * Test that notifyPortChanged() results in an IOFSwitchListener
-    * update and that its arguments are passed through to
-    * the listener call
-    */
-   @Test
-   public void testNotifySwitchPoArtChanged() throws Exception {
-       long dpid = 42L;
-
-       OFFeaturesReply fr1 = createOFFeaturesReply();
-       fr1.setDatapathId(dpid);
-       OFPhysicalPort p1 = createOFPhysicalPort("Port1", 1);
-       fr1.setPorts(Collections.singletonList(p1));
-
-       OFFeaturesReply fr2 = createOFFeaturesReply();
-       fr1.setDatapathId(dpid);
-       OFPhysicalPort p2 = createOFPhysicalPort("Port1", 1);
-       p2.setAdvertisedFeatures(0x2); // just some bogus values
-       fr2.setPorts(Collections.singletonList(p2));
-
-       OFDescriptionStatistics desc = createOFDescriptionStatistics();
-
-       // activate switch
-       IOFSwitch sw = doActivateNewSwitch(dpid, desc, fr1);
-
-       // check the store
-       SwitchSyncRepresentation ssr = storeClient.getValue(dpid);
-       assertNotNull(ssr);
-       assertEquals(dpid, ssr.getDpid());
-       assertEquals(1, ssr.getPorts().size());
-       assertEquals(p1, ssr.getPorts().get(0).toOFPhysicalPort());
-
-       IOFSwitchListener listener = createMock(IOFSwitchListener.class);
-       controller.addOFSwitchListener(listener);
-       // setup switch with the new, second features reply (and thus ports)
-       setupSwitchForAddSwitch(sw, dpid, desc, fr2);
-       listener.switchPortChanged(dpid, ImmutablePort.fromOFPhysicalPort(p2),
-                                  PortChangeType.OTHER_UPDATE);
-       expectLastCall().once();
-       replay(listener);
-       replay(sw);
-       controller.notifyPortChanged(sw, ImmutablePort.fromOFPhysicalPort(p2),
-                                    PortChangeType.OTHER_UPDATE);
-       controller.processUpdateQueueForTesting();
-       verify(listener);
-       verify(sw);
-
-       // check the store
-       ssr = storeClient.getValue(dpid);
-       assertNotNull(ssr);
-       assertEquals(dpid, ssr.getDpid());
-       assertEquals(1, ssr.getPorts().size());
-       assertEquals(p2, ssr.getPorts().get(0).toOFPhysicalPort());
-   }
-
-    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(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;
-    }
-
-    /**
-     * Test notifications for controller node IP changes. This requires
-     * synchronization between the main test thread and another thread
-     * that runs Controller's main loop and takes / handles updates. We
-     * synchronize with wait(timeout) / notifyAll(). We check for the
-     * expected condition after the wait returns. However, if wait returns
-     * due to the timeout (or due to spurious awaking) and the check fails we
-     * might just not have waited long enough. Using a long enough timeout
-     * mitigates this but we cannot get rid of the fundamental "issue".
-     *
-     * @throws Exception
-     */
-    @Test
-    public void testControllerNodeIPChanges() throws Exception {
-        class DummyHAListener implements IHAListener {
-            public Map<String, String> curControllerNodeIPs;
-            public Map<String, String> addedControllerNodeIPs;
-            public Map<String, String> removedControllerNodeIPs;
-            public int nCalled;
-
-            public DummyHAListener() {
-                this.nCalled = 0;
-            }
-
-            @Override
-            public synchronized void controllerNodeIPsChanged(
-                    Map<String, String> curControllerNodeIPs,
-                    Map<String, String> addedControllerNodeIPs,
-                    Map<String, String> removedControllerNodeIPs) {
-                this.curControllerNodeIPs = curControllerNodeIPs;
-                this.addedControllerNodeIPs = addedControllerNodeIPs;
-                this.removedControllerNodeIPs = removedControllerNodeIPs;
-                this.nCalled++;
-                notifyAll();
-            }
-
-            public void do_assert(int nCalled,
-                    Map<String, String> curControllerNodeIPs,
-                    Map<String, String> addedControllerNodeIPs,
-                    Map<String, String> removedControllerNodeIPs) {
-                assertEquals("nCalled is not as expected", nCalled, this.nCalled);
-                assertEquals("curControllerNodeIPs is not as expected",
-                        curControllerNodeIPs, this.curControllerNodeIPs);
-                assertEquals("addedControllerNodeIPs is not as expected",
-                        addedControllerNodeIPs, this.addedControllerNodeIPs);
-                assertEquals("removedControllerNodeIPs is not as expected",
-                        removedControllerNodeIPs, this.removedControllerNodeIPs);
-
-            }
-
-            @Override
-            public String getName() {
-                return null;
-            }
-
-            @Override
-            public boolean
-                    isCallbackOrderingPrereq(HAListenerTypeMarker type,
-                                             String name) {
-                return false;
-            }
-
-            @Override
-            public boolean
-                    isCallbackOrderingPostreq(HAListenerTypeMarker type,
-                                              String name) {
-                return false;
-            }
-
-            @Override
-            public void transitionToMaster() {
-            }
-        }
-        DummyHAListener listener  = new DummyHAListener();
-        HashMap<String,String> expectedCurMap = new HashMap<String, String>();
-        HashMap<String,String> expectedAddedMap = new HashMap<String, String>();
-        HashMap<String,String> expectedRemovedMap = new HashMap<String, String>();
-
-        controller.addHAListener(listener);
-
-        synchronized(listener) {
-            // Insert a first entry
-            controller.getStorageSourceService()
-                .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
-                    getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1"));
-            expectedCurMap.clear();
-            expectedAddedMap.clear();
-            expectedRemovedMap.clear();
-            expectedCurMap.put("c1", "1.1.1.1");
-            expectedAddedMap.put("c1", "1.1.1.1");
-            controller.processUpdateQueueForTesting();
-            listener.do_assert(1, expectedCurMap, expectedAddedMap, expectedRemovedMap);
-
-            // Add an interface that we want to ignore.
-            controller.getStorageSourceService()
-                .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();
-            assertTrue("controllerNodeIPsChanged() should not have been called here",
-                    listener.nCalled == 1);
-
-            // Add another entry
-            controller.getStorageSourceService()
-                .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
-                    getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2"));
-            expectedCurMap.clear();
-            expectedAddedMap.clear();
-            expectedRemovedMap.clear();
-            expectedCurMap.put("c1", "1.1.1.1");
-            expectedCurMap.put("c2", "2.2.2.2");
-            expectedAddedMap.put("c2", "2.2.2.2");
-            controller.processUpdateQueueForTesting();
-            listener.do_assert(2, expectedCurMap, expectedAddedMap, expectedRemovedMap);
-
-
-            // Update an entry
-            controller.getStorageSourceService()
-                .updateRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
-                    "row3", getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.3"));
-            expectedCurMap.clear();
-            expectedAddedMap.clear();
-            expectedRemovedMap.clear();
-            expectedCurMap.put("c1", "1.1.1.1");
-            expectedCurMap.put("c2", "2.2.2.3");
-            expectedAddedMap.put("c2", "2.2.2.3");
-            expectedRemovedMap.put("c2", "2.2.2.2");
-            controller.processUpdateQueueForTesting();
-            listener.do_assert(3, expectedCurMap, expectedAddedMap, expectedRemovedMap);
-
-            // Delete an entry
-            controller.getStorageSourceService()
-                .deleteRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME, "row3");
-            expectedCurMap.clear();
-            expectedAddedMap.clear();
-            expectedRemovedMap.clear();
-            expectedCurMap.put("c1", "1.1.1.1");
-            expectedRemovedMap.put("c2", "2.2.2.3");
-            controller.processUpdateQueueForTesting();
-            listener.do_assert(4, expectedCurMap, expectedAddedMap, expectedRemovedMap);
-        }
-    }
-
-    @Test
-    public void testGetControllerNodeIPs() {
-        HashMap<String,String> expectedCurMap = new HashMap<String, String>();
-
-        controller.getStorageSourceService()
-            .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
-                getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1"));
-        controller.getStorageSourceService()
-            .insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
-                getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2"));
-        controller.getStorageSourceService()
-            .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");
-        assertEquals("expectedControllerNodeIPs is not as expected",
-                expectedCurMap, controller.getControllerNodeIPs());
-        // we don't care for updates. drain update queue
-        controller.processUpdateQueueForTesting();
-    }
-
-
-    /**
-     * Test the driver registry: test the bind order
-     */
-    @Test
-    public void testSwitchDriverRegistryBindOrder() {
-        IOFSwitchDriver driver1 = createMock(IOFSwitchDriver.class);
-        IOFSwitchDriver driver2 = createMock(IOFSwitchDriver.class);
-        IOFSwitchDriver driver3 = createMock(IOFSwitchDriver.class);
-        IOFSwitch returnedSwitch = null;
-        IOFSwitch mockSwitch = createMock(IOFSwitch.class);
-        controller.addOFSwitchDriver("", driver3);
-        controller.addOFSwitchDriver("test switch", driver1);
-        controller.addOFSwitchDriver("test", driver2);
-
-        replay(driver1);
-        replay(driver2);
-        replay(driver3);
-        replay(mockSwitch);
-
-        OFDescriptionStatistics desc = createOFDescriptionStatistics();
-        desc.setManufacturerDescription("test switch");
-        desc.setHardwareDescription("version 0.9");
-        reset(driver1);
-        reset(driver2);
-        reset(driver3);
-        reset(mockSwitch);
-        mockSwitch.setSwitchProperties(desc);
-        expectLastCall().once();
-        expect(driver1.getOFSwitchImpl(desc)).andReturn(mockSwitch).once();
-        replay(driver1);
-        replay(driver2);
-        replay(driver3);
-        replay(mockSwitch);
-        returnedSwitch = controller.getOFSwitchInstance(desc);
-        assertSame(mockSwitch, returnedSwitch);
-        verify(driver1);
-        verify(driver2);
-        verify(driver3);
-        verify(mockSwitch);
-
-        desc = createOFDescriptionStatistics();
-        desc.setManufacturerDescription("testFooBar");
-        desc.setHardwareDescription("version 0.9");
-        reset(driver1);
-        reset(driver2);
-        reset(driver3);
-        reset(mockSwitch);
-        mockSwitch.setSwitchProperties(desc);
-        expectLastCall().once();
-        expect(driver2.getOFSwitchImpl(desc)).andReturn(mockSwitch).once();
-        replay(driver1);
-        replay(driver2);
-        replay(driver3);
-        replay(mockSwitch);
-        returnedSwitch = controller.getOFSwitchInstance(desc);
-        assertSame(mockSwitch, returnedSwitch);
-        verify(driver1);
-        verify(driver2);
-        verify(driver3);
-        verify(mockSwitch);
-
-        desc = createOFDescriptionStatistics();
-        desc.setManufacturerDescription("FooBar");
-        desc.setHardwareDescription("version 0.9");
-        reset(driver1);
-        reset(driver2);
-        reset(driver3);
-        reset(mockSwitch);
-        mockSwitch.setSwitchProperties(desc);
-        expectLastCall().once();
-        expect(driver3.getOFSwitchImpl(desc)).andReturn(mockSwitch).once();
-        replay(driver1);
-        replay(driver2);
-        replay(driver3);
-        replay(mockSwitch);
-        returnedSwitch = controller.getOFSwitchInstance(desc);
-        assertSame(mockSwitch, returnedSwitch);
-        verify(driver1);
-        verify(driver2);
-        verify(driver3);
-        verify(mockSwitch);
-    }
-
-    /**
-     * Test SwitchDriverRegistry
-     * Test fallback to default if no switch driver is registered for a
-     * particular prefix
-     */
-    @Test
-    public void testSwitchDriverRegistryNoDriver() {
-        IOFSwitchDriver driver = createMock(IOFSwitchDriver.class);
-        IOFSwitch returnedSwitch = null;
-        IOFSwitch mockSwitch = createMock(IOFSwitch.class);
-        controller.addOFSwitchDriver("test switch", driver);
-
-        replay(driver);
-        replay(mockSwitch);
-
-        OFDescriptionStatistics desc = createOFDescriptionStatistics();
-        desc.setManufacturerDescription("test switch");
-        desc.setHardwareDescription("version 0.9");
-        reset(driver);
-        reset(mockSwitch);
-        mockSwitch.setSwitchProperties(desc);
-        expectLastCall().once();
-        expect(driver.getOFSwitchImpl(desc)).andReturn(mockSwitch).once();
-        replay(driver);
-        replay(mockSwitch);
-        returnedSwitch = controller.getOFSwitchInstance(desc);
-        assertSame(mockSwitch, returnedSwitch);
-        verify(driver);
-        verify(mockSwitch);
-
-
-        desc = createOFDescriptionStatistics();
-        desc.setManufacturerDescription("Foo Bar test switch");
-        desc.setHardwareDescription("version 0.9");
-        reset(driver);
-        reset(mockSwitch);
-        replay(driver);
-        replay(mockSwitch);
-        returnedSwitch = controller.getOFSwitchInstance(desc);
-        assertNotNull(returnedSwitch);
-        assertTrue("Returned switch should be OFSwitchImpl",
-                   returnedSwitch instanceof OFSwitchImpl);
-        assertEquals(desc, returnedSwitch.getDescriptionStatistics());
-        verify(driver);
-        verify(mockSwitch);
-    }
-
-    /**
-     *
-     */
-    @Test
-    public void testDriverRegistryExceptions() {
-        IOFSwitchDriver driver = createMock(IOFSwitchDriver.class);
-        IOFSwitchDriver driver2 = createMock(IOFSwitchDriver.class);
-        replay(driver, driver2); // no calls expected on driver
-
-        //---------------
-        // Test exception handling when registering driver
-        try {
-            controller.addOFSwitchDriver("foobar", null);
-            fail("Expected NullPointerException not thrown");
-        } catch (NullPointerException e) {
-            //expected
-        }
-
-        try {
-            controller.addOFSwitchDriver(null, driver);
-            fail("Expected NullPointerException not thrown");
-        } catch (NullPointerException e) {
-            //expected
-        }
-
-        // test that we can register each prefix only once!
-        controller.addOFSwitchDriver("foobar",  driver);
-        try {
-            controller.addOFSwitchDriver("foobar",  driver);
-            fail("Expected IllegalStateException not thrown");
-        } catch (IllegalStateException e) {
-            //expected
-        }
-
-        try {
-            controller.addOFSwitchDriver("foobar",  driver2);
-            fail("Expected IllegalStateException not thrown");
-        } catch (IllegalStateException e) {
-            //expected
-        }
-
-        OFDescriptionStatistics desc = createOFDescriptionStatistics();
-
-        desc.setDatapathDescription(null);
-        try {
-            controller.getOFSwitchInstance(desc);
-            fail("Expected NullPointerException not thrown");
-        } catch (NullPointerException e) {
-            //expected
-        }
-        desc.setHardwareDescription(null);
-        try {
-            controller.getOFSwitchInstance(desc);
-            fail("Expected NullPointerException not thrown");
-        } catch (NullPointerException e) {
-            //expected
-        }
-        desc.setManufacturerDescription(null);
-        try {
-            controller.getOFSwitchInstance(desc);
-            fail("Expected NullPointerException not thrown");
-        } catch (NullPointerException e) {
-            //expected
-        }
-        desc.setSerialNumber(null);
-        try {
-            controller.getOFSwitchInstance(desc);
-            fail("Expected NullPointerException not thrown");
-        } catch (NullPointerException e) {
-            //expected
-        }
-        desc.setSoftwareDescription(null);
-        try {
-            controller.getOFSwitchInstance(desc);
-            fail("Expected NullPointerException not thrown");
-        } catch (NullPointerException e) {
-            //expected
-        }
-        verify(driver, driver2);
-    }
-
 }
diff --git a/src/test/java/net/floodlightcontroller/core/internal/MockOFConnection.java b/src/test/java/net/floodlightcontroller/core/internal/MockOFConnection.java
new file mode 100644
index 0000000000000000000000000000000000000000..64631b78afd5cfe93e065ddac678717aec507579
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/MockOFConnection.java
@@ -0,0 +1,217 @@
+package net.floodlightcontroller.core.internal;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import java.util.Date;
+import net.floodlightcontroller.core.IOFConnectionBackend;
+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.OFStatsRequest;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFAuxId;
+
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+
+public class MockOFConnection implements IOFConnectionBackend {
+
+    private final DatapathId id;
+    private final OFAuxId auxId;
+    private Date connectedSince;
+    private boolean connected;
+    private SocketAddress localInetAddress, remoteInetAddress;
+    private OFFactory factory;
+    private final List<OFMessage> messages;
+    private final Map<Long, RequestAndFuture<?>>requests;
+    private IOFConnectionListener listener;
+
+    public MockOFConnection(DatapathId id, OFAuxId auxId){
+        this.id = id;
+        this.auxId = auxId;
+
+        this.setDefaultAddresses();
+        this.messages = new ArrayList<>();
+        this.requests = new HashMap<>();
+    }
+
+    private void setDefaultAddresses() {
+        SocketAddress socketAddress = null;
+        try {
+            byte[] addressBytes = {1, 1, 1, (byte)(this.id.getLong()%255)};
+            InetAddress inetAddress = InetAddress.getByAddress(addressBytes);
+            socketAddress = new InetSocketAddress(inetAddress, 7847);
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        this.remoteInetAddress = socketAddress;
+
+        socketAddress = null;
+        try {
+            byte[] addressBytes = {127, 0, 0, 1};
+            InetAddress inetAddress = InetAddress.getByAddress(addressBytes);
+            socketAddress = new InetSocketAddress(inetAddress, 7847);
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        this.localInetAddress = socketAddress;
+    }
+
+    @Override
+    public void write(OFMessage m) {
+        messages.add(m);
+    }
+
+    @Override
+    public void write(Iterable<OFMessage> msglist) {
+        Iterables.addAll(messages, msglist);
+    }
+
+    static class RequestAndFuture<R extends OFMessage> {
+        final OFRequest<R> request;
+        final SettableFuture<R> replyFuture;
+
+        public RequestAndFuture(OFRequest<R> request) {
+            this.request = request;
+            this.replyFuture = SettableFuture.create();
+        }
+
+        public OFRequest<R> getRequest() {
+            return request;
+        }
+
+        public SettableFuture<R> getReplyFuture() {
+            return replyFuture;
+        }
+
+    }
+
+    @Override
+    public <R extends OFMessage> ListenableFuture<R>
+            writeRequest(OFRequest<R> request) {
+        RequestAndFuture<R> raf = new RequestAndFuture<>(request);
+        messages.add(request);
+        requests.put(request.getXid(), raf);
+        return raf.getReplyFuture();
+    }
+
+    @Override
+    public <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>>
+            writeStatsRequest(OFStatsRequest<REPLY> request) {
+        return null;
+    }
+
+    public void setConnectedSince(Date connectedSince) {
+        this.connectedSince = connectedSince;
+    }
+
+    @Override
+    public Date getConnectedSince() {
+        return this.connectedSince;
+    }
+
+    @Override
+    public void flush() {
+        // no op
+    }
+
+    @Override
+    public DatapathId getDatapathId() {
+        return this.id;
+    }
+
+    @Override
+    public OFAuxId getAuxId() {
+        return this.auxId;
+    }
+
+    public void setRemoteInetAddress(SocketAddress address){
+        this.remoteInetAddress = address;
+    }
+
+    @Override
+    public SocketAddress getRemoteInetAddress() {
+        return this.remoteInetAddress;
+    }
+
+    public void setLocalInetAddress(SocketAddress address){
+        this.localInetAddress = address;
+    }
+
+    @Override
+    public SocketAddress getLocalInetAddress() {
+        return this.localInetAddress;
+    }
+
+    public void setOFFactory(OFFactory factory) {
+        this.factory = factory;
+    }
+
+    @Override
+    public OFFactory getOFFactory() {
+        return this.factory;
+    }
+
+    @Override
+    public void disconnect() {
+        this.connected = false;
+    }
+
+    @Override
+    public void cancelAllPendingRequests() {
+       // no op
+    }
+
+    @Override
+    public boolean isWritable() {
+        return true;
+    }
+
+    @Override
+    public boolean isConnected() {
+        return this.connected;
+    }
+
+    public void setConnected(boolean conection) {
+       this.connected = true;
+    }
+
+    @Override
+    public void setListener(IOFConnectionListener listener) {
+        this.listener = listener;
+    }
+
+    // for interacting with the action
+    public List<OFMessage> getMessages() {
+        return messages;
+    }
+
+    public Map<Long, RequestAndFuture<?>> getRequests() {
+        return requests;
+    }
+
+    public IOFConnectionListener getListener() {
+        return listener;
+    }
+
+    public void clearMessages() {
+        this.messages.clear();
+        this.requests.clear();
+    }
+
+    public OFMessage retrieveMessage() {
+        return this.messages.remove(0);
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/MockOFSwitchImpl.java b/src/test/java/net/floodlightcontroller/core/internal/MockOFSwitchImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..846f4f7b82ad89a557f6b30aaf0b1ddacd6f1675
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/MockOFSwitchImpl.java
@@ -0,0 +1,71 @@
+package net.floodlightcontroller.core.internal;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.easymock.EasyMock;
+import net.floodlightcontroller.core.OFSwitch;
+import org.projectfloodlight.openflow.protocol.OFCapabilities;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * A sublcass of OFSwitchImpl that contains extra setters.
+ * This class can be used for testing.
+ * @author alexreimers
+ *
+ */
+public class MockOFSwitchImpl extends OFSwitch {
+    protected Map<OFStatsType, List<OFStatsReply>> statsMap;
+
+    public MockOFSwitchImpl(MockOFConnection connection) {
+        super(connection, OFFactories.getFactory(OFVersion.OF_10),
+              EasyMock.createMock(IOFSwitchManager.class), connection.getDatapathId());
+        statsMap = new HashMap<OFStatsType, List<OFStatsReply>>();
+    }
+
+    public void setBuffers(int buffers) {
+        this.buffers = buffers;
+    }
+
+    public void setCapabilities(Set<OFCapabilities> cap) {
+        this.capabilities = cap;
+    }
+
+    public void setAttributes(Map<Object, Object> attrs) {
+        this.attributes.putAll(attrs);
+    }
+
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <REPLY extends OFStatsReply> ListenableFuture<List<REPLY>> writeStatsRequest(OFStatsRequest<REPLY> request) {
+        ListenableFuture<List<REPLY>> ofStatsFuture =
+                EasyMock.createNiceMock(ListenableFuture.class);
+
+        // We create a mock future and return info from the map
+        try {
+            OFStatsType statsType = request.getStatsType();
+            List<REPLY> replies = (List<REPLY>) statsMap.get(statsType);
+            EasyMock.expect(ofStatsFuture.get(EasyMock.anyLong(),
+                    EasyMock.anyObject(TimeUnit.class))).andReturn(replies).anyTimes();
+            EasyMock.expect(ofStatsFuture.get()).andReturn(replies).anyTimes();
+            EasyMock.replay(ofStatsFuture);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return ofStatsFuture;
+    }
+
+    public void addStatsRequest(OFStatsType type, List<OFStatsReply> reply) {
+        statsMap.put(type, reply);
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java
deleted file mode 100644
index ed01868b0035eeae062f8f8f17afa2930a3c5ed2..0000000000000000000000000000000000000000
--- a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java
+++ /dev/null
@@ -1,1419 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-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.IOFSwitch.PortChangeType;
-import net.floodlightcontroller.core.ImmutablePort;
-import net.floodlightcontroller.debugcounter.DebugCounter;
-import net.floodlightcontroller.debugcounter.IDebugCounterService;
-import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
-import net.floodlightcontroller.storage.IResultSet;
-import net.floodlightcontroller.storage.IStorageSourceService;
-import net.floodlightcontroller.threadpool.IThreadPoolService;
-import net.floodlightcontroller.util.OrderedCollection;
-import net.floodlightcontroller.util.LinkedHashSetWrapper;
-
-import org.easymock.Capture;
-import org.easymock.CaptureType;
-import org.easymock.EasyMock;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelStateEvent;
-import org.jboss.netty.channel.ExceptionEvent;
-import org.jboss.netty.channel.MessageEvent;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.openflow.protocol.OFError;
-import org.openflow.protocol.OFError.OFBadRequestCode;
-import org.openflow.protocol.OFError.OFErrorType;
-import org.openflow.protocol.OFFeaturesReply;
-import org.openflow.protocol.OFGetConfigReply;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.protocol.OFPortStatus;
-import org.openflow.protocol.OFPortStatus.OFPortReason;
-import org.openflow.protocol.OFSetConfig;
-import org.openflow.protocol.OFStatisticsReply;
-import org.openflow.protocol.OFStatisticsRequest;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.OFVendor;
-import org.openflow.protocol.factory.BasicFactory;
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
-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 static org.easymock.EasyMock.*;
-
-import static org.junit.Assert.*;
-
-
-public class OFChannelHandlerTest {
-    private static final short CORE_PRIORITY = 4242;
-    private static final short ACCESS_PRIORITY = 42;
-    private Controller controller;
-    private IThreadPoolService threadPool;
-    private IDebugCounterService debugCounterService;
-    private OFChannelHandler handler;
-    private Channel channel;
-    private ChannelHandlerContext ctx;
-    private MessageEvent messageEvent;
-    private ChannelStateEvent channelStateEvent;
-    private ChannelPipeline pipeline;
-
-
-    private Capture<ExceptionEvent> exceptionEventCapture;
-    private Capture<List<OFMessage>> writeCapture;
-
-    private OFFeaturesReply featuresReply;
-
-    private Set<Integer> seenXids = null;
-    private IStorageSourceService storageSource;
-    private IResultSet storageResultSet;
-    private IOFSwitch sw;
-
-
-
-    @Before
-    public void setUpFeaturesReply() {
-        featuresReply = (OFFeaturesReply)BasicFactory.getInstance()
-                .getMessage(OFType.FEATURES_REPLY);
-        featuresReply.setDatapathId(0x42L);
-        featuresReply.setBuffers(1);
-        featuresReply.setTables((byte)1);
-        featuresReply.setCapabilities(3);
-        featuresReply.setActions(4);
-        List<OFPhysicalPort> ports = new ArrayList<OFPhysicalPort>();
-        // A dummy port.
-        OFPhysicalPort p = new OFPhysicalPort();
-        p.setName("Eth1");
-        p.setPortNumber((short)1);
-        ports.add(p);
-        featuresReply.setPorts(ports);
-    }
-
-
-    @Before
-    public void setUp() throws Exception {
-        controller = createMock(Controller.class);
-        threadPool = createMock(IThreadPoolService.class);
-        ctx = createMock(ChannelHandlerContext.class);
-        channelStateEvent = createMock(ChannelStateEvent.class);
-        channel = createMock(Channel.class);
-        messageEvent = createMock(MessageEvent.class);
-        exceptionEventCapture = new Capture<ExceptionEvent>(CaptureType.ALL);
-        pipeline = createMock(ChannelPipeline.class);
-        writeCapture = new Capture<List<OFMessage>>(CaptureType.ALL);
-        sw = createMock(IOFSwitch.class);
-        seenXids = null;
-
-        // TODO: should mock IDebugCounterService and make sure
-        // the expected counters are updated.
-        debugCounterService = new DebugCounter();
-        Controller.Counters counters =
-                new Controller.Counters();
-        counters.createCounters(debugCounterService);
-        expect(controller.getCounters()).andReturn(counters).anyTimes();
-        replay(controller);
-        handler = new OFChannelHandler(controller);
-        verify(controller);
-        reset(controller);
-
-        resetChannel();
-
-        // thread pool is usually not called, so start empty replay
-        replay(threadPool);
-
-        // replay controller. Reset it if you need more specific behavior
-        replay(controller);
-
-        // replay switch. Reset it if you need more specific behavior
-        replay(sw);
-
-        // Mock ctx and channelStateEvent
-        expect(ctx.getChannel()).andReturn(channel).anyTimes();
-        expect(channelStateEvent.getChannel()).andReturn(channel).anyTimes();
-        replay(ctx, channelStateEvent);
-
-        /* Setup an exception event capture on the channel. Right now
-         * we only expect exception events to be send up the channel.
-         * However, it's easy to extend to other events if we need it
-         */
-        pipeline.sendUpstream(capture(exceptionEventCapture));
-        expectLastCall().anyTimes();
-        replay(pipeline);
-    }
-
-    @After
-    public void tearDown() {
-        /* ensure no exception was thrown */
-        if (exceptionEventCapture.hasCaptured()) {
-            Throwable ex = exceptionEventCapture.getValue().getCause();
-            throw new AssertionError("Unexpected exception: " +
-                       ex.getClass().getName() + "(" + ex + ")");
-        }
-        assertFalse("Unexpected messages have been captured",
-                    writeCapture.hasCaptured());
-        // verify all mocks.
-        verify(channel);
-        verify(messageEvent);
-        verify(controller);
-        verify(threadPool);
-        verify(ctx);
-        verify(channelStateEvent);
-        verify(pipeline);
-        verify(sw);
-    }
-
-    /** Reset the channel mock and set basic method call expectations */
-    void resetChannel() {
-        reset(channel);
-        expect(channel.getPipeline()).andReturn(pipeline).anyTimes();
-        expect(channel.getRemoteAddress()).andReturn(null).anyTimes();
-    }
-
-
-    /** reset, setup, and replay the messageEvent mock for the given
-     * messages
-     */
-    void setupMessageEvent(List<OFMessage> messages) {
-        reset(messageEvent);
-        expect(messageEvent.getMessage()).andReturn(messages).atLeastOnce();
-        replay(messageEvent);
-    }
-
-
-    /** reset, setup, and replay the messageEvent mock for the given
-     * messages, mock controller  send message to channel handler
-     *
-     * This method will reset, start replay on controller, and then verify
-     */
-    void sendMessageToHandlerWithControllerReset(List<OFMessage> messages)
-            throws Exception {
-        verify(controller);
-        reset(controller);
-
-        sendMessageToHandlerNoControllerReset(messages);
-    }
-
-    /** reset, setup, and replay the messageEvent mock for the given
-     * messages, mock controller  send message to channel handler
-     *
-     * This method will start replay on controller, and then verify
-     */
-    void sendMessageToHandlerNoControllerReset(List<OFMessage> messages)
-            throws Exception {
-        setupMessageEvent(messages);
-
-        // mock controller
-        controller.flushAll();
-        expectLastCall().atLeastOnce();
-        replay(controller);
-        handler.messageReceived(ctx, messageEvent);
-        verify(controller);
-    }
-
-    /**
-     * Extract the list of OFMessages that was captured by the Channel.write()
-     * capture. Will check that something was actually captured first. We'll
-     * collapse the messages from multiple writes into a single list of
-     * OFMessages.
-     * Resets the channelWriteCapture.
-     */
-    List<OFMessage> getMessagesFromCapture() {
-        List<OFMessage> msgs = new ArrayList<OFMessage>();
-
-        assertTrue("No write on channel was captured",
-                   writeCapture.hasCaptured());
-        List<List<OFMessage>> capturedVals = writeCapture.getValues();
-
-        for (List<OFMessage> oneWriteList: capturedVals)
-            msgs.addAll(oneWriteList);
-        writeCapture.reset();
-        return msgs;
-    }
-
-
-    /**
-     * Verify that the given exception event capture (as returned by
-     * getAndInitExceptionCapture) has thrown an exception of the given
-     * expectedExceptionClass.
-     * Resets the capture
-     */
-    void verifyExceptionCaptured(
-            Class<? extends Throwable> expectedExceptionClass) {
-        assertTrue("Excpected exception not thrown",
-                   exceptionEventCapture.hasCaptured());
-        Throwable caughtEx = exceptionEventCapture.getValue().getCause();
-        assertEquals(expectedExceptionClass, caughtEx.getClass());
-        exceptionEventCapture.reset();
-    }
-
-    /** make sure that the transaction ids in the given messages are
-     * not 0 and differ between each other.
-     * While it's not a defect per se if the xids are we want to ensure
-     * we use different ones for each message we send.
-     */
-    void verifyUniqueXids(List<OFMessage> msgs) {
-        if (seenXids == null)
-            seenXids = new HashSet<Integer>();
-        for (OFMessage m: msgs)  {
-            int xid = m.getXid();
-            assertTrue("Xid in messags is 0", xid != 0);
-            assertFalse("Xid " + xid + " has already been used",
-                        seenXids.contains(xid));
-            seenXids.add(xid);
-        }
-    }
-
-
-    @Test
-    public void testInitState() throws Exception {
-        // Message event needs to be list
-        expect(messageEvent.getMessage()).andReturn(null);
-        replay(channel, messageEvent);
-        handler.messageReceived(ctx, messageEvent);
-        verify(channel, messageEvent);
-        verifyExceptionCaptured(AssertionError.class);
-
-        // Message event needs to be list *of OFMessages*
-        // TODO: messageReceived can throw exceptions that don't get send
-        // back into the channel (e.g., the ClassCastException below).
-        // Do we need to care?
-        /*
-        reset(channel, messageEvent);
-        List<String> listOfWrongType = Collections.singletonList("FooBar");
-        expect(messageEvent.getMessage()).andReturn(listOfWrongType)
-                .atLeastOnce();
-        replay(channel, messageEvent);
-        handler.messageReceived(ctx, messageEvent);
-        verify(channel, messageEvent);
-        verifyExceptionCaptured(ClassCastException.class);
-        */
-
-        // We don't expect to receive /any/ messages in init state since
-        // channelConnected moves us to a different state
-        OFMessage m = BasicFactory.getInstance().getMessage(OFType.HELLO);
-        sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
-
-        verifyExceptionCaptured(SwitchStateException.class);
-        assertEquals(OFChannelHandler.ChannelState.INIT,
-                     handler.getStateForTesting());
-    }
-
-    /* Move the channel from scratch to WAIT_HELLO state */
-    @Test
-    public void moveToWaitHello() throws Exception {
-        resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).once();
-        replay(channel);
-        // replay unused mocks
-        replay(messageEvent);
-
-        handler.channelConnected(ctx, channelStateEvent);
-
-        List<OFMessage> msgs = getMessagesFromCapture();
-        assertEquals(1, msgs.size());
-        assertEquals(OFType.HELLO, msgs.get(0).getType());
-        assertEquals(OFChannelHandler.ChannelState.WAIT_HELLO,
-                     handler.getStateForTesting());
-        verifyUniqueXids(msgs);
-    }
-
-    /** Move the channel from scratch to WAIT_FEATURES_REPLY state
-     * Builds on moveToWaitHello()
-     * adds testing for WAIT_HELLO state
-     */
-    @Test
-    public void moveToWaitFeaturesReply() throws Exception {
-        moveToWaitHello();
-        resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).atLeastOnce();
-        replay(channel);
-
-        OFMessage hello = BasicFactory.getInstance().getMessage(OFType.HELLO);
-        sendMessageToHandlerWithControllerReset(Collections.singletonList(hello));
-
-        List<OFMessage> msgs = getMessagesFromCapture();
-        assertEquals(1, msgs.size());
-        assertEquals(OFType.FEATURES_REQUEST, msgs.get(0).getType());
-        verifyUniqueXids(msgs);
-
-        assertEquals(OFChannelHandler.ChannelState.WAIT_FEATURES_REPLY,
-                     handler.getStateForTesting());
-    }
-
-
-    /** Move the channel from scratch to WAIT_CONFIG_REPLY state
-     * Builds on moveToWaitFeaturesReply
-     * adds testing for WAIT_FEATURES_REPLY state
-     */
-    @Test
-    public void moveToWaitConfigReply() throws Exception {
-        moveToWaitFeaturesReply();
-        resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).atLeastOnce();
-        replay(channel);
-
-        sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(featuresReply));
-
-        List<OFMessage> msgs = getMessagesFromCapture();
-        assertEquals(3, msgs.size());
-        assertEquals(OFType.SET_CONFIG, msgs.get(0).getType());
-        OFSetConfig sc = (OFSetConfig)msgs.get(0);
-        assertEquals((short)0xffff, sc.getMissSendLength());
-        assertEquals(OFType.BARRIER_REQUEST, msgs.get(1).getType());
-        assertEquals(OFType.GET_CONFIG_REQUEST, msgs.get(2).getType());
-        verifyUniqueXids(msgs);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_CONFIG_REPLY,
-                     handler.getStateForTesting());
-    }
-
-    /** Move the channel from scratch to WAIT_DESCRIPTION_STAT_REPLY state
-     * Builds on moveToWaitConfigReply()
-     * adds testing for WAIT_CONFIG_REPLY state
-     */
-    @Test
-    public void moveToWaitDescriptionStatReply() throws Exception {
-        moveToWaitConfigReply();
-        resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).atLeastOnce();
-        replay(channel);
-
-        OFGetConfigReply cr = (OFGetConfigReply)BasicFactory.getInstance()
-                .getMessage(OFType.GET_CONFIG_REPLY);
-        cr.setMissSendLength((short)0xffff);
-
-        sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(cr));
-
-        List<OFMessage> msgs = getMessagesFromCapture();
-        assertEquals(1, msgs.size());
-        assertEquals(OFType.STATS_REQUEST, msgs.get(0).getType());
-        OFStatisticsRequest sr = (OFStatisticsRequest)msgs.get(0);
-        assertEquals(OFStatisticsType.DESC, sr.getStatisticType());
-        // no idea why an  OFStatisticsRequest even /has/ a getStatistics()
-        // methods. It really shouldn't
-        assertNull(sr.getStatistics());
-        verifyUniqueXids(msgs);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_DESCRIPTION_STAT_REPLY,
-                     handler.getStateForTesting());
-    }
-
-
-    /** A helper bean that represents the config for a particular switch in
-     * the storage source.
-     */
-    private class MockStorageSourceConfig {
-        // the dpid
-        public String dpid;
-        // true if the given dpid should be present in the storage source
-        // if false the storage source will return an empty result
-        public boolean isPresent;
-        // the value of isCoreSwitch
-        public boolean isCoreSwitch;
-    }
-    /** setup and replay a mock storage source and result set that
-     * contains the IsCoreSwitch setting
-     */
-    private void setupMockStorageSource(MockStorageSourceConfig cfg) {
-
-        storageSource = createMock(IStorageSourceService.class);
-        storageResultSet = createMock(IResultSet.class);
-
-        Iterator<IResultSet> it = null;
-
-        if (cfg.isPresent) {
-            storageResultSet.getBoolean(Controller.SWITCH_CONFIG_CORE_SWITCH);
-            expectLastCall().andReturn(cfg.isCoreSwitch).atLeastOnce();
-            it = Collections.singletonList(storageResultSet).iterator();
-        } else {
-            it = Collections.<IResultSet>emptyList().iterator();
-        }
-
-        storageResultSet.close();
-        expectLastCall().atLeastOnce();
-        expect(storageResultSet.iterator()).andReturn(it).atLeastOnce();
-        storageSource.getRow(Controller.SWITCH_CONFIG_TABLE_NAME, cfg.dpid);
-        expectLastCall().andReturn(storageResultSet).atLeastOnce();
-        replay(storageResultSet, storageSource);
-    }
-
-    private void verifyStorageSource() {
-        verify(storageSource);
-        verify(storageResultSet);
-    }
-
-    private static OFStatisticsReply createDescriptionStatsReply() {
-        OFStatisticsReply sr = (OFStatisticsReply)BasicFactory.getInstance()
-                .getMessage(OFType.STATS_REPLY);
-        sr.setStatisticType(OFStatisticsType.DESC);
-        OFDescriptionStatistics desc = new OFDescriptionStatistics();
-        desc.setDatapathDescription("Datapath Description");
-        desc.setHardwareDescription("Hardware Description");
-        desc.setManufacturerDescription("Manufacturer Description");
-        desc.setSerialNumber("Serial Number");
-        desc.setSoftwareDescription("Software Description");
-        sr.setStatistics(Collections.singletonList(desc));
-        return sr;
-    }
-
-    /**
-     * setup the expectations for the mock switch that are needed
-     * after the switch is instantiated in the WAIT_DESCRIPTION_STATS STATE
-     * Will reset the switch
-     * @throws CounterException
-     */
-    private void setupSwitchForInstantiationWithReset(String dpid)
-            throws Exception {
-        reset(sw);
-        sw.setChannel(channel);
-        expectLastCall().once();
-        sw.setFloodlightProvider(controller);
-        expectLastCall().once();
-        sw.setThreadPoolService(threadPool);
-        expectLastCall().once();
-        sw.setDebugCounterService(debugCounterService);
-        expectLastCall().once();
-        sw.setFeaturesReply(featuresReply);
-        expectLastCall().once();
-        sw.setConnected(true);
-        expectLastCall().once();
-        sw.getStringId();
-        expectLastCall().andReturn(dpid).atLeastOnce();
-        sw.isWriteThrottleEnabled();  // used for log message only
-        expectLastCall().andReturn(false).anyTimes();
-        sw.setAccessFlowPriority(ACCESS_PRIORITY);
-        expectLastCall().once();
-        sw.setCoreFlowPriority(CORE_PRIORITY);
-        expectLastCall().once();
-    }
-
-    /** Move the channel from scratch to WAIT_INITIAL_ROLE state
-     * for a switch that does not have a sub-handshake
-     * Builds on moveToWaitDescriptionStatReply()
-     * adds testing for WAIT_DESCRIPTION_STAT_REPLY state
-     * @param storageSourceConfig paramterizes the contents of the storage
-     * source (for IS_CORE_SWITCH)
-     */
-    public void doMoveToWaitInitialRole(MockStorageSourceConfig cfg)
-            throws Exception {
-        moveToWaitDescriptionStatReply();
-
-        // We do not expect a write to the channel for the role request. We add
-        // the channel to the controller and the controller would in turn
-        // call handler.sendRoleRequest(). Since we mock the controller so
-        // we won't see the handler.sendRoleRequest() call and therefore we
-        // won't see any calls on the channel.
-        resetChannel();
-        replay(channel);
-
-        // build the stats reply
-        OFStatisticsReply sr = createDescriptionStatsReply();
-        OFDescriptionStatistics desc =
-                (OFDescriptionStatistics) sr.getFirstStatistics();
-
-        setupMessageEvent(Collections.<OFMessage>singletonList(sr));
-        setupMockStorageSource(cfg);
-
-        setupSwitchForInstantiationWithReset(cfg.dpid);
-        sw.startDriverHandshake();
-        expectLastCall().once();
-        sw.isDriverHandshakeComplete();
-        expectLastCall().andReturn(true).once();
-
-        if (cfg.isPresent)
-            sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, cfg.isCoreSwitch);
-        replay(sw);
-
-        // mock controller
-        reset(controller);
-        expect(controller.getDebugCounter()).andReturn(debugCounterService)
-                .once();
-        controller.flushAll();
-        expectLastCall().once();
-        expect(controller.getThreadPoolService())
-                .andReturn(threadPool).once();
-        expect(controller.getOFSwitchInstance(eq(desc)))
-                .andReturn(sw).once();
-        expect(controller.getCoreFlowPriority())
-                .andReturn(CORE_PRIORITY).once();
-        expect(controller.getAccessFlowPriority())
-                .andReturn(ACCESS_PRIORITY).once();
-        controller.addSwitchChannelAndSendInitialRole(handler);
-        expectLastCall().once();
-        expect(controller.getStorageSourceService())
-                .andReturn(storageSource).atLeastOnce();
-        replay(controller);
-
-        // send the description stats reply
-        handler.messageReceived(ctx, messageEvent);
-
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-        verifyStorageSource();
-    }
-
-    /**
-     * Move the channel from scratch to WAIT_INITIAL_ROLE state via
-     * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
-     * Does extensive testing for the WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state
-     *
-     */
-    @Test
-    public void testSwitchDriverSubHandshake()
-            throws Exception {
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = false;
-
-        moveToWaitDescriptionStatReply();
-
-        resetChannel();
-        channel.write(capture(writeCapture));
-        expectLastCall().andReturn(null).atLeastOnce();
-        replay(channel);
-
-        // build the stats reply
-        OFStatisticsReply sr = createDescriptionStatsReply();
-        OFDescriptionStatistics desc =
-                (OFDescriptionStatistics) sr.getFirstStatistics();
-
-        setupMessageEvent(Collections.<OFMessage>singletonList(sr));
-        setupMockStorageSource(cfg);
-
-        // Start the sub-handshake. Switch will indicate that it's not
-        // complete yet
-        setupSwitchForInstantiationWithReset(cfg.dpid);
-        sw.startDriverHandshake();
-        expectLastCall().once();
-        sw.isDriverHandshakeComplete();
-        expectLastCall().andReturn(false).once();
-
-        if (cfg.isPresent)
-            sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, cfg.isCoreSwitch);
-        replay(sw);
-
-        // mock controller
-        reset(controller);
-        expect(controller.getDebugCounter()).andReturn(debugCounterService)
-                .once();
-        controller.flushAll();
-        expectLastCall().once();
-        expect(controller.getThreadPoolService())
-                .andReturn(threadPool).once();
-        expect(controller.getOFSwitchInstance(eq(desc)))
-                .andReturn(sw).once();
-        expect(controller.getCoreFlowPriority())
-                .andReturn(CORE_PRIORITY).once();
-        expect(controller.getAccessFlowPriority())
-                .andReturn(ACCESS_PRIORITY).once();
-        expect(controller.getStorageSourceService())
-                .andReturn(storageSource).atLeastOnce();
-        replay(controller);
-
-        // send the description stats reply
-        handler.messageReceived(ctx, messageEvent);
-
-        assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
-                     handler.getStateForTesting());
-        assertFalse("Unexpected message captured", writeCapture.hasCaptured());
-        verifyStorageSource();
-        verify(sw);
-
-
-        //-------------------------------------------------
-        // Send a message to the handler, it should be passed to the
-        // switch's sub-handshake handling.
-        OFMessage m = BasicFactory.getInstance().getMessage(OFType.HELLO);
-        resetToStrict(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        sw.processDriverHandshakeMessage(m);
-        expectLastCall().once();
-        expect(sw.isDriverHandshakeComplete()).andReturn(false).once();
-        replay(sw);
-
-        sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
-        assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
-                     handler.getStateForTesting());
-        assertFalse("Unexpected message captured", writeCapture.hasCaptured());
-        verify(sw);
-
-        //-------------------------------------------------
-        // Send a ECHO_REQUEST. This should be handled by the OFChannelHandler
-        // and *not* passed to switch sub-handshake
-        // TODO: should this be also passed to the switch handshake instead?
-        m = BasicFactory.getInstance().getMessage(OFType.ECHO_REQUEST);
-        m.setXid(0x042042);
-
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        replay(sw);
-        sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
-        assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
-                     handler.getStateForTesting());
-        List<OFMessage> msgs = getMessagesFromCapture();
-        assertEquals(1, msgs.size());
-        assertEquals(OFType.ECHO_REPLY, msgs.get(0).getType());
-        assertEquals(0x42042, msgs.get(0).getXid());
-        verify(sw);
-
-
-        //-------------------------------------------------
-        //-------------------------------------------------
-        // Send a message to the handler, it should be passed to the
-        // switch's sub-handshake handling. After this message the
-        // sub-handshake will be complete
-        m = BasicFactory.getInstance().getMessage(OFType.FLOW_REMOVED);
-        resetToStrict(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        sw.processDriverHandshakeMessage(m);
-        expectLastCall().once();
-        expect(sw.isDriverHandshakeComplete()).andReturn(true).once();
-        replay(sw);
-
-        verify(controller);
-        reset(controller);
-        controller.addSwitchChannelAndSendInitialRole(handler);
-        expectLastCall().once();
-        sendMessageToHandlerNoControllerReset(Collections.singletonList(m));
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-        assertFalse("Unexpected message captured", writeCapture.hasCaptured());
-        verify(sw);
-
-        //-------------------------------------------------
-
-        //-------------------------------------------------
-    }
-
-    @Test
-    /** Test WaitDescriptionReplyState. No config for switch in storage */
-    public void testWaitDescriptionReplyState1() throws Exception {
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = false;
-        doMoveToWaitInitialRole(cfg);
-    }
-
-    @Test
-    /** Test WaitDescriptionReplyState. switch is core switch */
-    public void testWaitDescriptionReplyState2() throws Exception {
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = true;
-        cfg.isCoreSwitch = true;
-        doMoveToWaitInitialRole(cfg);
-    }
-
-    @Test
-    /** Test WaitDescriptionReplyState. switch is NOT core switch */
-    public void testWaitDescriptionReplyState3() throws Exception {
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = true;
-        cfg.isCoreSwitch = true;
-        doMoveToWaitInitialRole(cfg);
-    }
-
-    /**
-     * Helper
-     * Verify that the given OFMessage is a correct Nicira RoleRequest message
-     * for the given role using the given xid.
-     */
-    private void verifyRoleRequest(OFMessage m,
-                                   int expectedXid,
-                                   Role expectedRole) {
-        assertEquals(OFType.VENDOR, m.getType());
-        OFVendor vendorMsg = (OFVendor)m;
-        assertEquals(expectedXid, vendorMsg.getXid());
-        assertEquals(OFNiciraVendorData.NX_VENDOR_ID, vendorMsg.getVendor());
-        assertTrue("Vendor data is not an instance of OFRoleRequestVendorData"
-                   + " its class is: " + vendorMsg.getVendorData().getClass().getName(),
-                   vendorMsg.getVendorData() instanceof OFRoleRequestVendorData);
-        OFRoleRequestVendorData requestData =
-                (OFRoleRequestVendorData)vendorMsg.getVendorData();
-        assertEquals(expectedRole.toNxRole(), requestData.getRole());
-    }
-
-    /**
-     * Setup the mock switch and write capture for a role request, set the
-     * role and verify mocks.
-     * @param supportsNxRole whether the switch supports role request messages
-     * to setup the attribute. This must be null (don't yet know if roles
-     * supported: send to check) or true.
-     * @param xid The xid to use in the role request
-     * @param role The role to send
-     * @throws IOException
-     */
-    private void setupSwitchSendRoleRequestAndVerify(Boolean supportsNxRole,
-                                           int xid,
-                                           Role role) throws IOException {
-        assertTrue("This internal test helper method most not be called " +
-                   "with supportsNxRole==false. Test setup broken",
-                   supportsNxRole == null || supportsNxRole == true);
-        reset(sw);
-        expect(sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
-                .andReturn(supportsNxRole).atLeastOnce();
-        expect(sw.getNextTransactionId()).andReturn(xid).once();
-        sw.write(capture(writeCapture), EasyMock.<FloodlightContext>anyObject());
-        expectLastCall().anyTimes();
-        replay(sw);
-
-        handler.sendRoleRequest(role);
-
-        List<OFMessage> msgs = getMessagesFromCapture();
-        assertEquals(1, msgs.size());
-        verifyRoleRequest(msgs.get(0), xid, role);
-        verify(sw);
-    }
-
-    /**
-     * Setup the mock switch for a role change request where the switch
-     * does not support roles.
-     *
-     * Needs to verify and reset the controller since we need to set
-     * an expectation
-     */
-    private void setupSwitchRoleChangeUnsupported(int xid,
-                                                  Role role) {
-        boolean supportsNxRole = false;
-        reset(sw);
-        expect(sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
-                .andReturn(supportsNxRole).atLeastOnce();
-        // TODO: hmmm. While it's not incorrect that we set the attribute
-        // again it looks odd. Maybe change
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, supportsNxRole);
-        expectLastCall().anyTimes();
-        sw.setHARole(role);
-        expectLastCall().once();
-        if (role == Role.SLAVE) {
-            sw.disconnectOutputStream();
-            expectLastCall().once();
-        } else {
-            verify(controller);
-            reset(controller);
-            controller.switchActivated(sw);
-            replay(controller);
-        }
-        replay(sw);
-
-        handler.sendRoleRequest(role);
-
-        verify(sw);
-    }
-
-    /** Return a Nicira RoleReply message for the given role */
-    private OFMessage getRoleReply(int xid, Role role) {
-        OFVendor vm = (OFVendor)BasicFactory.getInstance()
-                .getMessage(OFType.VENDOR);
-        vm.setXid(xid);
-        vm.setVendor(OFNiciraVendorData.NX_VENDOR_ID);
-        OFRoleReplyVendorData replyData = new OFRoleReplyVendorData();
-        replyData.setRole(role.toNxRole());
-        vm.setVendorData(replyData);
-        return vm;
-    }
-
-    /** Return an OFError of the given type with the given xid */
-    private OFMessage getErrorMessage(OFErrorType type,
-                                      int i,
-                                      int xid) {
-        OFError e = (OFError) BasicFactory.getInstance()
-                .getMessage(OFType.ERROR);
-        e.setErrorType(type);
-        e.setErrorCode((short)i);
-        e.setXid(xid);
-        return e;
-    }
-
-
-    /** Move the channel from scratch to MASTER state
-     * Builds on doMoveToWaitInitialRole()
-     * adds testing for WAIT_INITAL_ROLE state
-     *
-     * This method tests only the simple case that the switch supports roles
-     * and transitions to MASTER
-     */
-    @Test
-    public void testInitialMoveToMasterWithRole() throws Exception {
-        int xid = 42;
-        // first, move us to WAIT_INITIAL_ROLE_STATE
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = false;
-        doMoveToWaitInitialRole(cfg);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // Set the role
-        setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // prepare mocks and inject the role reply message
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-               .andReturn(false).anyTimes();
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
-        expectLastCall().once();
-        sw.setHARole(Role.MASTER);
-        expectLastCall().once();
-        replay(sw);
-
-        verify(controller);
-        reset(controller);
-        controller.switchActivated(sw);
-        expectLastCall().once();
-        OFMessage reply = getRoleReply(xid, Role.MASTER);
-        // sendMessageToHandler will verify and rest controller mock
-        sendMessageToHandlerNoControllerReset(Collections.singletonList(reply));
-
-        assertEquals(OFChannelHandler.ChannelState.MASTER,
-                     handler.getStateForTesting());
-    }
-
-    /** Move the channel from scratch to SLAVE state
-     * Builds on doMoveToWaitInitialRole()
-     * adds testing for WAIT_INITAL_ROLE state
-     *
-     * This method tests only the simple case that the switch supports roles
-     * and transitions to SLAVE
-     */
-    @Test
-    public void testInitialMoveToSlaveWithRole() throws Exception {
-        int xid = 42;
-        // first, move us to WAIT_INITIAL_ROLE_STATE
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = false;
-        doMoveToWaitInitialRole(cfg);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // Set the role
-        setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // prepare mocks and inject the role reply message
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
-        expectLastCall().once();
-        sw.setHARole(Role.SLAVE);
-        expectLastCall().once();
-        replay(sw);
-
-        verify(controller);
-        reset(controller);
-        controller.switchDeactivated(sw);
-        expectLastCall().once();
-        OFMessage reply = getRoleReply(xid, Role.SLAVE);
-        // sendMessageToHandler will verify and rest controller mock
-        sendMessageToHandlerNoControllerReset(Collections.singletonList(reply));
-
-        assertEquals(OFChannelHandler.ChannelState.SLAVE,
-                     handler.getStateForTesting());
-    }
-
-    /** Move the channel from scratch to MASTER state
-     * Builds on doMoveToWaitInitialRole()
-     * adds testing for WAIT_INITAL_ROLE state
-     *
-     * This method tests the case that the switch does NOT support roles.
-     * The channel handler still needs to send the initial request to find
-     * out that whether the switch supports roles.
-     */
-    @Test
-    public void testInitialMoveToMasterNoRole() throws Exception {
-        int xid = 43;
-        // first, move us to WAIT_INITIAL_ROLE_STATE
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = false;
-        doMoveToWaitInitialRole(cfg);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // Set the role
-        setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // prepare mocks and inject the role reply message
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
-        expectLastCall().once();
-        sw.setHARole(Role.MASTER);
-        expectLastCall().once();
-        replay(sw);
-
-        // FIXME: shouldn't use ordinal(), but OFError is broken
-
-        // Error with incorrect xid and type. Should be ignored.
-        OFMessage err = getErrorMessage(OFErrorType.OFPET_BAD_ACTION,
-                                        0,
-                                        xid+1);
-        // sendMessageToHandler will verify and rest controller mock
-        sendMessageToHandlerWithControllerReset(Collections.singletonList(err));
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // Error with correct xid. Should trigger state transition
-        err = getErrorMessage(OFErrorType.OFPET_BAD_REQUEST,
-                              OFError.OFBadRequestCode.OFPBRC_BAD_VENDOR.ordinal(),
-                              xid);
-        verify(controller);
-        reset(controller);
-        controller.switchActivated(sw);
-        expectLastCall().once();
-        // sendMessageToHandler will verify and rest controller mock
-        sendMessageToHandlerNoControllerReset(Collections.singletonList(err));
-
-        assertEquals(OFChannelHandler.ChannelState.MASTER,
-                     handler.getStateForTesting());
-
-    }
-
-    /** Move the channel from scratch to MASTER state
-     * Builds on doMoveToWaitInitialRole()
-     * adds testing for WAIT_INITAL_ROLE state
-     *
-     * We let the initial role request time out. Role support should be
-     * disabled but the switch should be activated.
-     */
-    @Test
-    public void testInitialMoveToMasterTimeout() throws Exception {
-        int timeout = 50;
-        handler.useRoleChangerWithOtherTimeoutForTesting(timeout);
-        int xid = 4343;
-
-        // first, move us to WAIT_INITIAL_ROLE_STATE
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = false;
-        doMoveToWaitInitialRole(cfg);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // Set the role
-        setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // prepare mocks and inject the role reply message
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
-        expectLastCall().once();
-        sw.setHARole(Role.MASTER);
-        expectLastCall().once();
-        replay(sw);
-
-        OFMessage m = BasicFactory.getInstance().getMessage(OFType.ECHO_REPLY);
-
-        Thread.sleep(timeout+5);
-
-        verify(controller);
-        reset(controller);
-        controller.switchActivated(sw);
-        expectLastCall().once();
-        sendMessageToHandlerNoControllerReset(Collections.singletonList(m));
-
-        assertEquals(OFChannelHandler.ChannelState.MASTER,
-                     handler.getStateForTesting());
-
-    }
-
-
-    /** Move the channel from scratch to SLAVE state
-     * Builds on doMoveToWaitInitialRole()
-     * adds testing for WAIT_INITAL_ROLE state
-     *
-     * This method tests the case that the switch does NOT support roles.
-     * The channel handler still needs to send the initial request to find
-     * out that whether the switch supports roles.
-     *
-     */
-    @Test
-    public void testInitialMoveToSlaveNoRole() throws Exception {
-        int xid = 44;
-        // first, move us to WAIT_INITIAL_ROLE_STATE
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = false;
-        doMoveToWaitInitialRole(cfg);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // Set the role
-        setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // prepare mocks and inject the role reply message
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
-        expectLastCall().once();
-        sw.setHARole(Role.SLAVE);
-        expectLastCall().once();
-        sw.disconnectOutputStream(); // Make sure we disconnect
-        expectLastCall().once();
-        replay(sw);
-
-
-        // FIXME: shouldn't use ordinal(), but OFError is broken
-
-        // Error with incorrect xid and type. Should be ignored.
-        OFMessage err = getErrorMessage(OFErrorType.OFPET_BAD_ACTION,
-                                        0,
-                                        xid+1);
-        // sendMessageToHandler will verify and rest controller mock
-        sendMessageToHandlerWithControllerReset(Collections.singletonList(err));
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // Error with correct xid. Should trigger state transition
-        err = getErrorMessage(OFErrorType.OFPET_BAD_REQUEST,
-                              OFError.OFBadRequestCode.OFPBRC_BAD_VENDOR.ordinal(),
-                              xid);
-        // sendMessageToHandler will verify and rest controller mock
-        sendMessageToHandlerWithControllerReset(Collections.singletonList(err));
-    }
-
-
-    /** Move the channel from scratch to SLAVE state
-     * Builds on doMoveToWaitInitialRole()
-     * adds testing for WAIT_INITAL_ROLE state
-     *
-     * We let the initial role request time out. The switch should be
-     * disconnected
-     */
-    @Test
-    public void testInitialMoveToSlaveTimeout() throws Exception {
-        int timeout = 50;
-        handler.useRoleChangerWithOtherTimeoutForTesting(timeout);
-        int xid = 4444;
-
-        // first, move us to WAIT_INITIAL_ROLE_STATE
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = false;
-        doMoveToWaitInitialRole(cfg);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // Set the role
-        setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // prepare mocks and inject the role reply message
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
-        expectLastCall().once();
-        sw.setHARole(Role.SLAVE);
-        expectLastCall().once();
-        sw.disconnectOutputStream(); // Make sure we disconnect
-        expectLastCall().once();
-        replay(sw);
-
-        OFMessage m = BasicFactory.getInstance().getMessage(OFType.ECHO_REPLY);
-
-        Thread.sleep(timeout+5);
-
-        sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
-    }
-
-
-    /** Move channel from scratch to WAIT_INITIAL_STATE, then MASTER,
-     * then SLAVE for cases where the switch does not support roles.
-     * I.e., the final SLAVE transition should disconnect the switch.
-     */
-    @Test
-    public void testNoRoleInitialToMasterToSlave() throws Exception {
-        int xid = 46;
-        // First, lets move the state to MASTER without role support
-        testInitialMoveToMasterNoRole();
-        assertEquals(OFChannelHandler.ChannelState.MASTER,
-                     handler.getStateForTesting());
-
-        // try to set master role again. should be a no-op
-        setupSwitchRoleChangeUnsupported(xid, Role.MASTER);
-        assertEquals(OFChannelHandler.ChannelState.MASTER,
-                     handler.getStateForTesting());
-
-
-        setupSwitchRoleChangeUnsupported(xid, Role.SLAVE);
-        assertEquals(OFChannelHandler.ChannelState.SLAVE,
-                     handler.getStateForTesting());
-
-    }
-
-    /** Move the channel to MASTER state
-     * Expects that the channel is in MASTER or SLAVE state.
-     *
-     */
-    public void changeRoleToMasterWithRequest() throws Exception {
-        int xid = 4242;
-
-        assertTrue("This method can only be called when handler is in " +
-                   "MASTER or SLAVE role", handler.isHandshakeComplete());
-
-        // Set the role
-        setupSwitchSendRoleRequestAndVerify(true, xid, Role.MASTER);
-
-        // prepare mocks and inject the role reply message
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
-        expectLastCall().once();
-        sw.setHARole(Role.MASTER);
-        expectLastCall().once();
-        replay(sw);
-
-        verify(controller);
-        reset(controller);
-        controller.switchActivated(sw);
-        expectLastCall().once();
-        OFMessage reply = getRoleReply(xid, Role.MASTER);
-        // sendMessageToHandler will verify and rest controller mock
-        sendMessageToHandlerNoControllerReset(Collections.singletonList(reply));
-
-        assertEquals(OFChannelHandler.ChannelState.MASTER,
-                     handler.getStateForTesting());
-    }
-
-    /** Move the channel to SLAVE state
-     * Expects that the channel is in MASTER or SLAVE state.
-     *
-     */
-    public void changeRoleToSlaveWithRequest() throws Exception {
-        int xid = 2323;
-
-        assertTrue("This method can only be called when handler is in " +
-                   "MASTER or SLAVE role", handler.isHandshakeComplete());
-
-        // Set the role
-        setupSwitchSendRoleRequestAndVerify(true, xid, Role.SLAVE);
-
-        // prepare mocks and inject the role reply message
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
-        expectLastCall().once();
-        sw.setHARole(Role.SLAVE);
-        expectLastCall().once();
-        replay(sw);
-
-        verify(controller);
-        reset(controller);
-        controller.switchDeactivated(sw);
-        expectLastCall().once();
-        OFMessage reply = getRoleReply(xid, Role.SLAVE);
-        // sendMessageToHandler will verify and rest controller mock
-        sendMessageToHandlerNoControllerReset(Collections.singletonList(reply));
-
-        assertEquals(OFChannelHandler.ChannelState.SLAVE,
-                     handler.getStateForTesting());
-    }
-
-    @Test
-    public void testMultiRoleChange1() throws Exception {
-        testInitialMoveToMasterWithRole();
-        changeRoleToMasterWithRequest();
-        changeRoleToSlaveWithRequest();
-        changeRoleToSlaveWithRequest();
-        changeRoleToMasterWithRequest();
-        changeRoleToSlaveWithRequest();
-    }
-
-    @Test
-    public void testMultiRoleChange2() throws Exception {
-        testInitialMoveToSlaveWithRole();
-        changeRoleToMasterWithRequest();
-        changeRoleToSlaveWithRequest();
-        changeRoleToSlaveWithRequest();
-        changeRoleToMasterWithRequest();
-        changeRoleToSlaveWithRequest();
-    }
-
-    /** Start from scratch and reply with an unexpected error to the role
-     * change request
-     * Builds on doMoveToWaitInitialRole()
-     * adds testing for WAIT_INITAL_ROLE state
-     */
-    @Test
-    public void testInitialRoleChangeOtherError() throws Exception {
-        int xid = 4343;
-        // first, move us to WAIT_INITIAL_ROLE_STATE
-        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
-        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
-        cfg.isPresent = false;
-        doMoveToWaitInitialRole(cfg);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-        // Set the role
-        setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
-        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
-                     handler.getStateForTesting());
-
-
-        // FIXME: shouldn't use ordinal(), but OFError is broken
-
-        OFMessage err = getErrorMessage(OFErrorType.OFPET_BAD_ACTION,
-                                        0,
-                                        xid);
-        verify(sw);
-        reset(sw);
-        expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                .andReturn(false).anyTimes();
-        replay(sw);
-        sendMessageToHandlerWithControllerReset(Collections.singletonList(err));
-
-        verifyExceptionCaptured(SwitchStateException.class);
-    }
-
-    /**
-     * Test dispatch of messages while in MASTER role
-     */
-    @Test
-    public void testMessageDispatchMaster() throws Exception {
-        testInitialMoveToMasterWithRole();
-
-        // Send packet in. expect dispatch
-        OFPacketIn pi = (OFPacketIn)
-                BasicFactory.getInstance().getMessage(OFType.PACKET_IN);
-        reset(controller);
-        controller.handleMessage(sw, pi, null);
-        expectLastCall().once();
-        sendMessageToHandlerNoControllerReset(
-               Collections.<OFMessage>singletonList(pi));
-        verify(controller);
-        // TODO: many more to go
-    }
-
-    /**
-     * Test port status message handling while MASTER
-     *
-     */
-    @Test
-    public void testPortStatusMessageMaster() throws Exception {
-        long dpid = featuresReply.getDatapathId();
-        testInitialMoveToMasterWithRole();
-
-        OFPhysicalPort p = new OFPhysicalPort();
-        p.setName("Port1");
-        p.setPortNumber((short)1);
-        OFPortStatus ps = (OFPortStatus)
-                BasicFactory.getInstance().getMessage(OFType.PORT_STATUS);
-        ps.setDesc(p);
-
-        // The events we expect sw.handlePortStatus to return
-        // We'll just use the same list for all valid OFPortReasons and add
-        // arbitrary events for arbitrary ports that are not necessarily
-        // related to the port status message. Our goal
-        // here is not to return the correct set of events but the make sure
-        // that a) sw.handlePortStatus is called
-        //      b) the list of events sw.handlePortStatus returns is sent
-        //         as IOFSwitchListener notifications.
-        OrderedCollection<PortChangeEvent> events =
-                new LinkedHashSetWrapper<PortChangeEvent>();
-        ImmutablePort p1 = ImmutablePort.create("eth1", (short)1);
-        ImmutablePort p2 = ImmutablePort.create("eth2", (short)2);
-        ImmutablePort p3 = ImmutablePort.create("eth3", (short)3);
-        ImmutablePort p4 = ImmutablePort.create("eth4", (short)4);
-        ImmutablePort p5 = ImmutablePort.create("eth5", (short)5);
-        events.add(new PortChangeEvent(p1, PortChangeType.ADD));
-        events.add(new PortChangeEvent(p2, PortChangeType.DELETE));
-        events.add(new PortChangeEvent(p3, PortChangeType.UP));
-        events.add(new PortChangeEvent(p4, PortChangeType.DOWN));
-        events.add(new PortChangeEvent(p5, PortChangeType.OTHER_UPDATE));
-
-
-        for (OFPortReason reason: OFPortReason.values()) {
-            ps.setReason(reason.getReasonCode());
-
-            reset(sw);
-            expect(sw.inputThrottled(anyObject(OFMessage.class)))
-                    .andReturn(false).anyTimes();
-            expect(sw.getId()).andReturn(dpid).anyTimes();
-
-            expect(sw.processOFPortStatus(ps)).andReturn(events).once();
-            replay(sw);
-
-            reset(controller);
-            controller.notifyPortChanged(sw, p1, PortChangeType.ADD);
-            controller.notifyPortChanged(sw, p2, PortChangeType.DELETE);
-            controller.notifyPortChanged(sw, p3, PortChangeType.UP);
-            controller.notifyPortChanged(sw, p4, PortChangeType.DOWN);
-            controller.notifyPortChanged(sw, p5, PortChangeType.OTHER_UPDATE);
-            sendMessageToHandlerNoControllerReset(
-                   Collections.<OFMessage>singletonList(ps));
-            verify(sw);
-            verify(controller);
-        }
-    }
-
-    /**
-     * Test re-assert MASTER
-     *
-     */
-    @Test
-    public void testReassertMaster() throws Exception {
-        testInitialMoveToMasterWithRole();
-
-        OFError err = (OFError)
-                BasicFactory.getInstance().getMessage(OFType.ERROR);
-        err.setXid(42);
-        err.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
-        err.setErrorCode(OFBadRequestCode.OFPBRC_EPERM);
-
-        reset(controller);
-        controller.reassertRole(handler, Role.MASTER);
-        expectLastCall().once();
-        controller.handleMessage(sw, err, null);
-        expectLastCall().once();
-
-        sendMessageToHandlerNoControllerReset(
-                Collections.<OFMessage>singletonList(err));
-
-        verify(sw);
-        verify(controller);
-    }
-
-
-}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer10Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer10Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..038639f79ff45cd566c5f92c3c684d377cb2f49d
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer10Test.java
@@ -0,0 +1,464 @@
+package net.floodlightcontroller.core.internal;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.easymock.Capture;
+import org.easymock.CaptureType;
+import org.easymock.EasyMock;
+import org.hamcrest.CoreMatchers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import net.floodlightcontroller.core.IOFConnectionBackend;
+import net.floodlightcontroller.core.OFConnectionCounters;
+import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandler;
+import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandshakeTimeout;
+import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
+import org.projectfloodlight.openflow.protocol.OFCapabilities;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketInReason;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortReason;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+
+import com.google.common.collect.ImmutableList;
+
+
+public class OFChannelHandlerVer10Test {
+    private IOFSwitchManager switchManager;
+    private IOFConnectionListener connectionListener;
+    private IDebugCounterService debugCounterService;
+    private OFChannelHandler handler;
+    private Channel channel;
+    private Timer timer;
+    private ChannelHandlerContext ctx;
+    private MessageEvent messageEvent;
+    private ChannelStateEvent channelStateEvent;
+    private ChannelPipeline pipeline;
+    // FIXME:LOJI: Currently only use OF 1.0
+    private final OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
+
+    private Capture<ExceptionEvent> exceptionEventCapture;
+    private Capture<List<OFMessage>> writeCapture;
+
+    private OFPortDesc portDesc;
+    private OFFeaturesReply featuresReply;
+
+    private Set<Long> seenXids = null;
+    private INewOFConnectionListener newConnectionListener;
+    private Capture<IOFConnectionBackend> newConnection;
+    private Capture<OFFeaturesReply> newFeaturesReply;
+
+    @Before
+    public void setUpFeaturesReply() {
+       portDesc = factory.buildPortDesc()
+                .setName("Eth1")
+                .setPortNo(OFPort.of(1))
+                .build();
+        featuresReply = factory.buildFeaturesReply()
+                .setDatapathId(DatapathId.of(0x42L))
+                .setNBuffers(1)
+                .setNTables((short)1)
+                .setCapabilities(EnumSet.<OFCapabilities>of(OFCapabilities.FLOW_STATS, OFCapabilities.TABLE_STATS))
+                .setActions(EnumSet.<OFActionType>of(OFActionType.SET_VLAN_PCP))
+                .setPorts(ImmutableList.<OFPortDesc>of(portDesc))
+                .build();
+    }
+
+
+    @Before
+    public void setUp() throws Exception {
+        switchManager = createMock(IOFSwitchManager.class);
+        connectionListener = createMock(IOFConnectionListener.class);
+        newConnectionListener = createMock(INewOFConnectionListener.class);
+        newConnection = new Capture<IOFConnectionBackend>();
+        newFeaturesReply = new Capture<OFFeaturesReply>();
+
+        ctx = createMock(ChannelHandlerContext.class);
+        channelStateEvent = createMock(ChannelStateEvent.class);
+        channel = createMock(Channel.class);
+        timer = new HashedWheelTimer();
+        messageEvent = createMock(MessageEvent.class);
+        exceptionEventCapture = new Capture<ExceptionEvent>(CaptureType.ALL);
+        pipeline = createMock(ChannelPipeline.class);
+        writeCapture = new Capture<List<OFMessage>>(CaptureType.ALL);
+        seenXids = null;
+
+        // TODO: should mock IDebugCounterService and make sure
+        // the expected counters are updated.
+        debugCounterService = new DebugCounterServiceImpl();
+        debugCounterService.registerModule(OFConnectionCounters.COUNTER_MODULE);
+        SwitchManagerCounters counters =
+                new SwitchManagerCounters(debugCounterService);
+        expect(switchManager.getCounters()).andReturn(counters).anyTimes();
+        replay(switchManager);
+        handler = new OFChannelHandler(switchManager, newConnectionListener,
+                                       pipeline, debugCounterService,
+                                       timer);
+        verify(switchManager);
+        reset(switchManager);
+
+        resetChannel();
+
+        // replay controller. Reset it if you need more specific behavior
+        replay(switchManager);
+
+        // Mock ctx and channelStateEvent
+        expect(ctx.getChannel()).andReturn(channel).anyTimes();
+        expect(channelStateEvent.getChannel()).andReturn(channel).anyTimes();
+        replay(ctx, channelStateEvent);
+
+        /* Setup an exception event capture on the channel. Right now
+         * we only expect exception events to be send up the channel.
+         * However, it's easy to extend to other events if we need it
+         */
+        pipeline.sendUpstream(capture(exceptionEventCapture));
+        expectLastCall().anyTimes();
+        expect(pipeline.get(OFMessageDecoder.class)).andReturn(new OFMessageDecoder()).anyTimes();
+        replay(pipeline);
+    }
+
+    @After
+    public void tearDown() {
+        /* ensure no exception was thrown */
+        if (exceptionEventCapture.hasCaptured()) {
+            Throwable ex = exceptionEventCapture.getValue().getCause();
+            ex.printStackTrace();
+            throw new AssertionError("Unexpected exception: " +
+                       ex.getClass().getName() + "(" + ex + ")");
+        }
+        assertFalse("Unexpected messages have been captured",
+                    writeCapture.hasCaptured());
+        // verify all mocks.
+        verify(channel);
+        verify(messageEvent);
+        verify(switchManager);
+        verify(ctx);
+        verify(channelStateEvent);
+        verify(pipeline);
+    }
+
+    /** Reset the channel mock and set basic method call expectations */
+    void resetChannel() {
+        reset(channel);
+        expect(channel.getPipeline()).andReturn(pipeline).anyTimes();
+        expect(channel.getRemoteAddress()).andReturn(InetSocketAddress.createUnresolved("1.1.1.1", 80)).anyTimes();
+    }
+
+
+    /** reset, setup, and replay the messageEvent mock for the given
+     * messages
+     */
+    void setupMessageEvent(List<OFMessage> messages) {
+        reset(messageEvent);
+        expect(messageEvent.getMessage()).andReturn(messages).atLeastOnce();
+        replay(messageEvent);
+    }
+
+
+    /** reset, setup, and replay the messageEvent mock for the given
+     * messages, mock controller  send message to channel handler
+     *
+     * This method will reset, start replay on controller, and then verify
+     */
+    void sendMessageToHandlerWithControllerReset(List<OFMessage> messages)
+            throws Exception {
+
+        sendMessageToHandlerNoControllerReset(messages);
+    }
+
+    /** reset, setup, and replay the messageEvent mock for the given
+     * messages, mock controller  send message to channel handler
+     *
+     * This method will start replay on controller, and then verify
+     */
+    void sendMessageToHandlerNoControllerReset(List<OFMessage> messages)
+            throws Exception {
+        setupMessageEvent(messages);
+
+        handler.messageReceived(ctx, messageEvent);
+    }
+
+    /**
+     * Extract the list of OFMessages that was captured by the Channel.write()
+     * capture. Will check that something was actually captured first. We'll
+     * collapse the messages from multiple writes into a single list of
+     * OFMessages.
+     * Resets the channelWriteCapture.
+     */
+    List<OFMessage> getMessagesFromCapture() {
+        List<OFMessage> msgs = new ArrayList<OFMessage>();
+
+        assertTrue("No write on channel was captured",
+                   writeCapture.hasCaptured());
+        List<List<OFMessage>> capturedVals = writeCapture.getValues();
+
+        for (List<OFMessage> oneWriteList: capturedVals)
+            msgs.addAll(oneWriteList);
+        writeCapture.reset();
+        return msgs;
+    }
+
+
+    /**
+     * Verify that the given exception event capture (as returned by
+     * getAndInitExceptionCapture) has thrown an exception of the given
+     * expectedExceptionClass.
+     * Resets the capture
+     */
+    void verifyExceptionCaptured(
+            Class<? extends Throwable> expectedExceptionClass) {
+        assertTrue("Excpected exception not thrown",
+                   exceptionEventCapture.hasCaptured());
+        Throwable caughtEx = exceptionEventCapture.getValue().getCause();
+        assertEquals(expectedExceptionClass, caughtEx.getClass());
+        exceptionEventCapture.reset();
+    }
+
+    /** make sure that the transaction ids in the given messages are
+     * not 0 and differ between each other.
+     * While it's not a defect per se if the xids are we want to ensure
+     * we use different ones for each message we send.
+     */
+    void verifyUniqueXids(List<OFMessage> msgs) {
+        if (seenXids == null)
+            seenXids = new HashSet<Long>();
+        for (OFMessage m: msgs)  {
+            long xid = m.getXid();
+            assertTrue("Xid in messags is 0", xid != 0);
+            assertFalse("Xid " + xid + " has already been used",
+                        seenXids.contains(xid));
+            seenXids.add(xid);
+        }
+    }
+
+
+    @Test
+    public void testInitState() throws Exception {
+        // Message event needs to be list
+        expect(messageEvent.getMessage()).andReturn(null);
+        replay(channel, messageEvent);
+        handler.messageReceived(ctx, messageEvent);
+        verify(channel, messageEvent);
+        verifyExceptionCaptured(AssertionError.class);
+
+        // We don't expect to receive /any/ messages in init state since
+        // channelConnected moves us to a different state
+        OFMessage m = factory.buildHello().build();
+        sendMessageToHandlerWithControllerReset(ImmutableList.<OFMessage>of(m));
+
+        verifyExceptionCaptured(SwitchStateException.class);
+        assertThat(handler.getStateForTesting(), CoreMatchers.instanceOf(OFChannelHandler.InitState.class));
+    }
+
+    /* Move the channel from scratch to WAIT_HELLO state */
+    @Test
+    public void moveToWaitHello() throws Exception {
+
+        resetChannel();
+        channel.write(capture(writeCapture));
+        expectLastCall().andReturn(null).once();
+        replay(channel);
+        // replay unused mocks
+        replay(messageEvent);
+
+        handler.channelConnected(ctx, channelStateEvent);
+
+        List<OFMessage> msgs = getMessagesFromCapture();
+        assertEquals(1, msgs.size());
+        assertEquals(OFType.HELLO, msgs.get(0).getType());
+        assertThat(handler.getStateForTesting(), CoreMatchers.instanceOf(OFChannelHandler.WaitHelloState.class));
+        verifyUniqueXids(msgs);
+    }
+
+    /** Move the channel from scratch to WAIT_FEATURES_REPLY state
+     * Builds on moveToWaitHello()
+     * adds testing for WAIT_HELLO state
+     */
+    @Test
+    public void moveToWaitFeaturesReply() throws Exception {
+
+        moveToWaitHello();
+
+        resetChannel();
+        channel.write(capture(writeCapture));
+        expectLastCall().andReturn(null).atLeastOnce();
+        replay(channel);
+
+        OFMessage hello = factory.buildHello().build();
+        sendMessageToHandlerWithControllerReset(ImmutableList.<OFMessage>of(hello));
+
+        List<OFMessage> msgs = getMessagesFromCapture();
+        assertEquals(1, msgs.size());
+        assertEquals(OFType.FEATURES_REQUEST, msgs.get(0).getType());
+        verifyUniqueXids(msgs);
+
+        assertThat(handler.getStateForTesting(), CoreMatchers.instanceOf(OFChannelHandler.WaitFeaturesReplyState.class));
+    }
+
+
+    /** Move the channel from scratch to WAIT_FEATURES_REPLY state
+     * Builds on moveToWaitHello()
+     * adds testing for WAIT_HELLO state
+     */
+    @Test
+    public void moveToComplete() throws Exception {
+        moveToWaitFeaturesReply();
+
+        reset(pipeline);
+        HandshakeTimeoutHandler newHandler = new HandshakeTimeoutHandler(
+                                                                         handler,
+                                                                         timer,
+                                                                         PipelineHandshakeTimeout.SWITCH);
+
+        expect(
+               pipeline.replace(EasyMock.eq(PipelineHandler.CHANNEL_HANDSHAKE_TIMEOUT),
+                                EasyMock.eq(PipelineHandler.SWITCH_HANDSHAKE_TIMEOUT),
+                                EasyMock.anyObject(HandshakeTimeoutHandler.class))).andReturn(newHandler)
+                                                                          .once();
+
+        replay(pipeline);
+
+        reset(newConnectionListener);
+        newConnectionListener.connectionOpened(capture(newConnection), capture(newFeaturesReply));
+        expectLastCall().once();
+        replay(newConnectionListener);
+
+        sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(featuresReply));
+
+        assertThat(handler.getStateForTesting(), CoreMatchers.instanceOf(OFChannelHandler.CompleteState.class));
+        assertTrue("A connection has been created and set", handler.getConnectionForTesting() != null);
+
+
+    }
+
+    /**
+     * Test dispatch of messages while in Complete state
+     */
+    @Test
+    public void testMessageDispatchComplete() throws Exception {
+        moveToComplete();
+        newConnection.getValue().setListener(connectionListener);
+
+        resetChannel();
+        channel.write(capture(writeCapture));
+        expectLastCall().andReturn(null).atLeastOnce();
+        replay(channel);
+
+        // Send echo request. expect reply
+        OFMessage echoRequest = factory.buildEchoRequest().build();
+        sendMessageToHandlerWithControllerReset(ImmutableList.<OFMessage>of(echoRequest));
+
+        List<OFMessage> msgs = getMessagesFromCapture();
+        assertEquals(1, msgs.size());
+        assertEquals(OFType.ECHO_REPLY, msgs.get(0).getType());
+
+        // Send barrier reply. expect dispatch
+        OFBarrierReply barrierReply = factory.buildBarrierReply()
+                .build();
+
+        resetAndExpectConnectionListener(barrierReply);
+
+
+        // Send packet in. expect dispatch
+        OFFlowRemoved flowRemoved = factory.buildFlowRemoved()
+                .build();
+
+        resetAndExpectConnectionListener(flowRemoved);
+
+        // Send get config reply. expect dispatch
+        OFGetConfigReply getConfigReply = factory.buildGetConfigReply()
+                .build();
+
+        resetAndExpectConnectionListener(getConfigReply);
+
+        // Send packet in. expect dispatch
+        OFPacketIn pi = factory.buildPacketIn()
+                .setReason(OFPacketInReason.NO_MATCH)
+                .build();
+
+        resetAndExpectConnectionListener(pi);
+
+        // Send port status. expect dispatch
+        OFPortStatus portStatus = factory.buildPortStatus()
+                .setReason(OFPortReason.DELETE)
+                .setDesc(portDesc)
+                .build();
+
+        resetAndExpectConnectionListener(portStatus);
+
+        // Send queue reply. expect dispatch
+        OFQueueGetConfigReply queueReply = factory.buildQueueGetConfigReply()
+                .build();
+
+        resetAndExpectConnectionListener(queueReply);
+
+        // Send stat reply. expect dispatch
+        OFFlowStatsReply statReply = factory.buildFlowStatsReply()
+                .build();
+
+        resetAndExpectConnectionListener(statReply);
+
+        // Send role reply. expect dispatch
+        OFNiciraControllerRoleReply roleReply = factory.buildNiciraControllerRoleReply()
+                .setRole(OFNiciraControllerRole.ROLE_MASTER)
+                .build();
+
+        resetAndExpectConnectionListener(roleReply);
+
+    }
+
+    public void resetAndExpectConnectionListener(OFMessage m) throws Exception{
+        reset(connectionListener);
+        connectionListener.messageReceived(handler.getConnectionForTesting(), m);
+        expectLastCall().once();
+        replay(connectionListener);
+
+        sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(m));
+
+        verify(connectionListener);
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer13Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer13Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..0703ef8c49a8ecdd052c59c96f176bf16a516ab8
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerVer13Test.java
@@ -0,0 +1,470 @@
+package net.floodlightcontroller.core.internal;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.easymock.Capture;
+import org.easymock.CaptureType;
+import org.easymock.EasyMock;
+import org.hamcrest.CoreMatchers;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import net.floodlightcontroller.core.IOFConnectionBackend;
+import net.floodlightcontroller.core.OFConnectionCounters;
+import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandler;
+import net.floodlightcontroller.core.internal.OpenflowPipelineFactory.PipelineHandshakeTimeout;
+import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
+import org.projectfloodlight.openflow.protocol.OFBsnSetAuxCxnsReply;
+import org.projectfloodlight.openflow.protocol.OFCapabilities;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
+import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketInReason;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortReason;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
+import org.projectfloodlight.openflow.protocol.OFRoleReply;
+import org.projectfloodlight.openflow.protocol.OFType;
+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 com.google.common.collect.ImmutableList;
+
+
+public class OFChannelHandlerVer13Test {
+    private static final DatapathId dpid = DatapathId.of(0x42L);
+
+    private IOFSwitchManager switchManager;
+    private IOFConnectionListener connectionListener;
+    private INewOFConnectionListener newConnectionListener;
+    private IDebugCounterService debugCounterService;
+    private OFChannelHandler handler;
+    private Channel channel;
+    private Timer timer;
+    private ChannelHandlerContext ctx;
+    private MessageEvent messageEvent;
+    private ChannelStateEvent channelStateEvent;
+    private ChannelPipeline pipeline;
+    private final OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
+
+    private Capture<ExceptionEvent> exceptionEventCapture;
+    private Capture<List<OFMessage>> writeCapture;
+
+    private OFFeaturesReply featuresReply;
+    private OFPortDesc portDesc;
+
+    private Set<Long> seenXids = null;
+
+    private Capture<IOFConnectionBackend> newConnection;
+
+    private Capture<OFFeaturesReply> newFeaturesReply;
+
+    @Before
+    public void setUpFeaturesReply() {
+        portDesc = factory.buildPortDesc()
+                .setName("Eth1")
+                .setPortNo(OFPort.of(1))
+                .build();
+        featuresReply = factory.buildFeaturesReply()
+                .setDatapathId(dpid)
+                .setNBuffers(1)
+                .setNTables((short)1)
+                .setCapabilities(EnumSet.<OFCapabilities>of(OFCapabilities.FLOW_STATS, OFCapabilities.TABLE_STATS))
+                .setAuxiliaryId(OFAuxId.MAIN)
+                .build();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        switchManager = createMock(IOFSwitchManager.class);
+        connectionListener = createMock(IOFConnectionListener.class);
+        newConnectionListener = createMock(INewOFConnectionListener.class);
+        newConnection = new Capture<IOFConnectionBackend>();
+        newFeaturesReply = new Capture<OFFeaturesReply>();
+
+        ctx = createMock(ChannelHandlerContext.class);
+        channelStateEvent = createMock(ChannelStateEvent.class);
+        channel = createMock(Channel.class);
+        timer = new HashedWheelTimer();
+        messageEvent = createMock(MessageEvent.class);
+        exceptionEventCapture = new Capture<ExceptionEvent>(CaptureType.ALL);
+        pipeline = createMock(ChannelPipeline.class);
+        writeCapture = new Capture<List<OFMessage>>(CaptureType.ALL);
+        seenXids = null;
+
+
+        // TODO: should mock IDebugCounterService and make sure
+        // the expected counters are updated.
+        debugCounterService = new DebugCounterServiceImpl();
+        debugCounterService.registerModule(OFConnectionCounters.COUNTER_MODULE);
+        SwitchManagerCounters counters =
+                new SwitchManagerCounters(debugCounterService);
+        expect(switchManager.getCounters()).andReturn(counters).anyTimes();
+        replay(switchManager);
+        handler = new OFChannelHandler(switchManager, newConnectionListener,
+                                       pipeline, debugCounterService, timer);
+        verify(switchManager);
+        reset(switchManager);
+
+        resetChannel();
+
+        // replay controller. Reset it if you need more specific behavior
+        replay(switchManager);
+
+        // Mock ctx and channelStateEvent
+        expect(ctx.getChannel()).andReturn(channel).anyTimes();
+        expect(channelStateEvent.getChannel()).andReturn(channel).anyTimes();
+        replay(ctx, channelStateEvent);
+
+        /* Setup an exception event capture on the channel. Right now
+         * we only expect exception events to be send up the channel.
+         * However, it's easy to extend to other events if we need it
+         */
+        pipeline.sendUpstream(capture(exceptionEventCapture));
+        expectLastCall().anyTimes();
+        expect(pipeline.get(OFMessageDecoder.class)).andReturn(new OFMessageDecoder()).anyTimes();
+        replay(pipeline);
+    }
+
+    @After
+    public void tearDown() {
+        /* ensure no exception was thrown */
+        if (exceptionEventCapture.hasCaptured()) {
+            Throwable ex = exceptionEventCapture.getValue().getCause();
+            ex.printStackTrace();
+            throw new AssertionError("Unexpected exception: " +
+                       ex.getClass().getName() + "(" + ex + ")");
+        }
+        assertFalse("Unexpected messages have been captured",
+                    writeCapture.hasCaptured());
+        // verify all mocks.
+        verify(channel);
+        verify(messageEvent);
+        verify(switchManager);
+        verify(ctx);
+        verify(channelStateEvent);
+        verify(pipeline);
+    }
+
+    /** Reset the channel mock and set basic method call expectations */
+    void resetChannel() {
+        reset(channel);
+        expect(channel.getPipeline()).andReturn(pipeline).anyTimes();
+        expect(channel.getRemoteAddress()).andReturn(null).anyTimes();
+    }
+
+
+    /** reset, setup, and replay the messageEvent mock for the given
+     * messages
+     */
+    void setupMessageEvent(List<OFMessage> messages) {
+        reset(messageEvent);
+        expect(messageEvent.getMessage()).andReturn(messages).atLeastOnce();
+        replay(messageEvent);
+    }
+
+
+    /** reset, setup, and replay the messageEvent mock for the given
+     * messages, mock controller  send message to channel handler
+     *
+     * This method will reset, start replay on controller, and then verify
+     */
+    void sendMessageToHandlerWithControllerReset(List<OFMessage> messages)
+            throws Exception {
+
+        sendMessageToHandlerNoControllerReset(messages);
+    }
+
+    /** reset, setup, and replay the messageEvent mock for the given
+     * messages, mock controller  send message to channel handler
+     *
+     * This method will start replay on controller, and then verify
+     */
+    void sendMessageToHandlerNoControllerReset(List<OFMessage> messages)
+            throws Exception {
+        setupMessageEvent(messages);
+
+        handler.messageReceived(ctx, messageEvent);
+    }
+
+    /**
+     * Extract the list of OFMessages that was captured by the Channel.write()
+     * capture. Will check that something was actually captured first. We'll
+     * collapse the messages from multiple writes into a single list of
+     * OFMessages.
+     * Resets the channelWriteCapture.
+     */
+    List<OFMessage> getMessagesFromCapture() {
+        List<OFMessage> msgs = new ArrayList<OFMessage>();
+
+        assertTrue("No write on channel was captured",
+                   writeCapture.hasCaptured());
+        List<List<OFMessage>> capturedVals = writeCapture.getValues();
+
+        for (List<OFMessage> oneWriteList: capturedVals)
+            msgs.addAll(oneWriteList);
+        writeCapture.reset();
+        return msgs;
+    }
+
+
+    /**
+     * Verify that the given exception event capture (as returned by
+     * getAndInitExceptionCapture) has thrown an exception of the given
+     * expectedExceptionClass.
+     * Resets the capture
+     */
+    void verifyExceptionCaptured(
+            Class<? extends Throwable> expectedExceptionClass) {
+        assertTrue("Excpected exception not thrown",
+                   exceptionEventCapture.hasCaptured());
+        Throwable caughtEx = exceptionEventCapture.getValue().getCause();
+        assertEquals(expectedExceptionClass, caughtEx.getClass());
+        exceptionEventCapture.reset();
+    }
+
+    /** make sure that the transaction ids in the given messages are
+     * not 0 and differ between each other.
+     * While it's not a defect per se if the xids are we want to ensure
+     * we use different ones for each message we send.
+     */
+    void verifyUniqueXids(List<OFMessage> msgs) {
+        if (seenXids == null)
+            seenXids = new HashSet<Long>();
+        for (OFMessage m: msgs)  {
+            long xid = m.getXid();
+            assertTrue("Xid in messags is 0", xid != 0);
+            assertFalse("Xid " + xid + " has already been used",
+                        seenXids.contains(xid));
+            seenXids.add(xid);
+        }
+    }
+
+
+    @Test
+    public void testInitState() throws Exception {
+        // Message event needs to be list
+        expect(messageEvent.getMessage()).andReturn(null);
+        replay(channel, messageEvent);
+        handler.messageReceived(ctx, messageEvent);
+        verify(channel, messageEvent);
+        verifyExceptionCaptured(AssertionError.class);
+
+        // We don't expect to receive /any/ messages in init state since
+        // channelConnected moves us to a different state
+        OFMessage m = factory.buildHello().build();
+        sendMessageToHandlerWithControllerReset(ImmutableList.<OFMessage>of(m));
+
+        verifyExceptionCaptured(SwitchStateException.class);
+        assertThat(handler.getStateForTesting(), CoreMatchers.instanceOf(OFChannelHandler.InitState.class));
+    }
+
+    /* Move the channel from scratch to WAIT_HELLO state */
+    @Test
+    public void moveToWaitHello() throws Exception {
+        resetChannel();
+        channel.write(capture(writeCapture));
+        expectLastCall().andReturn(null).once();
+        replay(channel);
+        // replay unused mocks
+        replay(messageEvent);
+
+        handler.channelConnected(ctx, channelStateEvent);
+
+        List<OFMessage> msgs = getMessagesFromCapture();
+        assertEquals(1, msgs.size());
+        assertEquals(OFType.HELLO, msgs.get(0).getType());
+        assertThat(handler.getStateForTesting(), CoreMatchers.instanceOf(OFChannelHandler.WaitHelloState.class));
+        verifyUniqueXids(msgs);
+    }
+
+    /** Move the channel from scratch to WAIT_FEATURES_REPLY state
+     * Builds on moveToWaitHello()
+     * adds testing for WAIT_HELLO state
+     */
+    @Test
+    public void moveToWaitFeaturesReply() throws Exception {
+        moveToWaitHello();
+        resetChannel();
+        channel.write(capture(writeCapture));
+        expectLastCall().andReturn(null).atLeastOnce();
+        replay(channel);
+
+        OFMessage hello = factory.buildHello().build();
+        sendMessageToHandlerWithControllerReset(ImmutableList.<OFMessage>of(hello));
+
+        List<OFMessage> msgs = getMessagesFromCapture();
+        assertEquals(1, msgs.size());
+        assertEquals(OFType.FEATURES_REQUEST, msgs.get(0).getType());
+        verifyUniqueXids(msgs);
+
+        assertThat(handler.getStateForTesting(), CoreMatchers.instanceOf(OFChannelHandler.WaitFeaturesReplyState.class));
+    }
+
+
+    /** Move the channel from scratch to WAIT_FEATURES_REPLY state
+     * Builds on moveToWaitHello()
+     * adds testing for WAIT_HELLO state
+     */
+    @Test
+    public void moveToComplete() throws Exception {
+        moveToWaitFeaturesReply();
+
+        reset(pipeline);
+        HandshakeTimeoutHandler newHandler = new HandshakeTimeoutHandler(
+                                                                         handler,
+                                                                         timer,
+                                                                         PipelineHandshakeTimeout.SWITCH);
+
+        expect(
+               pipeline.replace(EasyMock.eq(PipelineHandler.CHANNEL_HANDSHAKE_TIMEOUT),
+                                EasyMock.eq(PipelineHandler.SWITCH_HANDSHAKE_TIMEOUT),
+                                EasyMock.anyObject(HandshakeTimeoutHandler.class))).andReturn(newHandler)
+                                                                          .once();
+
+        replay(pipeline);
+
+        newConnectionListener.connectionOpened(capture(newConnection), capture(newFeaturesReply));
+        expectLastCall().once();
+        replay(newConnectionListener);
+
+        sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(featuresReply));
+
+        assertThat(handler.getStateForTesting(), CoreMatchers.instanceOf(OFChannelHandler.CompleteState.class));
+        assertTrue("A connection has been created and set", handler.getConnectionForTesting() != null);
+        verify(newConnectionListener);
+        assertTrue(newConnection.hasCaptured());
+        assertThat(newFeaturesReply.getValue(), equalTo(featuresReply));
+    }
+
+    /**
+     * Test dispatch of messages while in Complete state
+     */
+    @Test
+    public void testMessageDispatchComplete() throws Exception {
+        moveToComplete();
+        newConnection.getValue().setListener(connectionListener);
+
+        resetChannel();
+        channel.write(capture(writeCapture));
+        expectLastCall().andReturn(null).atLeastOnce();
+        replay(channel);
+
+        // Send echo request. expect reply
+        OFMessage echoRequest = factory.buildEchoRequest().build();
+        sendMessageToHandlerWithControllerReset(ImmutableList.<OFMessage>of(echoRequest));
+
+        List<OFMessage> msgs = getMessagesFromCapture();
+        assertEquals(1, msgs.size());
+        assertEquals(OFType.ECHO_REPLY, msgs.get(0).getType());
+
+
+        // Send barrier reply. expect dispatch
+        OFBarrierReply barrierReply = factory.buildBarrierReply()
+                .build();
+
+        resetAndExpectConnectionListener(barrierReply);
+
+
+        // Send packet in. expect dispatch
+        OFFlowRemoved flowRemoved = factory.buildFlowRemoved()
+                .build();
+
+        resetAndExpectConnectionListener(flowRemoved);
+
+        // Send get config reply. expect dispatch
+        OFGetConfigReply getConfigReply = factory.buildGetConfigReply()
+                .build();
+
+        resetAndExpectConnectionListener(getConfigReply);
+
+        // Send packet in. expect dispatch
+        OFPacketIn pi = factory.buildPacketIn()
+                .setReason(OFPacketInReason.NO_MATCH)
+                .build();
+
+        resetAndExpectConnectionListener(pi);
+
+        // Send port status. expect dispatch
+        OFPortStatus portStatus = factory.buildPortStatus()
+                .setReason(OFPortReason.DELETE)
+                .setDesc(portDesc)
+                .build();
+
+        resetAndExpectConnectionListener(portStatus);
+
+        // Send queue reply. expect dispatch
+        OFQueueGetConfigReply queueReply = factory.buildQueueGetConfigReply()
+                .build();
+
+        resetAndExpectConnectionListener(queueReply);
+
+        // Send stat reply. expect dispatch
+        OFFlowStatsReply statReply = factory.buildFlowStatsReply()
+                .build();
+
+        resetAndExpectConnectionListener(statReply);
+
+        // Send role reply. expect dispatch
+        OFRoleReply roleReply = factory.buildRoleReply()
+                .setRole(OFControllerRole.ROLE_MASTER)
+                .build();
+
+        resetAndExpectConnectionListener(roleReply);
+
+        // Send experimenter. expect dispatch
+        OFBsnSetAuxCxnsReply auxReply = factory.buildBsnSetAuxCxnsReply()
+                .build();
+
+        resetAndExpectConnectionListener(auxReply);
+
+    }
+
+    public void resetAndExpectConnectionListener(OFMessage m) throws Exception{
+        reset(connectionListener);
+        connectionListener.messageReceived(handler.getConnectionForTesting(), m);
+        expectLastCall().once();
+        replay(connectionListener);
+
+        sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(m));
+
+        verify(connectionListener);
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFStatisticsFutureTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFStatisticsFutureTest.java
deleted file mode 100644
index 15dc9f401052962dde4f1df3ce3111599f87d1e4..0000000000000000000000000000000000000000
--- a/src/test/java/net/floodlightcontroller/core/internal/OFStatisticsFutureTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.test.MockThreadPoolService;
-
-import org.junit.Before;
-import org.junit.Test;
-import static org.junit.Assert.*;
-import org.openflow.protocol.OFStatisticsReply;
-import org.openflow.protocol.statistics.OFFlowStatisticsReply;
-import org.openflow.protocol.statistics.OFStatistics;
-import org.openflow.protocol.statistics.OFStatisticsType;
-
-import static org.easymock.EasyMock.*;
-
-public class OFStatisticsFutureTest {
-    private MockThreadPoolService tp;
-
-    @Before
-    public void setUp() {
-        tp = new MockThreadPoolService();
-    }
-
-    private OFStatisticsReply getStatisticsReply(int transactionId,
-                                                   int count, boolean moreReplies) {
-        OFStatisticsReply sr = new OFStatisticsReply();
-        sr.setXid(transactionId);
-        sr.setStatisticType(OFStatisticsType.FLOW);
-        List<OFStatistics> statistics = new ArrayList<OFStatistics>();
-        for (int i = 0; i < count; ++i) {
-            statistics.add(new OFFlowStatisticsReply());
-        }
-        sr.setStatistics(statistics);
-        if (moreReplies)
-            sr.setFlags((short) 1);
-        return sr;
-    }
-
-    public class FutureFetcher<E> implements Runnable {
-        public E value;
-        public Future<E> future;
-
-        public FutureFetcher(Future<E> future) {
-            this.future = future;
-        }
-
-        @Override
-        public void run() {
-            try {
-                value = future.get();
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        /**
-         * @return the value
-         */
-        public E getValue() {
-            return value;
-        }
-
-        /**
-         * @return the future
-         */
-        public Future<E> getFuture() {
-            return future;
-        }
-    }
-
-    /**
-    *
-    * @throws Exception
-    */
-   @Test
-   public void testOFStatisticsFuture() throws Exception {
-       // Test for a single stats reply
-       IOFSwitch sw = createMock(IOFSwitch.class);
-       sw.cancelStatisticsReply(1);
-       OFStatisticsFuture sf = new OFStatisticsFuture(tp, sw, 1);
-
-       replay(sw);
-       List<OFStatistics> stats;
-       FutureFetcher<List<OFStatistics>> ff = new FutureFetcher<List<OFStatistics>>(sf);
-       Thread t = new Thread(ff);
-       t.start();
-       sf.deliverFuture(sw, getStatisticsReply(1, 10, false));
-
-       t.join();
-       stats = ff.getValue();
-       verify(sw);
-       assertEquals(10, stats.size());
-
-       // Test multiple stats replies
-       reset(sw);
-       sw.cancelStatisticsReply(1);
-
-       sf = new OFStatisticsFuture(tp, sw, 1);
-
-       replay(sw);
-       ff = new FutureFetcher<List<OFStatistics>>(sf);
-       t = new Thread(ff);
-       t.start();
-       sf.deliverFuture(sw, getStatisticsReply(1, 10, true));
-       sf.deliverFuture(sw, getStatisticsReply(1, 5, false));
-       t.join();
-
-       stats = sf.get();
-       verify(sw);
-       assertEquals(15, stats.size());
-
-       // Test cancellation
-       reset(sw);
-       sw.cancelStatisticsReply(1);
-       sf = new OFStatisticsFuture(tp, sw, 1);
-
-       replay(sw);
-       ff = new FutureFetcher<List<OFStatistics>>(sf);
-       t = new Thread(ff);
-       t.start();
-       sf.cancel(true);
-       t.join();
-
-       stats = sf.get();
-       verify(sw);
-       assertEquals(0, stats.size());
-
-       // Test self timeout
-       reset(sw);
-       sw.cancelStatisticsReply(1);
-       sf = new OFStatisticsFuture(tp, sw, 1, 75, TimeUnit.MILLISECONDS);
-
-       replay(sw);
-       ff = new FutureFetcher<List<OFStatistics>>(sf);
-       t = new Thread(ff);
-       t.start();
-       t.join(2000);
-
-       stats = sf.get();
-       verify(sw);
-       assertEquals(0, stats.size());
-   }
-
-}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2b4bfcf82c591d363408ce694b72fe791701d47
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandlerTestBase.java
@@ -0,0 +1,1102 @@
+package net.floodlightcontroller.core.internal;
+
+import static org.easymock.EasyMock.anyLong;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.resetToStrict;
+import static org.easymock.EasyMock.verify;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.easymock.EasyMock;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Matchers;
+import org.jboss.netty.util.Timeout;
+import org.jboss.netty.util.Timer;
+import org.jboss.netty.util.TimerTask;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import net.floodlightcontroller.core.HARole;
+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.PortChangeType;
+import net.floodlightcontroller.core.internal.OFSwitchAppHandshakePlugin.PluginResultType;
+import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.QuarantineState;
+import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.WaitAppHandshakeState;
+import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import org.projectfloodlight.openflow.protocol.OFBadActionCode;
+import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketInReason;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortReason;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFSetConfig;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.match.Match;
+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 com.google.common.collect.ImmutableList;
+
+
+public abstract class OFSwitchHandlerTestBase {
+    protected static final DatapathId dpid = DatapathId.of(0x42L);
+
+    protected IOFSwitchManager switchManager;
+    protected RoleManager roleManager;
+
+    private IDebugCounterService debugCounterService;
+    protected OFSwitchHandshakeHandler switchHandler;
+    protected MockOFConnection connection;
+    // Use a 1.0 factory for the 1.0 test
+    protected final OFFactory factory = getFactory();
+
+    protected OFFeaturesReply featuresReply;
+    protected List<IAppHandshakePluginFactory> plugins;
+
+    private HashSet<Long> seenXids = null;
+    protected IOFSwitchBackend sw;
+    private Timer timer;
+    private TestHandshakePlugin handshakePlugin;
+
+    private class TestHandshakePlugin extends OFSwitchAppHandshakePlugin {
+        protected TestHandshakePlugin(PluginResult defaultResult, int timeoutS) {
+            super(defaultResult, timeoutS);
+        }
+
+        @Override
+        protected void processOFMessage(OFMessage m) {
+        }
+
+        @Override
+        protected void enterPlugin() {
+        }
+    }
+
+    @Before
+    public void setUpFeaturesReply() {
+        getFeaturesReply();
+        this.featuresReply = getFeaturesReply();
+
+        // Plugin set
+        IAppHandshakePluginFactory factory = createMock(IAppHandshakePluginFactory.class);
+        PluginResult result = new PluginResult(PluginResultType.QUARANTINE, "test quarantine");
+        handshakePlugin = new TestHandshakePlugin(result, 5);
+        expect(factory.createPlugin()).andReturn(handshakePlugin).anyTimes();
+        replay(factory);
+        plugins = ImmutableList.of(factory);
+    }
+
+
+    @Before
+    public void setUp() throws Exception {
+        switchManager = createMock(IOFSwitchManager.class);
+        roleManager = createMock(RoleManager.class);
+        sw = createMock(IOFSwitchBackend.class);
+        timer = createMock(Timer.class);
+        expect(timer.newTimeout(anyObject(TimerTask.class), anyLong(), anyObject(TimeUnit.class))).andReturn(EasyMock.createNiceMock(Timeout.class));
+        replay(timer);
+        seenXids = null;
+
+        // TODO: should mock IDebugCounterService and make sure
+        // the expected counters are updated.
+        debugCounterService = new DebugCounterServiceImpl();
+        SwitchManagerCounters counters =
+                new SwitchManagerCounters(debugCounterService);
+        expect(switchManager.getCounters()).andReturn(counters).anyTimes();
+        replay(switchManager);
+        connection = new MockOFConnection(featuresReply.getDatapathId(), OFAuxId.MAIN);
+        switchHandler = new OFSwitchHandshakeHandler(connection, featuresReply, switchManager, roleManager, timer);
+
+        // replay sw. Reset it if you need more specific behavior
+        replay(sw);
+    }
+
+
+    @After
+    public void tearDown() {
+        verifyAll();
+    }
+
+    private void verifyAll() {
+        assertThat("Unexpected messages have been captured",
+                   connection.getMessages(),
+                    Matchers.empty());
+        // verify all mocks.
+        verify(sw);
+    }
+
+    void verifyUniqueXids(OFMessage... msgs) {
+        verifyUniqueXids(Arrays.asList(msgs));
+    }
+
+    /** make sure that the transaction ids in the given messages are
+     * not 0 and differ between each other.
+     * While it's not a defect per se if the xids are we want to ensure
+     * we use different ones for each message we send.
+     */
+    void verifyUniqueXids(List<OFMessage> msgs) {
+        if (seenXids == null)
+            seenXids = new HashSet<Long>();
+        for (OFMessage m: msgs)  {
+            long xid = m.getXid();
+            assertTrue("Xid in messags is 0", xid != 0);
+            assertFalse("Xid " + xid + " has already been used",
+                        seenXids.contains(xid));
+            seenXids.add(xid);
+        }
+    }
+
+
+    /*************************** abstract phases / utilities to be filled in by the subclasses */
+
+    // Factory + messages
+
+    /** @return the version-appropriate factory */
+    public abstract OFFactory getFactory();
+
+    /**
+     * @return a version appropriate features reply (different in 1.3 because it
+     * doesn't have ports)
+     */
+    abstract OFFeaturesReply getFeaturesReply();
+    /** @return the class that's used for role requests/replies (OFNiciraRoleRequest vs.
+     *  OFRequest)
+     */
+
+    /// Role differences
+
+    abstract Class<?> getRoleRequestClass();
+    /** Verify that the given OFMessage is a correct RoleRequest message
+     * for the given role using the given xid (for the version).
+     */
+    public abstract void verifyRoleRequest(OFMessage m,
+                                   OFControllerRole expectedRole);
+    /** Return a RoleReply message for the given role */
+    protected abstract OFMessage getRoleReply(long xid, OFControllerRole role);
+
+    /// Difference in the handshake sequence
+
+    /** OF1.3 has the PortDescStatsRequest, OF1.0 not */
+    abstract void moveToPreConfigReply() throws Exception;
+    /**
+     * Move the channel from scratch to WaitAppHandshakeState
+     * Different for OF1.0 and OF1.3 because of GenTables.
+     * @throws Exception
+     */
+    @Test
+    public abstract void moveToWaitAppHandshakeState() throws Exception;
+
+    /**
+     * Move the channel from scratch to WaitSwitchDriverSubHandshake
+     * Different for OF1.0 and OF1.3 because of GenTables.
+     * @throws Exception
+     */
+    @Test
+    public abstract void moveToWaitSwitchDriverSubHandshake() throws Exception;
+
+    /**
+     * Move the channel from scratch to WaitInitialRole
+     * Different for OF1.0 and OF1.3 because of Controller Connections.
+     * @throws Exception
+     */
+    @Test
+    public abstract void moveToWaitInitialRole() throws Exception;
+
+    /*******************************************************************************************/
+
+
+    /** Move the channel from scratch to INIT state
+        This occurs upon creation of the switch handler
+     */
+    @Test
+    public void testInitState() throws Exception {
+        assertThat(connection.getListener(), notNullValue());
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.InitState.class));
+    }
+
+
+    /** Move the channel from scratch to WAIT_CONFIG_REPLY state
+     * adds testing for beginHandshake() which moves the state from
+     * InitState to WaitConfigReply.
+     */
+    @Test
+    public void moveToWaitConfigReply() throws Exception {
+        moveToPreConfigReply();
+
+        List<OFMessage> msgs = connection.getMessages();
+        assertEquals(3, msgs.size());
+        assertEquals(OFType.SET_CONFIG, msgs.get(0).getType());
+        OFSetConfig sc = (OFSetConfig)msgs.get(0);
+        assertEquals(0xffff, sc.getMissSendLen());
+        assertEquals(OFType.BARRIER_REQUEST, msgs.get(1).getType());
+        assertEquals(OFType.GET_CONFIG_REQUEST, msgs.get(2).getType());
+        verifyUniqueXids(msgs);
+        msgs.clear();
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitConfigReplyState.class));
+        verifyAll();
+    }
+
+
+
+    /** Move the channel from scratch to WAIT_DESCRIPTION_STAT_REPLY state
+     * Builds on moveToWaitConfigReply()
+     * adds testing for WAIT_CONFIG_REPLY state
+     */
+    @Test
+    public void moveToWaitDescriptionStatReply() throws Exception {
+        moveToWaitConfigReply();
+
+        connection.clearMessages();
+        OFGetConfigReply cr = factory.buildGetConfigReply()
+                .setMissSendLen(0xFFFF)
+                .build();
+
+        switchHandler.processOFMessage(cr);
+
+        OFMessage msg = connection.retrieveMessage();
+        assertEquals(OFType.STATS_REQUEST, msg.getType());
+        OFStatsRequest<?> sr = (OFStatsRequest<?>)msg;
+        assertEquals(OFStatsType.DESC, sr.getStatsType());
+        verifyUniqueXids(msg);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitDescriptionStatReplyState.class));
+    }
+
+    protected OFDescStatsReply createDescriptionStatsReply() {
+        OFDescStatsReply statsReply = factory.buildDescStatsReply()
+                .setDpDesc("Datapath Description")
+                .setHwDesc("Hardware Description")
+                .setMfrDesc("Manufacturer Description")
+                .setSwDesc("Software Description")
+                .setSerialNum("Serial Number")
+                .build();
+        return statsReply;
+    }
+
+    /**
+     * setup the expectations for the mock switch that are needed
+     * after the switch is instantiated in the WAIT_DESCRIPTION_STATS STATE
+     * Will reset the switch
+     * @throws CounterException
+     */
+    protected void setupSwitchForInstantiationWithReset()
+            throws Exception {
+        reset(sw);
+        sw.setFeaturesReply(featuresReply);
+        expectLastCall().once();
+    }
+
+    /**
+     * Tests a situation where a switch returns a QUARANTINE result. This means
+     * we should move the handshake handler to a quarantine state and also
+     * quarantine the switch in the controller.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void moveQuarantine() throws Exception {
+        moveToWaitAppHandshakeState();
+
+        reset(switchManager);
+        switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.QUARANTINED);
+        expectLastCall().once();
+        replay(switchManager);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(WaitAppHandshakeState.class));
+        WaitAppHandshakeState state = (WaitAppHandshakeState) switchHandler.getStateForTesting();
+        assertThat(state.getCurrentPlugin(), CoreMatchers.<OFSwitchAppHandshakePlugin>equalTo(handshakePlugin));
+
+        reset(sw);
+        expect(sw.getStatus()).andReturn(SwitchStatus.HANDSHAKE);
+        sw.setStatus(SwitchStatus.QUARANTINED);
+        expectLastCall().once();
+        replay(sw);
+
+        PluginResult result = new PluginResult(PluginResultType.QUARANTINE, "test quarantine");
+        handshakePlugin.exitPlugin(result);
+
+        assertThat(switchHandler.getStateForTesting(),
+                   CoreMatchers.instanceOf(QuarantineState.class));
+        verify(switchManager);
+    }
+
+    /**
+     * Tests a situation where a plugin returns a DISCONNECT result. This means
+     * we should disconnect the connection and the state should not change.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void failedAppHandshake() throws Exception {
+        moveToWaitAppHandshakeState();
+
+        assertThat(switchHandler.getStateForTesting(),
+                   CoreMatchers.instanceOf(WaitAppHandshakeState.class));
+
+        WaitAppHandshakeState state = (WaitAppHandshakeState) switchHandler.getStateForTesting();
+        assertThat(state.getCurrentPlugin(), CoreMatchers.<OFSwitchAppHandshakePlugin>equalTo(handshakePlugin));
+
+        PluginResult result = new PluginResult(PluginResultType.DISCONNECT);
+        handshakePlugin.exitPlugin(result);
+
+        assertThat(connection.isConnected(), equalTo(false));
+    }
+
+
+    @Test
+    public void validAppHandshakePluginReason() throws Exception {
+        try{
+            new PluginResult(PluginResultType.QUARANTINE,"This should not cause an exception");
+        }catch(IllegalStateException e) {
+            fail("This should cause an illegal state exception");
+        }
+    }
+
+    @Test
+    public void invalidAppHandshakePluginReason() throws Exception {
+        try{
+            new PluginResult(PluginResultType.CONTINUE,"This should cause an exception");
+            fail("This should cause an illegal state exception");
+        }catch(IllegalStateException e) { /* Expected */ }
+
+        try{
+            new PluginResult(PluginResultType.DISCONNECT,"This should cause an exception");
+            fail("This should cause an illegal state exception");
+        }catch(IllegalStateException e) { /* Expected */ }
+    }
+
+    /**
+     * Move the channel from scratch to WAIT_INITIAL_ROLE state via
+     * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
+     * Does extensive testing for the WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state
+     *
+     */
+    @Test
+    public void testSwitchDriverSubHandshake()
+            throws Exception {
+        moveToWaitSwitchDriverSubHandshake();
+
+        //-------------------------------------------------
+        //-------------------------------------------------
+        // Send a message to the handler, it should be passed to the
+        // switch's sub-handshake handling. After this message the
+        // sub-handshake will be complete
+        // FIXME:LOJI: With Andi's fix for a default Match object we won't
+        // need to build/set this match object
+
+        Match match = factory.buildMatch().build();
+        OFMessage m = factory.buildFlowRemoved().setMatch(match).build();
+        resetToStrict(sw);
+        sw.processDriverHandshakeMessage(m);
+        expectLastCall().once();
+        expect(sw.isDriverHandshakeComplete()).andReturn(true).once();
+        replay(sw);
+
+        switchHandler.processOFMessage(m);
+
+        assertThat(switchHandler.getStateForTesting(),
+                   CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitAppHandshakeState.class));
+        assertThat("Unexpected message captured", connection.getMessages(), Matchers.empty());
+        verify(sw);
+    }
+
+    @Test
+    /** Test WaitDescriptionReplyState */
+    public void testWaitDescriptionReplyState() throws Exception {
+        moveToWaitInitialRole();
+    }
+
+    /**
+     * Setup the mock switch and write capture for a role request, set the
+     * role and verify mocks.
+     * @param supportsNxRole whether the switch supports role request messages
+     * to setup the attribute. This must be null (don't yet know if roles
+     * supported: send to check) or true.
+     * @param role The role to send
+     * @throws IOException
+     */
+    private long setupSwitchSendRoleRequestAndVerify(Boolean supportsNxRole,
+                                           OFControllerRole role) throws IOException {
+        assertTrue("This internal test helper method most not be called " +
+                   "with supportsNxRole==false. Test setup broken",
+                   supportsNxRole == null || supportsNxRole == true);
+        reset(sw);
+        expect(sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
+                .andReturn(supportsNxRole).atLeastOnce();
+        replay(sw);
+
+        switchHandler.sendRoleRequest(role);
+
+        OFMessage msg = connection.retrieveMessage();
+        verifyRoleRequest(msg, role);
+        verify(sw);
+        return msg.getXid();
+    }
+
+
+    /**
+     * Setup the mock switch for a role change request where the switch
+     * does not support roles.
+     *
+     * Needs to verify and reset the controller since we need to set
+     * an expectation
+     */
+    private void setupSwitchRoleChangeUnsupported(int xid,
+                                                  OFControllerRole role) {
+        SwitchStatus newStatus = role != OFControllerRole.ROLE_SLAVE ? SwitchStatus.MASTER : SwitchStatus.SLAVE;
+        boolean supportsNxRole = false;
+        verify(switchManager);
+        reset(sw, switchManager);
+        expect(sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
+                .andReturn(supportsNxRole).atLeastOnce();
+        // TODO: hmmm. While it's not incorrect that we set the attribute
+        // again it looks odd. Maybe change
+        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, supportsNxRole);
+        expectLastCall().anyTimes();
+        sw.setControllerRole(role);
+        expectLastCall().once();
+
+        if (role == OFControllerRole.ROLE_SLAVE) {
+            sw.disconnect();
+            expectLastCall().once();
+        } else {
+            expect(sw.getStatus()).andReturn(SwitchStatus.HANDSHAKE).once();
+            sw.setStatus(newStatus);
+            expectLastCall().once();
+            switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, newStatus);
+        }
+        replay(sw, switchManager);
+
+        switchHandler.sendRoleRequest(role);
+
+        verify(sw, switchManager);
+    }
+
+    /** Return a bad request error message with the given xid/code */
+    private OFMessage getBadRequestErrorMessage(OFBadRequestCode code, long xid) {
+        OFErrorMsg msg = factory.errorMsgs().buildBadRequestErrorMsg()
+                .setXid(xid)
+                .setCode(code)
+                .build();
+        return msg;
+    }
+
+    /** Return a bad action error message with the given xid/code */
+    private OFMessage getBadActionErrorMessage(OFBadActionCode code, long xid) {
+        OFErrorMsg msg = factory.errorMsgs().buildBadActionErrorMsg()
+                .setXid(xid)
+                .setCode(code)
+                .build();
+        return msg;
+    }
+
+
+    /** Move the channel from scratch to MASTER state
+     * Builds on doMoveToWaitInitialRole()
+     * adds testing for WAIT_INITAL_ROLE state
+     *
+     * This method tests only the simple case that the switch supports roles
+     * and transitions to MASTER
+     */
+    @Test
+    public void testInitialMoveToMasterWithRole() throws Exception {
+        // first, move us to WAIT_INITIAL_ROLE_STATE
+        moveToWaitInitialRole();
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // Set the role
+        long xid = setupSwitchSendRoleRequestAndVerify(null, OFControllerRole.ROLE_MASTER);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // prepare mocks and inject the role reply message
+        reset(sw);
+        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
+        expectLastCall().once();
+        sw.setControllerRole(OFControllerRole.ROLE_MASTER);
+        expectLastCall().once();
+        expect(sw.getStatus()).andReturn(SwitchStatus.HANDSHAKE).once();
+        sw.setStatus(SwitchStatus.MASTER);
+        expectLastCall().once();
+        replay(sw);
+
+        reset(switchManager);
+        switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+        expectLastCall().once();
+        replay(switchManager);
+        OFMessage reply = getRoleReply(xid, OFControllerRole.ROLE_MASTER);
+
+        // sendMessageToHandler will verify and rest controller mock
+        switchHandler.processOFMessage(reply);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.MasterState.class));
+    }
+
+    /** Move the channel from scratch to SLAVE state
+     * Builds on doMoveToWaitInitialRole()
+     * adds testing for WAIT_INITAL_ROLE state
+     *
+     * This method tests only the simple case that the switch supports roles
+     * and transitions to SLAVE
+     */
+    @Test
+    public void testInitialMoveToSlaveWithRole() throws Exception {
+
+        // first, move us to WAIT_INITIAL_ROLE_STATE
+        moveToWaitInitialRole();
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // Set the role
+        long xid = setupSwitchSendRoleRequestAndVerify(null, OFControllerRole.ROLE_SLAVE);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // prepare mocks and inject the role reply message
+        reset(sw);
+        sw.setAttribute(IOFSwitchBackend.SWITCH_SUPPORTS_NX_ROLE, true);
+        expectLastCall().once();
+        sw.setControllerRole(OFControllerRole.ROLE_SLAVE);
+        expectLastCall().once();
+        expect(sw.getStatus()).andReturn(SwitchStatus.HANDSHAKE).once();
+        sw.setStatus(SwitchStatus.SLAVE);
+        expectLastCall().once();
+        replay(sw);
+
+        reset(switchManager);
+        switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.SLAVE);
+        expectLastCall().once();
+        replay(switchManager);
+
+        OFMessage reply = getRoleReply(xid, OFControllerRole.ROLE_SLAVE);
+
+        // sendMessageToHandler will verify and rest controller mock
+        switchHandler.processOFMessage(reply);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.SlaveState.class));
+    }
+
+    /** Move the channel from scratch to MASTER state
+     * Builds on doMoveToWaitInitialRole()
+     * adds testing for WAIT_INITAL_ROLE state
+     *
+     * This method tests the case that the switch does NOT support roles.
+     * The channel handler still needs to send the initial request to find
+     * out that whether the switch supports roles.
+     */
+    @Test
+    public void testInitialMoveToMasterNoRole() throws Exception {
+        // first, move us to WAIT_INITIAL_ROLE_STATE
+        moveToWaitInitialRole();
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // Set the role
+        long xid = setupSwitchSendRoleRequestAndVerify(null, OFControllerRole.ROLE_MASTER);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // prepare mocks and inject the role reply message
+        reset(sw);
+        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
+        expectLastCall().once();
+        sw.setControllerRole(OFControllerRole.ROLE_MASTER);
+        expectLastCall().once();
+        expect(sw.getStatus()).andReturn(SwitchStatus.HANDSHAKE).once();
+        sw.setStatus(SwitchStatus.MASTER);
+        expectLastCall().once();
+        replay(sw);
+
+        // FIXME: shouldn't use ordinal(), but OFError is broken
+
+        // Error with incorrect xid and type. Should be ignored.
+        OFMessage err = getBadActionErrorMessage(OFBadActionCode.BAD_TYPE, xid+1);
+        // sendMessageToHandler will verify and rest controller mock
+        switchHandler.processOFMessage(err);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // Error with correct xid. Should trigger state transition
+        err = getBadRequestErrorMessage(OFBadRequestCode.BAD_EXPERIMENTER, xid);
+        reset(switchManager);
+        switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+        expectLastCall().once();
+        replay(switchManager);
+        // sendMessageToHandler will verify and rest controller mock
+        switchHandler.processOFMessage(err);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.MasterState.class));
+    }
+
+    /** Move the channel from scratch to MASTER state
+     * Builds on doMoveToWaitInitialRole()
+     * adds testing for WAIT_INITAL_ROLE state
+     *
+     * We let the initial role request time out. Role support should be
+     * disabled but the switch should be activated.
+     */
+    @Test
+    public void testInitialMoveToMasterTimeout() throws Exception {
+        int timeout = 50;
+        switchHandler.useRoleChangerWithOtherTimeoutForTesting(timeout);
+
+        // first, move us to WAIT_INITIAL_ROLE_STATE
+        moveToWaitInitialRole();
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // Set the role
+        setupSwitchSendRoleRequestAndVerify(null, OFControllerRole.ROLE_MASTER);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // prepare mocks and inject the role reply message
+        reset(sw);
+        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
+        expectLastCall().once();
+        sw.setControllerRole(OFControllerRole.ROLE_MASTER);
+        expectLastCall().once();
+        expect(sw.getStatus()).andReturn(SwitchStatus.HANDSHAKE).once();
+        sw.setStatus(SwitchStatus.MASTER);
+        expectLastCall().once();
+        replay(sw);
+
+        OFMessage m = factory.buildBarrierReply().build();
+
+        Thread.sleep(timeout+5);
+
+        reset(switchManager);
+        switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+        expectLastCall().once();
+        replay(switchManager);
+        switchHandler.processOFMessage(m);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.MasterState.class));
+
+    }
+
+
+    /** Move the channel from scratch to SLAVE state
+     * Builds on doMoveToWaitInitialRole()
+     * adds testing for WAIT_INITAL_ROLE state
+     *
+     * This method tests the case that the switch does NOT support roles.
+     * The channel handler still needs to send the initial request to find
+     * out that whether the switch supports roles.
+     *
+     */
+    @Test
+    public void testInitialMoveToSlaveNoRole() throws Exception {
+        // first, move us to WAIT_INITIAL_ROLE_STATE
+        moveToWaitInitialRole();
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // Set the role
+        long xid = setupSwitchSendRoleRequestAndVerify(null, OFControllerRole.ROLE_SLAVE);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // prepare mocks and inject the role reply message
+        reset(sw);
+        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
+        expectLastCall().once();
+        sw.setControllerRole(OFControllerRole.ROLE_SLAVE);
+        expectLastCall().once();
+        sw.disconnect(); // Make sure we disconnect
+        expectLastCall().once();
+        replay(sw);
+
+
+        // FIXME: shouldn't use ordinal(), but OFError is broken
+
+        // Error with incorrect xid and type. Should be ignored.
+        OFMessage err = getBadActionErrorMessage(OFBadActionCode.BAD_TYPE, xid+1);
+
+        // sendMessageToHandler will verify and rest controller mock
+        switchHandler.processOFMessage(err);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // Error with correct xid. Should trigger state transition
+        err = getBadRequestErrorMessage(OFBadRequestCode.BAD_EXPERIMENTER, xid);
+        // sendMessageToHandler will verify and rest controller mock
+        switchHandler.processOFMessage(err);
+    }
+
+
+    /** Move the channel from scratch to SLAVE state
+     * Builds on doMoveToWaitInitialRole()
+     * adds testing for WAIT_INITAL_ROLE state
+     *
+     * We let the initial role request time out. The switch should be
+     * disconnected
+     */
+    @Test
+    public void testInitialMoveToSlaveTimeout() throws Exception {
+        int timeout = 50;
+        switchHandler.useRoleChangerWithOtherTimeoutForTesting(timeout);
+
+        // first, move us to WAIT_INITIAL_ROLE_STATE
+        moveToWaitInitialRole();
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // Set the role
+        setupSwitchSendRoleRequestAndVerify(null, OFControllerRole.ROLE_SLAVE);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // prepare mocks and inject the role reply message
+        reset(sw);
+        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
+        expectLastCall().once();
+        sw.setControllerRole(OFControllerRole.ROLE_SLAVE);
+        expectLastCall().once();
+        sw.disconnect(); // Make sure we disconnect
+        expectLastCall().once();
+        replay(sw);
+
+        // Apparently this can be any type of message for this test?!
+        OFMessage m = factory.buildBarrierReply().build();
+
+        Thread.sleep(timeout+5);
+        switchHandler.processOFMessage(m);
+    }
+
+
+    /** Move channel from scratch to WAIT_INITIAL_STATE, then MASTER,
+     * then SLAVE for cases where the switch does not support roles.
+     * I.e., the final SLAVE transition should disconnect the switch.
+     */
+    @Test
+    public void testNoRoleInitialToMasterToSlave() throws Exception {
+        int xid = 46;
+        // First, lets move the state to MASTER without role support
+        testInitialMoveToMasterNoRole();
+        assertThat(switchHandler.getStateForTesting(),
+                CoreMatchers.instanceOf(OFSwitchHandshakeHandler.MasterState.class));
+
+        assertThat("Unexpected messages have been captured",
+                connection.getMessages(),
+                 Matchers.empty());
+
+        // try to set master role again. should be a no-op
+        setupSwitchRoleChangeUnsupported(xid, OFControllerRole.ROLE_MASTER);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.MasterState.class));
+
+        assertThat("Unexpected messages have been captured",
+                connection.getMessages(),
+                 Matchers.empty());
+
+        setupSwitchRoleChangeUnsupported(xid, OFControllerRole.ROLE_SLAVE);
+        assertThat(connection.isConnected(), equalTo(false));
+
+        assertThat("Unexpected messages have been captured",
+                connection.getMessages(),
+                 Matchers.empty());
+    }
+
+    /** Move the channel to MASTER state
+     * Expects that the channel is in MASTER or SLAVE state.
+     *
+     */
+    public void changeRoleToMasterWithRequest() throws Exception {
+        assertTrue("This method can only be called when handler is in " +
+                   "MASTER or SLAVE role", switchHandler.isHandshakeComplete());
+
+        // Set the role
+        long xid = setupSwitchSendRoleRequestAndVerify(true, OFControllerRole.ROLE_MASTER);
+
+        // prepare mocks and inject the role reply message
+        reset(sw);
+        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
+        expectLastCall().once();
+        sw.setControllerRole(OFControllerRole.ROLE_MASTER);
+        expectLastCall().once();
+        expect(sw.getStatus()).andReturn(SwitchStatus.HANDSHAKE).once();
+        sw.setStatus(SwitchStatus.MASTER);
+        expectLastCall().once();
+        replay(sw);
+
+        reset(switchManager);
+        switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+        expectLastCall().once();
+        replay(switchManager);
+
+        OFMessage reply = getRoleReply(xid, OFControllerRole.ROLE_MASTER);
+
+        switchHandler.processOFMessage(reply);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.MasterState.class));
+    }
+
+    /** Move the channel to SLAVE state
+     * Expects that the channel is in MASTER or SLAVE state.
+     *
+     */
+    public void changeRoleToSlaveWithRequest() throws Exception {
+        assertTrue("This method can only be called when handler is in " +
+                   "MASTER or SLAVE role", switchHandler.isHandshakeComplete());
+
+        // Set the role
+        long xid = setupSwitchSendRoleRequestAndVerify(true, OFControllerRole.ROLE_SLAVE);
+
+        // prepare mocks and inject the role reply message
+        reset(sw);
+        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
+        expectLastCall().once();
+        sw.setControllerRole(OFControllerRole.ROLE_SLAVE);
+        expectLastCall().once();
+        expect(sw.getStatus()).andReturn(SwitchStatus.MASTER).once();
+        sw.setStatus(SwitchStatus.SLAVE);
+        expectLastCall().once();
+        replay(sw);
+
+        reset(switchManager);
+        switchManager.switchStatusChanged(sw, SwitchStatus.MASTER, SwitchStatus.SLAVE);
+        expectLastCall().once();
+        replay(switchManager);
+
+        OFMessage reply = getRoleReply(xid, OFControllerRole.ROLE_SLAVE);
+        connection.getListener().messageReceived(connection, reply);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.SlaveState.class));
+    }
+
+    @Test
+    public void testMultiRoleChange1() throws Exception {
+        testInitialMoveToMasterWithRole();
+        changeRoleToMasterWithRequest();
+        changeRoleToSlaveWithRequest();
+        changeRoleToSlaveWithRequest();
+        changeRoleToMasterWithRequest();
+        changeRoleToSlaveWithRequest();
+    }
+
+    @Test
+    public void testMultiRoleChange2() throws Exception {
+        testInitialMoveToSlaveWithRole();
+        changeRoleToMasterWithRequest();
+        changeRoleToSlaveWithRequest();
+        changeRoleToSlaveWithRequest();
+        changeRoleToMasterWithRequest();
+        changeRoleToSlaveWithRequest();
+    }
+
+    /** Start from scratch and reply with an unexpected error to the role
+     * change request
+     * Builds on doMoveToWaitInitialRole()
+     * adds testing for WAIT_INITAL_ROLE state
+     */
+    @Test
+    public void testInitialRoleChangeOtherError() throws Exception {
+        // first, move us to WAIT_INITIAL_ROLE_STATE
+        moveToWaitInitialRole();
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        // Set the role
+        long xid = setupSwitchSendRoleRequestAndVerify(null, OFControllerRole.ROLE_MASTER);
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+
+        OFMessage err = getBadActionErrorMessage(OFBadActionCode.BAD_TYPE, xid);
+
+        verifyExceptionCaptured(err, SwitchStateException.class);
+    }
+
+    /**
+     * Test dispatch of messages while in MASTER role
+     */
+    @Test
+    public void testMessageDispatchMaster() throws Exception {
+        testInitialMoveToMasterWithRole();
+
+        // Send packet in. expect dispatch
+        OFPacketIn pi = factory.buildPacketIn()
+                .setReason(OFPacketInReason.NO_MATCH)
+                .build();
+        reset(switchManager);
+        switchManager.handleMessage(sw, pi, null);
+        expectLastCall().once();
+        replay(switchManager);
+        switchHandler.processOFMessage(pi);
+
+        // TODO: many more to go
+    }
+
+    /**
+     * Test port status message handling while MASTER
+     *
+     */
+    @Test
+    public void testPortStatusMessageMaster() throws Exception {
+        DatapathId dpid = featuresReply.getDatapathId();
+        testInitialMoveToMasterWithRole();
+
+        OFPortDesc portDesc = factory.buildPortDesc()
+                .setName("Port1")
+                .setPortNo(OFPort.of(1))
+                .build();
+        OFPortStatus.Builder portStatusBuilder = factory.buildPortStatus()
+                .setDesc(portDesc);
+
+        // The events we expect sw.handlePortStatus to return
+        // We'll just use the same list for all valid OFPortReasons and add
+        // arbitrary events for arbitrary ports that are not necessarily
+        // related to the port status message. Our goal
+        // here is not to return the correct set of events but the make sure
+        // that a) sw.handlePortStatus is called
+        //      b) the list of events sw.handlePortStatus returns is sent
+        //         as IOFSwitchListener notifications.
+        OrderedCollection<PortChangeEvent> events =
+                new LinkedHashSetWrapper<PortChangeEvent>();
+        OFPortDesc.Builder pb = factory.buildPortDesc();
+        OFPortDesc p1 = pb.setName("eth1").setPortNo(OFPort.of(1)).build();
+        OFPortDesc p2 = pb.setName("eth2").setPortNo(OFPort.of(2)).build();
+        OFPortDesc p3 = pb.setName("eth3").setPortNo(OFPort.of(3)).build();
+        OFPortDesc p4 = pb.setName("eth4").setPortNo(OFPort.of(4)).build();
+        OFPortDesc p5 = pb.setName("eth5").setPortNo(OFPort.of(5)).build();
+
+        
+        events.add(new PortChangeEvent(p1, PortChangeType.ADD));
+        events.add(new PortChangeEvent(p2, PortChangeType.DELETE));
+        events.add(new PortChangeEvent(p3, PortChangeType.UP));
+        events.add(new PortChangeEvent(p4, PortChangeType.DOWN));
+        events.add(new PortChangeEvent(p5, PortChangeType.OTHER_UPDATE));
+
+
+        for (OFPortReason reason: OFPortReason.values()) {
+            OFPortStatus portStatus = portStatusBuilder.setReason(reason).build();
+
+            reset(sw);
+            expect(sw.getId()).andReturn(dpid).anyTimes();
+
+            expect(sw.processOFPortStatus(portStatus)).andReturn(events).once();
+            replay(sw);
+
+            reset(switchManager);
+            switchManager.notifyPortChanged(sw, p1, PortChangeType.ADD);
+            switchManager.notifyPortChanged(sw, p2, PortChangeType.DELETE);
+            switchManager.notifyPortChanged(sw, p3, PortChangeType.UP);
+            switchManager.notifyPortChanged(sw, p4, PortChangeType.DOWN);
+            switchManager.notifyPortChanged(sw, p5, PortChangeType.OTHER_UPDATE);
+            replay(switchManager);
+
+            switchHandler.processOFMessage(portStatus);
+
+            verify(sw);
+        }
+    }
+
+    /**
+     * Test re-assert MASTER
+     *
+     */
+    @Test
+    public void testReassertMaster() throws Exception {
+        testInitialMoveToMasterWithRole();
+
+        OFMessage err = getBadRequestErrorMessage(OFBadRequestCode.EPERM, 42);
+
+        reset(roleManager);
+        roleManager.reassertRole(switchHandler, HARole.ACTIVE);
+        expectLastCall().once();
+        replay(roleManager);
+
+        reset(switchManager);
+        switchManager.handleMessage(sw, err, null);
+        expectLastCall().once();
+        replay(switchManager);
+
+        switchHandler.processOFMessage(err);
+
+        verify(sw);
+    }
+
+    /**
+     * Verify that the given exception event capture (as returned by
+     * getAndInitExceptionCapture) has thrown an exception of the given
+     * expectedExceptionClass.
+     * Resets the capture
+     * @param err
+     */
+    void verifyExceptionCaptured(
+            OFMessage err, Class<? extends Throwable> expectedExceptionClass) {
+
+        Throwable caughtEx = null;
+        // This should purposely cause an exception
+        try{
+            switchHandler.processOFMessage(err);
+        }
+        catch(Exception e){
+            // Capture the exception
+            caughtEx = e;
+        }
+
+        assertThat(caughtEx, CoreMatchers.instanceOf(expectedExceptionClass));
+    }
+
+    /**
+     * Tests the connection closed functionality before the switch handshake is complete.
+     * Essentially when the switch handshake is only aware of the IOFConnection.
+     */
+    @Test
+    public void testConnectionClosedBeforeHandshakeComplete() {
+
+        // Test connection closed prior to being finished
+        reset(switchManager);
+        switchManager.handshakeDisconnected(dpid);
+        expectLastCall().once();
+        replay(switchManager);
+
+        switchHandler.connectionClosed(connection);
+
+        verify(switchManager);
+    }
+
+    /**
+     * Tests the connection closed functionality after the switch handshake is complete.
+     * Essentially when the switch handshake is aware of an IOFSwitch.
+     * @throws Exception
+     */
+    @Test
+    public void testConnectionClosedAfterHandshakeComplete() throws Exception {
+
+        testInitialMoveToMasterWithRole();
+        // Test connection closed prior to being finished
+        reset(switchManager);
+        switchManager.handshakeDisconnected(dpid);
+        expectLastCall().once();
+        switchManager.switchDisconnected(sw);
+        expectLastCall().once();
+        replay(switchManager);
+
+        reset(sw);
+        expect(sw.getStatus()).andReturn(SwitchStatus.DISCONNECTED).anyTimes();
+        replay(sw);
+
+        switchHandler.connectionClosed(connection);
+
+        verify(switchManager);
+        verify(sw);
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..cefde88995600fc48eeda697301e801f89ff5dd7
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer10Test.java
@@ -0,0 +1,172 @@
+package net.floodlightcontroller.core.internal;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertThat;
+
+import java.util.EnumSet;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import net.floodlightcontroller.core.IOFSwitchBackend;
+import net.floodlightcontroller.core.OFConnection;
+import net.floodlightcontroller.core.SwitchDescription;
+import net.floodlightcontroller.core.internal.OFSwitchAppHandshakePlugin.PluginResultType;
+import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.WaitAppHandshakeState;
+import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.projectfloodlight.openflow.protocol.OFCapabilities;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+
+import com.google.common.collect.ImmutableList;
+
+
+public class OFSwitchHandshakeHandlerVer10Test extends OFSwitchHandlerTestBase {
+
+    @Override
+    public OFFactory getFactory() {
+        return OFFactories.getFactory(OFVersion.OF_10);
+    }
+
+    @Override
+    OFFeaturesReply getFeaturesReply() {
+        OFPortDesc portDesc = factory.buildPortDesc()
+                .setName("Eth1")
+                .setPortNo(OFPort.of(1))
+                .build();
+        return factory.buildFeaturesReply()
+                .setDatapathId(dpid)
+                .setNBuffers(1)
+                .setNTables((short)1)
+                .setCapabilities(EnumSet.<OFCapabilities>of(OFCapabilities.FLOW_STATS, OFCapabilities.TABLE_STATS))
+                .setActions(EnumSet.<OFActionType>of(OFActionType.SET_VLAN_PCP))
+                .setPorts(ImmutableList.<OFPortDesc>of(portDesc))
+                .build();
+    }
+
+    @Override
+    void moveToPreConfigReply() throws Exception {
+        testInitState();
+        switchHandler.beginHandshake();
+    }
+
+    public void handleDescStatsAndCreateSwitch(boolean switchDriverComplete) throws Exception {
+        // build the stats reply
+        OFDescStatsReply sr = createDescriptionStatsReply();
+
+        reset(sw);
+        SwitchDescription switchDescription = new SwitchDescription(sr);
+        setupSwitchForInstantiationWithReset();
+        sw.startDriverHandshake();
+        expectLastCall().once();
+        sw.isDriverHandshakeComplete();
+        expectLastCall().andReturn(switchDriverComplete).once();
+
+        if(factory.getVersion().compareTo(OFVersion.OF_13) >= 0) {
+            sw.setPortDescStats(anyObject(OFPortDescStatsReply.class));
+            expectLastCall().once();
+        }
+
+        replay(sw);
+
+        reset(switchManager);
+        expect(switchManager.getHandshakePlugins()).andReturn(plugins).anyTimes();
+        expect(
+               switchManager.getOFSwitchInstance(anyObject(OFConnection.class),
+                                              eq(switchDescription),
+                                              anyObject(OFFactory.class),
+                                              anyObject(DatapathId.class))).andReturn(sw).once();
+        switchManager.switchAdded(sw);
+        expectLastCall().once();
+        replay(switchManager);
+
+        // send the description stats reply
+        switchHandler.processOFMessage(sr);
+    }
+
+    @Test
+    @Override
+    public void moveToWaitAppHandshakeState() throws Exception {
+        moveToWaitDescriptionStatReply();
+        handleDescStatsAndCreateSwitch(true);
+        assertThat(switchHandler.getStateForTesting(),
+                CoreMatchers.instanceOf(WaitAppHandshakeState.class));
+    }
+
+    @Override
+    Class<?> getRoleRequestClass() {
+        return OFNiciraControllerRoleRequest.class;
+    }
+
+    @Override
+    public void verifyRoleRequest(OFMessage m, OFControllerRole expectedRole) {
+        assertThat(m.getType(), equalTo(OFType.EXPERIMENTER));
+        OFNiciraControllerRoleRequest roleRequest = (OFNiciraControllerRoleRequest)m;
+        assertThat(roleRequest.getRole(), equalTo(NiciraRoleUtils.ofRoleToNiciraRole(expectedRole)));
+    }
+
+    @Override
+    protected OFMessage getRoleReply(long xid, OFControllerRole role) {
+        OFNiciraControllerRoleReply roleReply = factory.buildNiciraControllerRoleReply()
+                .setXid(xid)
+                .setRole(NiciraRoleUtils.ofRoleToNiciraRole(role))
+                .build();
+        return roleReply;
+    }
+
+    @Override
+    @Test
+    public void moveToWaitSwitchDriverSubHandshake() throws Exception {
+        moveToWaitDescriptionStatReply();
+        handleDescStatsAndCreateSwitch(false);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitSwitchDriverSubHandshakeState.class));
+        assertThat("Unexpected message captured", connection.getMessages(), Matchers.empty());
+        verify(sw);
+    }
+
+    @Override
+    @Test
+    public void moveToWaitInitialRole()
+            throws Exception {
+        moveToWaitAppHandshakeState();
+
+        assertThat(switchHandler.getStateForTesting(),
+                   CoreMatchers.instanceOf(WaitAppHandshakeState.class));
+
+        reset(sw);
+        expect(sw.getAttribute(IOFSwitchBackend.SWITCH_SUPPORTS_NX_ROLE)).andReturn(true).anyTimes();
+        replay(sw);
+
+        reset(roleManager);
+        expect(roleManager.getOFControllerRole()).andReturn(OFControllerRole.ROLE_MASTER).anyTimes();
+        replay(roleManager);
+
+        WaitAppHandshakeState state = (WaitAppHandshakeState) switchHandler.getStateForTesting();
+        PluginResult result = new PluginResult(PluginResultType.CONTINUE);
+        state.exitPlugin(result);
+
+        assertThat(connection.retrieveMessage(), instanceOf(getRoleRequestClass()));
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..caf061b1d2fb1574710bdacc3a92319d3222991a
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchHandshakeHandlerVer13Test.java
@@ -0,0 +1,345 @@
+package net.floodlightcontroller.core.internal;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.easymock.Capture;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import net.floodlightcontroller.core.IOFSwitchBackend;
+import net.floodlightcontroller.core.OFConnection;
+import net.floodlightcontroller.core.SwitchDescription;
+import net.floodlightcontroller.core.internal.OFSwitchAppHandshakePlugin.PluginResultType;
+import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.WaitAppHandshakeState;
+import net.floodlightcontroller.core.util.URIUtil;
+import org.projectfloodlight.openflow.protocol.OFBsnControllerConnection;
+import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionState;
+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.OFCapabilities;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+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.protocol.OFPortDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFRoleReply;
+import org.projectfloodlight.openflow.protocol.OFRoleRequest;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.GenTableId;
+import org.projectfloodlight.openflow.types.OFAuxId;
+import org.projectfloodlight.openflow.types.OFPort;
+
+import com.google.common.collect.ImmutableList;
+
+
+public class OFSwitchHandshakeHandlerVer13Test extends OFSwitchHandlerTestBase {
+
+    @Override
+    public OFFactory getFactory() {
+        return OFFactories.getFactory(OFVersion.OF_13);
+    }
+
+    @Override
+    OFFeaturesReply getFeaturesReply() {
+        return factory.buildFeaturesReply()
+                .setDatapathId(dpid)
+                .setNBuffers(1)
+                .setNTables((short)1)
+                .setCapabilities(EnumSet.<OFCapabilities>of(OFCapabilities.FLOW_STATS, OFCapabilities.TABLE_STATS))
+                .setAuxiliaryId(OFAuxId.MAIN)
+                .build();
+    }
+
+    OFPortDescStatsReply getPortDescStatsReply() {
+        OFPortDesc portDesc = factory.buildPortDesc()
+                .setName("Eth1")
+                .setPortNo(OFPort.of(1))
+                .build();
+        return factory.buildPortDescStatsReply()
+            .setEntries(ImmutableList.<OFPortDesc>of(portDesc))
+            .build();
+    }
+
+
+    /** Move the channel from scratch to WAIT_CONFIG_REPLY state
+     * Builds on moveToWaitFeaturesReply
+     * adds testing for WAIT_FEATURES_REPLY state
+     */
+    @Test
+    public void moveToWaitPortDescStatsReply() throws Exception {
+        testInitState();
+
+        switchHandler.beginHandshake();
+
+        OFMessage msg = connection.retrieveMessage();
+        assertThat(msg, CoreMatchers.instanceOf(OFPortDescStatsRequest.class));
+        verifyUniqueXids(msg);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitPortDescStatsReplyState.class));
+    }
+
+    @Override
+    void moveToPreConfigReply() throws Exception {
+        moveToWaitPortDescStatsReply();
+        switchHandler.processOFMessage(getPortDescStatsReply());
+    }
+
+    public void handleDescStatsAndCreateSwitch() throws Exception {
+        // build the stats reply
+        OFDescStatsReply sr = createDescriptionStatsReply();
+
+        reset(sw);
+        SwitchDescription switchDescription = new SwitchDescription(sr);
+        setupSwitchForInstantiationWithReset();
+        sw.setPortDescStats(anyObject(OFPortDescStatsReply.class));
+        expectLastCall().once();
+        replay(sw);
+
+        reset(switchManager);
+        expect(switchManager.getHandshakePlugins()).andReturn(plugins).anyTimes();
+        expect(
+               switchManager.getOFSwitchInstance(anyObject(OFConnection.class),
+                                              eq(switchDescription),
+                                              anyObject(OFFactory.class),
+                                              anyObject(DatapathId.class))).andReturn(sw).once();
+        expect(switchManager.getNumRequiredConnections()).andReturn(0);
+        switchManager.switchAdded(sw);
+        expectLastCall().once();
+        replay(switchManager);
+
+        // send the description stats reply
+        switchHandler.processOFMessage(sr);
+
+        verify(sw, switchManager);
+    }
+
+    /** Move the channel from scratch to WAIT_DESCRIPTION_STAT_REPLY state
+     * Builds on moveToWaitConfigReply()
+     * adds testing for WAIT_CONFIG_REPLY state
+     */
+    @Test
+    public void moveToWaitOFAuxCxnsReply() throws Exception {
+        moveToWaitDescriptionStatReply();
+        handleDescStatsAndCreateSwitch();
+
+        OFMessage msg = connection.retrieveMessage();
+        assertThat(msg, CoreMatchers.instanceOf(OFBsnSetAuxCxnsRequest.class));
+        verifyUniqueXids(msg);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitOFAuxCxnsReplyState.class));
+
+    }
+
+    /** Move the channel from scratch to WAIT_DESCRIPTION_STAT_REPLY state
+     * Builds on moveToWaitConfigReply()
+     * adds testing for WAIT_CONFIG_REPLY state
+     */
+    @Test
+    public void moveToWaitGenDescStatsReply() throws Exception {
+        moveToWaitOFAuxCxnsReply();
+
+        // build the stats reply
+        OFBsnSetAuxCxnsReply auxReply = factory.buildBsnSetAuxCxnsReply()
+                .setNumAux(0)
+                .setStatus(0)
+                .build();
+
+        // send the description stats reply
+        switchHandler.processOFMessage(auxReply);
+        OFMessage msg = connection.retrieveMessage();
+        assertThat(msg, CoreMatchers.instanceOf(OFBsnGentableDescStatsRequest.class));
+        verifyUniqueXids(msg);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitGentableDescStatsReplyState.class));
+
+    }
+
+
+    /** This makes sure the correct behavior occurs for an illegal OF Aux Reply status
+     */
+    @Test
+    public void testOFAuxSwitchFail() throws Exception {
+        moveToWaitOFAuxCxnsReply();
+
+        // Build and OF Aux reply - status of non zero denotes failure on switch end
+        OFBsnSetAuxCxnsReply auxReply = factory.buildBsnSetAuxCxnsReply()
+                .setNumAux(0)
+                .setStatus(-1)
+                .build();
+
+        verifyExceptionCaptured(auxReply, OFAuxException.class);
+    }
+
+    @Test
+    @Override
+    public void moveToWaitAppHandshakeState() throws Exception {
+        moveToWaitGenDescStatsReply();
+
+        handleGenDescStatsReplay(true);
+
+        assertThat(switchHandler.getStateForTesting(),
+                   CoreMatchers.instanceOf(WaitAppHandshakeState.class));
+    }
+
+    private void handleGenDescStatsReplay(boolean driverHandshakeComplete) {
+        reset(sw);
+        Capture<GenTableMap> capGenTable = new Capture<>();
+        sw.setGenTableMap(capture(capGenTable));
+        expectLastCall().anyTimes();
+        sw.startDriverHandshake();
+        expectLastCall().once();
+        sw.isDriverHandshakeComplete();
+        expectLastCall().andReturn(driverHandshakeComplete).once();
+        expect(sw.getId()).andReturn(featuresReply.getDatapathId()).anyTimes();
+        replay(sw);
+
+        reset(switchManager);
+        expect(switchManager.getHandshakePlugins()).andReturn(plugins).anyTimes();
+        replay(switchManager);
+        OFBsnGentableDescStatsReply reply = createGenDescStatsReply();
+
+        switchHandler.processOFMessage(reply);
+    }
+
+    private OFBsnGentableDescStatsReply createGenDescStatsReply() {
+        OFBsnGentableDescStatsReply reply = factory.buildBsnGentableDescStatsReply()
+          .setEntries(
+                  ImmutableList.of(
+                          factory.buildBsnGentableDescStatsEntry()
+                              .setTableId(GenTableId.of(0))
+                              .setName("dhcp")
+                              .setBucketsSize(64)
+                              .setMaxEntries(4096)
+                              .build(),
+                          factory.buildBsnGentableDescStatsEntry()
+                              .setTableId(GenTableId.of(1))
+                              .setName("arp")
+                              .setMaxEntries(8192)
+                              .setBucketsSize(64)
+                              .build()
+                  ))
+           .build();
+        return reply;
+    }
+
+    @Override
+    Class<?> getRoleRequestClass() {
+        return OFRoleRequest.class;
+    }
+
+    @Override
+    public void verifyRoleRequest(OFMessage m, OFControllerRole expectedRole) {
+        assertThat(m, CoreMatchers.instanceOf(OFRoleRequest.class));
+        OFRoleRequest roleRequest = (OFRoleRequest) m;
+        assertThat(roleRequest.getRole(), equalTo(expectedRole));
+    }
+
+    @Override
+    protected OFMessage getRoleReply(long xid, OFControllerRole role) {
+        OFRoleReply roleReply = factory.buildRoleReply()
+                .setXid(xid)
+                .setRole(role)
+                .build();
+        return roleReply;
+    }
+
+    @Test
+    public void moveToWaitControllerCxnsReplyState() throws Exception {
+        moveToWaitAppHandshakeState();
+
+        assertThat(switchHandler.getStateForTesting(),
+                   CoreMatchers.instanceOf(WaitAppHandshakeState.class));
+
+
+        WaitAppHandshakeState state = (WaitAppHandshakeState) switchHandler.getStateForTesting();
+        PluginResult result = new PluginResult(PluginResultType.CONTINUE);
+        state.exitPlugin(result);
+
+        OFMessage msg = connection.retrieveMessage();
+        assertThat(msg, CoreMatchers.instanceOf(OFBsnControllerConnectionsRequest.class));
+        verifyUniqueXids(msg);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitControllerCxnsReplyState.class));
+    }
+
+    @Override
+    @Test
+    public void moveToWaitInitialRole()
+            throws Exception {
+        moveToWaitControllerCxnsReplyState();
+
+        assertThat(switchHandler.getStateForTesting(),
+                   CoreMatchers.instanceOf(WaitControllerCxnsReplyState.class));
+
+        OFBsnControllerConnection cxn = factory.buildBsnControllerConnection()
+                .setAuxiliaryId(OFAuxId.MAIN)
+                .setRole(OFControllerRole.ROLE_MASTER)
+                .setState(OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED)
+                .setUri(URIUtil.createURI("1.2.3.4", 6653).toString())
+                .build();
+
+        List<OFBsnControllerConnection> cxns = new ArrayList<OFBsnControllerConnection>();
+        cxns.add(cxn);
+
+        // build the controller connections reply
+        OFBsnControllerConnectionsReply cxnsReply = factory.buildBsnControllerConnectionsReply()
+                .setConnections(cxns)
+                .build();
+
+        reset(sw);
+        sw.updateControllerConnections(cxnsReply);
+        expectLastCall().once();
+        expect(sw.getAttribute(IOFSwitchBackend.SWITCH_SUPPORTS_NX_ROLE)).andReturn(true).anyTimes();
+        replay(sw);
+
+        reset(roleManager);
+        expect(roleManager.getOFControllerRole()).andReturn(OFControllerRole.ROLE_MASTER).anyTimes();
+        roleManager.notifyControllerConnectionUpdate();
+        expectLastCall().once();
+        replay(roleManager);
+
+        // send the controller connections reply
+        switchHandler.processOFMessage(cxnsReply);
+
+        // Expect wait initial role's enterState message to be written
+        OFMessage msg = connection.retrieveMessage();
+        assertThat(msg, CoreMatchers.instanceOf(OFRoleRequest.class));
+        verifyUniqueXids(msg);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitInitialRoleState.class));
+    }
+
+    @Override
+    @Test
+    public void moveToWaitSwitchDriverSubHandshake() throws Exception {
+        moveToWaitGenDescStatsReply();
+        handleGenDescStatsReplay(false);
+
+        assertThat(switchHandler.getStateForTesting(), CoreMatchers.instanceOf(OFSwitchHandshakeHandler.WaitSwitchDriverSubHandshakeState.class));
+        assertThat("Unexpected message captured", connection.getMessages(), Matchers.empty());
+        verify(sw);
+    }
+
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java
deleted file mode 100644
index e59a9d060899e856b6564d48cbf8527c90316a8c..0000000000000000000000000000000000000000
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java
+++ /dev/null
@@ -1,82 +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.internal;
-
-import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
-import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
-import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
-import net.floodlightcontroller.core.IFloodlightProviderService.Role;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.factory.BasicFactory;
-
-import static org.junit.Assert.*;
-
-public class OFSwitchImplTest {
-    protected OFSwitchImpl sw;
-
-
-    @Before
-    public void setUp() throws Exception {
-        sw = new OFSwitchImpl();
-    }
-
-    @Test
-    public void testSetHARoleReply() {
-
-        sw.setHARole(Role.MASTER);
-        assertEquals(Role.MASTER, sw.getHARole());
-
-        sw.setHARole(Role.EQUAL);
-        assertEquals(Role.EQUAL, sw.getHARole());
-
-        sw.setHARole(Role.SLAVE);
-        assertEquals(Role.SLAVE, sw.getHARole());
-    }
-
-    @Test
-    public void testSubHandshake() {
-        OFMessage m = BasicFactory.getInstance().getMessage(OFType.VENDOR);
-        // test execptions before handshake is started
-        try {
-            sw.processDriverHandshakeMessage(m);
-            fail("expected exception not thrown");
-        } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
-        try {
-            sw.isDriverHandshakeComplete();
-            fail("expected exception not thrown");
-        } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
-
-        // start the handshake -- it should immediately complete
-        sw.startDriverHandshake();
-        assertTrue("Handshake should be complete",
-                   sw.isDriverHandshakeComplete());
-
-        // test exceptions after handshake is completed
-        try {
-            sw.processDriverHandshakeMessage(m);
-            fail("expected exception not thrown");
-        } catch (SwitchDriverSubHandshakeCompleted e) { /* expected */ }
-        try {
-            sw.startDriverHandshake();
-            fail("Expected exception not thrown");
-        } catch (SwitchDriverSubHandshakeAlreadyStarted e) { /* expected */ }
-    }
-}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchManagerTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchManagerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e6a7389b7396e63546d7f9d907c973b4831ed9a
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchManagerTest.java
@@ -0,0 +1,840 @@
+/**
+*    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 static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.easymock.EasyMock.anyObject;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.jboss.netty.util.Timer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import net.floodlightcontroller.core.HARole;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+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.IShutdownListener;
+import net.floodlightcontroller.core.IShutdownService;
+import net.floodlightcontroller.core.LogicalOFMessageCategory;
+import net.floodlightcontroller.core.NullConnection;
+import net.floodlightcontroller.core.OFSwitch;
+import net.floodlightcontroller.core.PortChangeType;
+import net.floodlightcontroller.core.SwitchDescription;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.debugcounter.DebugCounterServiceImpl;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import net.floodlightcontroller.debugevent.DebugEventService;
+import net.floodlightcontroller.debugevent.IDebugEventService;
+import net.floodlightcontroller.restserver.IRestApiService;
+import net.floodlightcontroller.restserver.RestApiServer;
+import net.floodlightcontroller.storage.IStorageSourceService;
+import net.floodlightcontroller.storage.memory.MemoryStorageSource;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.threadpool.ThreadPool;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortFeatures;
+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 org.sdnplatform.sync.ISyncService;
+import org.sdnplatform.sync.test.MockSyncService;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class OFSwitchManagerTest{
+    private Controller controller;
+    private OFSwitchManager switchManager;
+
+    // FIXME:LOJI: For now just work with OF 1.0
+    private final OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
+    private static DatapathId DATAPATH_ID_0 = DatapathId.of(0);
+    private static DatapathId DATAPATH_ID_1 = DatapathId.of(1);
+
+    @Before
+    public void setUp() throws Exception {
+        doSetUp(HARole.ACTIVE);
+    }
+
+    public void doSetUp(HARole role) throws Exception {
+        FloodlightModuleContext fmc = new FloodlightModuleContext();
+
+        FloodlightProvider cm = new FloodlightProvider();
+        fmc.addConfigParam(cm, "role", role.toString());
+        controller = (Controller)cm.getServiceImpls().get(IFloodlightProviderService.class);
+        fmc.addService(IFloodlightProviderService.class, controller);
+
+        MemoryStorageSource memstorage = new MemoryStorageSource();
+        fmc.addService(IStorageSourceService.class, memstorage);
+        
+        RestApiServer restApi = new RestApiServer();
+        fmc.addService(IRestApiService.class, restApi);
+        
+        ThreadPool threadPool = new ThreadPool();
+        fmc.addService(IThreadPoolService.class, threadPool);
+        
+        // TODO: should mock IDebugCounterService and make sure
+        // the expected counters are updated.
+        DebugCounterServiceImpl debugCounterService = new DebugCounterServiceImpl();
+        fmc.addService(IDebugCounterService.class, debugCounterService);
+
+        DebugEventService debugEventService = new DebugEventService();
+        fmc.addService(IDebugEventService.class, debugEventService);
+
+        switchManager = new OFSwitchManager();
+        fmc.addService(IOFSwitchService.class, switchManager);
+
+        MockSyncService syncService = new MockSyncService();
+        fmc.addService(ISyncService.class, syncService);
+
+        IShutdownService shutdownService = createMock(IShutdownService.class);
+        shutdownService.registerShutdownListener(anyObject(IShutdownListener.class));
+        expectLastCall().anyTimes();
+        replay(shutdownService);
+        fmc.addService(IShutdownService.class, shutdownService);
+        verify(shutdownService);
+
+        threadPool.init(fmc);
+        syncService.init(fmc);
+        switchManager.init(fmc);
+        debugCounterService.init(fmc);
+        debugEventService.init(fmc);
+        restApi.init(fmc);
+        cm.init(fmc);
+
+        syncService.init(fmc);
+        switchManager.startUpBase(fmc);
+        debugCounterService.startUp(fmc);
+        debugEventService.startUp(fmc);
+        threadPool.startUp(fmc);
+        restApi.startUp(fmc);
+        cm.startUp(fmc);
+    }
+
+    @After
+    public void tearDown(){
+
+    }
+
+    public Controller getController() {
+        return controller;
+    }
+
+    private static SwitchDescription createSwitchDescription() {
+        return new SwitchDescription();
+    }
+
+    private OFFeaturesReply createOFFeaturesReply(DatapathId datapathId) {
+        OFFeaturesReply fr = factory.buildFeaturesReply()
+                .setXid(0)
+                .setDatapathId(datapathId)
+                .setPorts(ImmutableList.<OFPortDesc>of())
+                .build();
+        return fr;
+    }
+
+
+    /** Set the mock expectations for sw when sw is passed to addSwitch
+     * The same expectations can be used when a new SwitchSyncRepresentation
+     * is created from the given mocked switch */
+    protected void setupSwitchForAddSwitch(IOFSwitch sw, DatapathId datapathId,
+            SwitchDescription description, OFFeaturesReply featuresReply) {
+        String dpidString = datapathId.toString();
+        if (description == null) {
+            description = createSwitchDescription();
+        }
+        if (featuresReply == null) {
+            featuresReply = createOFFeaturesReply(datapathId);
+        }
+        List<OFPortDesc> ports = featuresReply.getPorts();
+
+        expect(sw.getOFFactory()).andReturn(OFFactories.getFactory(OFVersion.OF_10)).anyTimes();
+        expect(sw.getStatus()).andReturn(SwitchStatus.MASTER).anyTimes();
+        expect(sw.getId()).andReturn(datapathId).anyTimes();
+        expect(sw.getStringId()).andReturn(dpidString).anyTimes();
+        expect(sw.getSwitchDescription()).andReturn(description).anyTimes();
+        expect(sw.getBuffers())
+                .andReturn(featuresReply.getNBuffers()).anyTimes();
+        expect(sw.getTables())
+                .andReturn(featuresReply.getNTables()).anyTimes();
+        expect(sw.getCapabilities())
+                .andReturn(featuresReply.getCapabilities()).anyTimes();
+        expect(sw.getActions())
+                .andReturn(featuresReply.getActions()).anyTimes();
+        expect(sw.getPorts())
+                .andReturn(ports).anyTimes();
+        expect(sw.attributeEquals(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true))
+                .andReturn(false).anyTimes();
+        expect(sw.getInetAddress()).andReturn(null).anyTimes();
+    }
+
+    @Test
+    /**
+     * Test switchActivated for a new switch, i.e., a switch that was not
+     * previously known to the controller cluser. We expect that all
+     * flow mods are cleared and we expect a switchAdded
+     */
+    public void testNewSwitchActivated() throws Exception {
+
+        IOFSwitchBackend sw = createMock(IOFSwitchBackend.class);
+        setupSwitchForAddSwitch(sw, DATAPATH_ID_0, null, null);
+
+        // Ensure switch doesn't already exist
+        assertNull(switchManager.getSwitch(DATAPATH_ID_0));
+
+        // strict mock. Order of events matters!
+        IOFSwitchListener listener = createStrictMock(IOFSwitchListener.class);
+        listener.switchAdded(DATAPATH_ID_0);
+        expectLastCall().once();
+        listener.switchActivated(DATAPATH_ID_0);
+        expectLastCall().once();
+        replay(listener);
+        switchManager.addOFSwitchListener(listener);
+        replay(sw);
+        switchManager.switchAdded(sw);
+        switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+        verify(sw);
+
+        assertEquals(sw, switchManager.getSwitch(DATAPATH_ID_0));
+        controller.processUpdateQueueForTesting();
+        verify(listener);
+    }
+
+    /**
+     * Test switchActivated for a new switch while in slave: disconnect the switch
+     */
+    @Test
+    public void testNewSwitchActivatedWhileSlave() throws Exception {
+        doSetUp(HARole.STANDBY);
+        IOFSwitchBackend sw = createMock(IOFSwitchBackend.class);
+
+        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
+        switchManager.addOFSwitchListener(listener);
+
+        expect(sw.getId()).andReturn(DATAPATH_ID_0).anyTimes();
+        expect(sw.getStatus()).andReturn(SwitchStatus.MASTER).anyTimes();
+        sw.disconnect();
+        expectLastCall().once();
+        replay(sw, listener); // nothing recorded
+        switchManager.switchAdded(sw);
+        switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+        verify(sw);
+        controller.processUpdateQueueForTesting();
+        verify(listener);
+    }
+
+
+    /**
+     * Create and activate a switch, either completely new or reconnected
+     * The mocked switch instance will be returned. It will be reset.
+     */
+    private IOFSwitchBackend doActivateSwitchInt(DatapathId datapathId,
+                                          SwitchDescription description,
+                                          OFFeaturesReply featuresReply,
+                                          boolean clearFlows)
+                                          throws Exception {
+
+        IOFSwitchBackend sw = createMock(IOFSwitchBackend.class);
+        if (featuresReply == null) {
+            featuresReply = createOFFeaturesReply(datapathId);
+        }
+        if (description == null) {
+            description = createSwitchDescription();
+        }
+        setupSwitchForAddSwitch(sw, datapathId, description, featuresReply);
+        replay(sw);
+        switchManager.switchAdded(sw);
+        switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+        verify(sw);
+        assertEquals(sw, switchManager.getSwitch(datapathId));
+        // drain updates and ignore
+        controller.processUpdateQueueForTesting();
+
+        reset(sw);
+        return sw;
+    }
+
+    /**
+     * Create and activate a new switch with the given dpid, features reply
+     * and description. If description and/or features reply are null we'll
+     * allocate the default one
+     * The mocked switch instance will be returned. It wil be reset.
+     */
+    private IOFSwitchBackend doActivateNewSwitch(DatapathId dpid,
+                                          SwitchDescription description,
+                                          OFFeaturesReply featuresReply)
+                                          throws Exception {
+        return doActivateSwitchInt(dpid, description, featuresReply, true);
+    }
+
+    /**
+     * Remove a nonexisting switch. should be ignored
+     */
+    @Test
+    public void testNonexistingSwitchDisconnected() throws Exception {
+        IOFSwitchBackend sw = createMock(IOFSwitchBackend.class);
+        expect(sw.getId()).andReturn(DATAPATH_ID_1).anyTimes();
+        expect(sw.getStringId()).andReturn(DATAPATH_ID_1.toString()).anyTimes();
+        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
+        switchManager.addOFSwitchListener(listener);
+        replay(sw, listener);
+        switchManager.switchDisconnected(sw);
+        controller.processUpdateQueueForTesting();
+        verify(sw, listener);
+
+        assertNull(switchManager.getSwitch(DATAPATH_ID_1));
+    }
+
+    /**
+     * Try to remove a switch that's different from what's in the active
+     * switch map. Should be ignored
+     */
+    @Test
+    public void testSwitchDisconnectedOther() throws Exception {
+        IOFSwitch origSw = doActivateNewSwitch(DATAPATH_ID_1, null, null);
+        // create a new mock switch
+        IOFSwitchBackend sw = createMock(IOFSwitchBackend.class);
+        expect(sw.getId()).andReturn(DATAPATH_ID_1).anyTimes();
+        expect(sw.getStringId()).andReturn(DATAPATH_ID_1.toString()).anyTimes();
+        IOFSwitchListener listener = createMock(IOFSwitchListener.class);
+        switchManager.addOFSwitchListener(listener);
+        replay(sw, listener);
+        switchManager.switchDisconnected(sw);
+        controller.processUpdateQueueForTesting();
+        verify(sw, listener);
+
+        expect(origSw.getStatus()).andReturn(SwitchStatus.MASTER).anyTimes();
+        replay(origSw);
+        assertSame(origSw, switchManager.getSwitch(DATAPATH_ID_1));
+    }
+
+
+
+    /**
+     * Try to activate a switch that's already active (which can happen if
+     * two different switches have the same DPIP or if a switch reconnects
+     * while the old TCP connection is still alive
+     */
+    @Test
+    public void testSwitchActivatedWithAlreadyActiveSwitch() throws Exception {
+        SwitchDescription oldDescription = new SwitchDescription(
+                "", "", "", "", "Ye Olde Switch");
+        SwitchDescription newDescription = new SwitchDescription(
+                "", "", "", "", "The new Switch");
+        OFFeaturesReply featuresReply = createOFFeaturesReply(DATAPATH_ID_0);
+
+
+        // Setup: add a switch to the controller
+        IOFSwitchBackend oldsw = createMock(IOFSwitchBackend.class);
+        setupSwitchForAddSwitch(oldsw, DATAPATH_ID_0, oldDescription, featuresReply);
+        replay(oldsw);
+        switchManager.switchAdded(oldsw);
+        switchManager.switchStatusChanged(oldsw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+        verify(oldsw);
+        // drain the queue, we don't care what's in it
+        controller.processUpdateQueueForTesting();
+        assertEquals(oldsw, switchManager.getSwitch(DATAPATH_ID_0));
+
+        // Now the actual test: add a new switch with the same dpid to
+        // the controller
+        reset(oldsw);
+        expect(oldsw.getId()).andReturn(DATAPATH_ID_0).anyTimes();
+        oldsw.cancelAllPendingRequests();
+        expectLastCall().once();
+        oldsw.disconnect();
+        expectLastCall().once();
+
+
+        IOFSwitchBackend newsw = createMock(IOFSwitchBackend.class);
+        setupSwitchForAddSwitch(newsw, DATAPATH_ID_0, newDescription, featuresReply);
+
+        // Strict mock. We need to get the removed notification before the
+        // add notification
+        IOFSwitchListener listener = createStrictMock(IOFSwitchListener.class);
+        listener.switchRemoved(DATAPATH_ID_0);
+        listener.switchAdded(DATAPATH_ID_0);
+        listener.switchActivated(DATAPATH_ID_0);
+        replay(listener);
+        switchManager.addOFSwitchListener(listener);
+
+
+        replay(newsw, oldsw);
+        switchManager.switchAdded(newsw);
+        switchManager.switchStatusChanged(newsw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+        verify(newsw, oldsw);
+
+        assertEquals(newsw, switchManager.getSwitch(DATAPATH_ID_0));
+        controller.processUpdateQueueForTesting();
+        verify(listener);
+    }
+
+
+
+    /**
+    * Tests that you can't remove a switch from the map returned by
+    * getSwitches() (because getSwitches should return an unmodifiable
+    * map)
+    */
+   @Test
+   public void testRemoveActiveSwitch() {
+       IOFSwitchBackend sw = createNiceMock(IOFSwitchBackend.class);
+       setupSwitchForAddSwitch(sw, DATAPATH_ID_1, null, null);
+       replay(sw);
+       switchManager.switchAdded(sw);
+       switchManager.switchStatusChanged(sw, SwitchStatus.HANDSHAKE, SwitchStatus.MASTER);
+       assertEquals(sw, switchManager.getSwitch(DATAPATH_ID_1));
+       try {
+           switchManager.getAllSwitchMap().remove(DATAPATH_ID_1);
+           fail("Expected: UnsupportedOperationException");
+       } catch(UnsupportedOperationException e) {
+           // expected
+       }
+       // we don't care for updates. drain queue.
+       controller.processUpdateQueueForTesting();
+   }
+
+   /**
+    * Tests that the switch manager should only return a switch to a getActiveSwitch
+    * call when the switch is visible/active.
+    */
+   @Test
+   public void testGetActiveSwitch() {
+       MockOFConnection connection = new MockOFConnection(DATAPATH_ID_1, OFAuxId.MAIN);
+       IOFSwitchBackend sw = new MockOFSwitchImpl(connection);
+       sw.setStatus(SwitchStatus.HANDSHAKE);
+
+       assertNull(switchManager.getActiveSwitch(DATAPATH_ID_1));
+       switchManager.switchAdded(sw);
+       assertNull(switchManager.getActiveSwitch(DATAPATH_ID_1));
+       sw.setStatus(SwitchStatus.MASTER);
+       assertEquals(sw, switchManager.getActiveSwitch(DATAPATH_ID_1));
+       sw.setStatus(SwitchStatus.QUARANTINED);
+       assertNull(switchManager.getActiveSwitch(DATAPATH_ID_1));
+       sw.setStatus(SwitchStatus.SLAVE);
+       assertEquals(sw, switchManager.getActiveSwitch(DATAPATH_ID_1));
+       sw.setStatus(SwitchStatus.DISCONNECTED);
+       assertNull(switchManager.getActiveSwitch(DATAPATH_ID_1));
+       // we don't care for updates. drain queue.
+       controller.processUpdateQueueForTesting();
+   }
+
+   /**
+    * Test that notifyPortChanged() results in an IOFSwitchListener
+    * update and that its arguments are passed through to
+    * the listener call
+    */
+   @Test
+   public void testNotifySwitchPortChanged() throws Exception {
+       DatapathId dpid = DatapathId.of(42);
+
+       OFPortDesc p1 = factory.buildPortDesc()
+               .setName("Port1")
+               .setPortNo(OFPort.of(1))
+               .build();
+       OFFeaturesReply fr1 = factory.buildFeaturesReply()
+               .setXid(0)
+               .setDatapathId(dpid)
+               .setPorts(ImmutableList.<OFPortDesc>of(p1))
+               .build();
+
+       OFPortDesc p2 = factory.buildPortDesc()
+               .setName("Port1")
+               .setPortNo(OFPort.of(1))
+               .setAdvertised(ImmutableSet.<OFPortFeatures>of(OFPortFeatures.PF_100MB_FD))
+               .build();
+       OFFeaturesReply fr2 = factory.buildFeaturesReply()
+               .setXid(0)
+               .setDatapathId(dpid)
+               .setPorts(ImmutableList.<OFPortDesc>of(p2))
+               .build();
+
+       SwitchDescription desc = createSwitchDescription();
+
+       // activate switch
+       IOFSwitchBackend sw = doActivateNewSwitch(dpid, desc, fr1);
+
+       IOFSwitchListener listener = createMock(IOFSwitchListener.class);
+       switchManager.addOFSwitchListener(listener);
+       // setup switch with the new, second features reply (and thus ports)
+       setupSwitchForAddSwitch(sw, dpid, desc, fr2);
+       listener.switchPortChanged(dpid, p2,
+                                  PortChangeType.OTHER_UPDATE);
+       expectLastCall().once();
+       replay(listener);
+       replay(sw);
+       switchManager.notifyPortChanged(sw, p2,
+                                    PortChangeType.OTHER_UPDATE);
+       controller.processUpdateQueueForTesting();
+       verify(listener);
+       verify(sw);
+
+   }
+
+    /**
+     * Test the driver registry: test the bind order
+     */
+    @Test
+    public void testSwitchDriverRegistryBindOrder() {
+        IOFSwitchDriver driver1 = createMock(IOFSwitchDriver.class);
+        IOFSwitchDriver driver2 = createMock(IOFSwitchDriver.class);
+        IOFSwitchDriver driver3 = createMock(IOFSwitchDriver.class);
+        IOFSwitchBackend returnedSwitch = null;
+        IOFSwitchBackend mockSwitch = createMock(IOFSwitchBackend.class);
+        switchManager.addOFSwitchDriver("", driver3);
+        switchManager.addOFSwitchDriver("test switch", driver1);
+        switchManager.addOFSwitchDriver("test", driver2);
+
+        replay(driver1);
+        replay(driver2);
+        replay(driver3);
+        replay(mockSwitch);
+
+        SwitchDescription description = new SwitchDescription(
+                "test switch", "version 0.9", "", "", "");
+        reset(driver1);
+        reset(driver2);
+        reset(driver3);
+        reset(mockSwitch);
+        mockSwitch.setSwitchProperties(description);
+        expectLastCall().once();
+        OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
+        expect(driver1.getOFSwitchImpl(description, factory)).andReturn(mockSwitch).once();
+        replay(driver1);
+        replay(driver2);
+        replay(driver3);
+        replay(mockSwitch);
+        returnedSwitch = switchManager.getOFSwitchInstance(new NullConnection(), description, factory, DatapathId.of(1));
+        assertSame(mockSwitch, returnedSwitch);
+        verify(driver1);
+        verify(driver2);
+        verify(driver3);
+        verify(mockSwitch);
+
+        description = new SwitchDescription(
+                "testFooBar", "version 0.9", "", "", "");
+        reset(driver1);
+        reset(driver2);
+        reset(driver3);
+        reset(mockSwitch);
+        mockSwitch.setSwitchProperties(description);
+        expectLastCall().once();
+        expect(driver2.getOFSwitchImpl(description, factory)).andReturn(mockSwitch).once();
+        replay(driver1);
+        replay(driver2);
+        replay(driver3);
+        replay(mockSwitch);
+        returnedSwitch = switchManager.getOFSwitchInstance(new NullConnection(), description,
+                OFFactories.getFactory(OFVersion.OF_10), DatapathId.of(1));
+        assertSame(mockSwitch, returnedSwitch);
+        verify(driver1);
+        verify(driver2);
+        verify(driver3);
+        verify(mockSwitch);
+
+        description = new SwitchDescription(
+                "FooBar", "version 0.9", "", "", "");
+        reset(driver1);
+        reset(driver2);
+        reset(driver3);
+        reset(mockSwitch);
+        mockSwitch.setSwitchProperties(description);
+        expectLastCall().once();
+        expect(driver3.getOFSwitchImpl(description, factory)).andReturn(mockSwitch).once();
+        replay(driver1);
+        replay(driver2);
+        replay(driver3);
+        replay(mockSwitch);
+        returnedSwitch = switchManager.getOFSwitchInstance(new NullConnection(), description, factory, DatapathId.of(1));
+        assertSame(mockSwitch, returnedSwitch);
+        verify(driver1);
+        verify(driver2);
+        verify(driver3);
+        verify(mockSwitch);
+    }
+
+    /**
+     * Test SwitchDriverRegistry
+     * Test fallback to default if no switch driver is registered for a
+     * particular prefix
+     */
+    @Test
+    public void testSwitchDriverRegistryNoDriver() {
+        IOFSwitchDriver driver = createMock(IOFSwitchDriver.class);
+        IOFSwitch returnedSwitch = null;
+        IOFSwitchBackend mockSwitch = createMock(IOFSwitchBackend.class);
+        switchManager.addOFSwitchDriver("test switch", driver);
+
+        replay(driver);
+        replay(mockSwitch);
+
+        SwitchDescription desc = new SwitchDescription("test switch", "version 0.9", "", "", "");
+        reset(driver);
+        reset(mockSwitch);
+        mockSwitch.setSwitchProperties(desc);
+        expectLastCall().once();
+        expect(driver.getOFSwitchImpl(desc, factory)).andReturn(mockSwitch).once();
+        replay(driver);
+        replay(mockSwitch);
+        returnedSwitch = switchManager.getOFSwitchInstance(new NullConnection(), desc, factory, DatapathId.of(1));
+        assertSame(mockSwitch, returnedSwitch);
+        verify(driver);
+        verify(mockSwitch);
+
+        desc = new SwitchDescription("Foo Bar test switch", "version 0.9", "", "", "");
+        reset(driver);
+        reset(mockSwitch);
+        replay(driver);
+        replay(mockSwitch);
+        returnedSwitch = switchManager.getOFSwitchInstance(new NullConnection(), desc,
+                OFFactories.getFactory(OFVersion.OF_10), DatapathId.of(1));
+        assertNotNull(returnedSwitch);
+        assertTrue("Returned switch should be OFSwitch",
+                   returnedSwitch instanceof OFSwitch);
+        assertEquals(desc, returnedSwitch.getSwitchDescription());
+        verify(driver);
+        verify(mockSwitch);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testDriverRegistryExceptions() {
+        IOFSwitchDriver driver = createMock(IOFSwitchDriver.class);
+        IOFSwitchDriver driver2 = createMock(IOFSwitchDriver.class);
+        replay(driver, driver2); // no calls expected on driver
+
+        //---------------
+        // Test exception handling when registering driver
+        try {
+            switchManager.addOFSwitchDriver("foobar", null);
+            fail("Expected NullPointerException not thrown");
+        } catch (NullPointerException e) {
+            //expected
+        }
+
+        try {
+            switchManager.addOFSwitchDriver(null, driver);
+            fail("Expected NullPointerException not thrown");
+        } catch (NullPointerException e) {
+            //expected
+        }
+
+        // test that we can register each prefix only once!
+        switchManager.addOFSwitchDriver("foobar",  driver);
+        try {
+            switchManager.addOFSwitchDriver("foobar",  driver);
+            fail("Expected IllegalStateException not thrown");
+        } catch (IllegalStateException e) {
+            //expected
+        }
+
+        try {
+            switchManager.addOFSwitchDriver("foobar",  driver2);
+            fail("Expected IllegalStateException not thrown");
+        } catch (IllegalStateException e) {
+            //expected
+        }
+
+        //OFDescStatsReply desc = createOFDescStatsReply();
+        //desc.setDatapathDescription(null);
+        SwitchDescription description = new SwitchDescription(null, "", "", "", "");
+        try {
+            switchManager.getOFSwitchInstance(null, description,
+                    OFFactories.getFactory(OFVersion.OF_10), DatapathId.of(1));
+            fail("Expected NullPointerException not thrown");
+        } catch (NullPointerException e) {
+            //expected
+        }
+        description = new SwitchDescription("", null, "", "", "");
+        try {
+            switchManager.getOFSwitchInstance(null, description,
+                    OFFactories.getFactory(OFVersion.OF_10), DatapathId.of(1));
+            fail("Expected NullPointerException not thrown");
+        } catch (NullPointerException e) {
+            //expected
+        }
+        description = new SwitchDescription("", "", null, "", "");
+        try {
+            switchManager.getOFSwitchInstance(null, description,
+                    OFFactories.getFactory(OFVersion.OF_10), DatapathId.of(1));
+            fail("Expected NullPointerException not thrown");
+        } catch (NullPointerException e) {
+            //expected
+        }
+        description = new SwitchDescription("", "", "", null, "");
+        try {
+            switchManager.getOFSwitchInstance(null, description,
+                    OFFactories.getFactory(OFVersion.OF_10), DatapathId.of(1));
+            fail("Expected NullPointerException not thrown");
+        } catch (NullPointerException e) {
+            //expected
+        }
+        description = new SwitchDescription("", "", "", "", null);
+        try {
+            switchManager.getOFSwitchInstance(null, description,
+                    OFFactories.getFactory(OFVersion.OF_10), DatapathId.of(1));
+            fail("Expected NullPointerException not thrown");
+        } catch (NullPointerException e) {
+            //expected
+
+        }
+        verify(driver, driver2);
+    }
+
+    @Test
+    public void testRegisterCategory() {
+
+        // Must be in INIT state
+        Timer timer = createMock(Timer.class);
+        replay(timer);
+        switchManager = new OFSwitchManager();
+        switchManager.loadLogicalCategories();
+        assertTrue("Connections should be empty", switchManager.getNumRequiredConnections() == 0);
+
+        // Add initial category
+        switchManager = new OFSwitchManager();
+        LogicalOFMessageCategory category = new LogicalOFMessageCategory("aux1", 1);
+        switchManager.registerLogicalOFMessageCategory(category);
+        switchManager.loadLogicalCategories();
+
+        assertTrue("Required connections should be 1", switchManager.getNumRequiredConnections() == 1);
+
+        // Multiple categories on the same auxId should produce one required connection
+        switchManager = new OFSwitchManager();
+        switchManager.registerLogicalOFMessageCategory(new LogicalOFMessageCategory("aux1", 1));
+        switchManager.registerLogicalOFMessageCategory(new LogicalOFMessageCategory("aux1-2", 1));
+        switchManager.loadLogicalCategories();
+
+        assertTrue("Required connections should be 1", switchManager.getNumRequiredConnections() == 1);
+
+        // Adding a category on a different aux ID should increase the required connection count
+        switchManager = new OFSwitchManager();
+        switchManager.registerLogicalOFMessageCategory(new LogicalOFMessageCategory("aux1", 1));
+        switchManager.registerLogicalOFMessageCategory(new LogicalOFMessageCategory("aux2", 2));
+        switchManager.loadLogicalCategories();
+        assertTrue("Required connections should be 2", switchManager.getNumRequiredConnections() == 2);
+    }
+
+    @Test
+    public void testRegisterCategoryException() {
+
+        switchManager = new OFSwitchManager();
+        switchManager.loadLogicalCategories();
+        LogicalOFMessageCategory category = new LogicalOFMessageCategory("test", 1);
+
+        // Wrong State
+        try {
+            switchManager.registerLogicalOFMessageCategory(category);
+            fail("Expected Unsupported Operation Exception not thrown");
+        } catch (UnsupportedOperationException e) { /* expected */ }
+
+        switchManager = new OFSwitchManager();
+
+        // Categories must have category with auxid of 1
+        LogicalOFMessageCategory bad = new LogicalOFMessageCategory("bad", 2);
+        switchManager.registerLogicalOFMessageCategory(bad);
+
+        try{
+            switchManager.loadLogicalCategories();
+            fail("Expected exception not thrown");
+        } catch (IllegalStateException e) { /* expected */}
+
+        // Non contiguous category auxids of (1,3)
+        switchManager = new OFSwitchManager();
+        switchManager.registerLogicalOFMessageCategory(category);
+        LogicalOFMessageCategory nonContiguous = new LogicalOFMessageCategory("bad", 3);
+        switchManager.registerLogicalOFMessageCategory(nonContiguous);
+
+        try{
+            switchManager.loadLogicalCategories();
+            fail("Expected exception not thrown");
+        } catch (IllegalStateException e) { /* expected */}
+    }
+
+    @Test
+    public void testNewConnectionOpened() {
+        MockOFConnection connection = new MockOFConnection(DATAPATH_ID_1, OFAuxId.MAIN);
+        OFFeaturesReply featuresReply = createOFFeaturesReply(DATAPATH_ID_1);
+
+        // Assert no switch handlers
+        assertTrue(switchManager.getSwitchHandshakeHandlers().isEmpty());
+        switchManager.connectionOpened(connection, featuresReply);
+        // Ensure a
+        assertTrue(switchManager.getSwitchHandshakeHandlers().size() == 1);
+        assertTrue(switchManager.getSwitchHandshakeHandlers().get(0).getDpid().equals(DATAPATH_ID_1));
+    }
+
+    @Test
+    public void testDuplicateConnectionOpened() {
+        // Seed with 1 connection and handler
+        testNewConnectionOpened();
+
+        MockOFConnection connection = new MockOFConnection(DATAPATH_ID_1, OFAuxId.MAIN);
+        OFFeaturesReply featuresReply = createOFFeaturesReply(DATAPATH_ID_1);
+
+        switchManager.connectionOpened(connection, featuresReply);
+
+        // Ensure duplicate connections are
+        assertTrue(switchManager.getSwitchHandshakeHandlers().size() == 1);
+        assertTrue(switchManager.getSwitchHandshakeHandlers().get(0).getDpid().equals(DATAPATH_ID_1));
+    }
+
+    @Test
+    public void testHandshakeDisconnected() {
+        // Seed with 1 connection and handler
+        testNewConnectionOpened();
+
+        assertTrue(switchManager.getSwitchHandshakeHandlers().size() == 1);
+        // Disconnect wrong handshake
+        switchManager.handshakeDisconnected(DATAPATH_ID_0);
+        assertTrue(switchManager.getSwitchHandshakeHandlers().size() == 1);
+        // Disconnect correct handshake
+        switchManager.handshakeDisconnected(DATAPATH_ID_1);
+        assertTrue(switchManager.getSwitchHandshakeHandlers().size() == 0);
+
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b5ca01ed6884656e520c40ccd5cc284e88eae5f9
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchTest.java
@@ -0,0 +1,163 @@
+/**
+ *    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.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import net.floodlightcontroller.core.IOFSwitchBackend;
+import net.floodlightcontroller.core.OFSwitch;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
+import net.floodlightcontroller.core.util.URIUtil;
+import org.projectfloodlight.openflow.protocol.OFBsnControllerConnection;
+import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionState;
+import org.projectfloodlight.openflow.protocol.OFBsnControllerConnectionsReply;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFAuxId;
+
+public class OFSwitchTest {
+    protected OFSwitch sw;
+    protected OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
+
+    @Before
+    public void setUp() throws Exception {
+        MockOFConnection mockConnection = new MockOFConnection(DatapathId.of(1), OFAuxId.MAIN);
+        sw = new OFSwitch(mockConnection, OFFactories.getFactory(OFVersion.OF_10),
+                EasyMock.createMock(IOFSwitchManager.class), DatapathId.of(1));
+    }
+
+    @Test
+    public void testSetHARoleReply() {
+        sw.setControllerRole(OFControllerRole.ROLE_MASTER);
+        assertEquals(OFControllerRole.ROLE_MASTER, sw.getControllerRole());
+
+        sw.setControllerRole(OFControllerRole.ROLE_EQUAL);
+        assertEquals(OFControllerRole.ROLE_EQUAL, sw.getControllerRole());
+
+        sw.setControllerRole(OFControllerRole.ROLE_SLAVE);
+        assertEquals(OFControllerRole.ROLE_SLAVE, sw.getControllerRole());
+    }
+
+    @Test
+    public void testSubHandshake() {
+        OFFactory factory = OFFactories.getFactory(OFVersion.OF_10);
+        OFMessage m = factory.buildNiciraControllerRoleReply()
+                .setXid(1)
+                .setRole(OFNiciraControllerRole.ROLE_MASTER)
+                .build();
+        // test exceptions before handshake is started
+        try {
+            sw.processDriverHandshakeMessage(m);
+            fail("expected exception not thrown");
+        } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
+        try {
+            sw.isDriverHandshakeComplete();
+            fail("expected exception not thrown");
+        } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
+
+        // start the handshake -- it should immediately complete
+        sw.startDriverHandshake();
+        assertTrue("Handshake should be complete",
+                   sw.isDriverHandshakeComplete());
+
+        // test exceptions after handshake is completed
+        try {
+            sw.processDriverHandshakeMessage(m);
+            fail("expected exception not thrown");
+        } catch (SwitchDriverSubHandshakeCompleted e) { /* expected */ }
+        try {
+            sw.startDriverHandshake();
+            fail("Expected exception not thrown");
+        } catch (SwitchDriverSubHandshakeAlreadyStarted e) { /* expected */ }
+    }
+
+    /**
+     * Helper to load controller connection messages into a switch for testing.
+     * @param sw the switch to insert the message on
+     * @param role the role for the controller connection message
+     * @param state the state for the controller connection message
+     * @param uri the URI for the controller connection message
+     */
+    public void updateControllerConnections(IOFSwitchBackend sw, OFControllerRole role1, OFBsnControllerConnectionState state1, String uri1
+                                            ,  OFControllerRole role2, OFBsnControllerConnectionState state2, String uri2) {
+        OFBsnControllerConnection connection1 = factory.buildBsnControllerConnection()
+                .setAuxiliaryId(OFAuxId.MAIN)
+                .setRole(role1)
+                .setState(state1)
+                .setUri(uri1)
+                .build();
+
+        OFBsnControllerConnection connection2 = factory.buildBsnControllerConnection()
+                .setAuxiliaryId(OFAuxId.MAIN)
+                .setRole(role2)
+                .setState(state2)
+                .setUri(uri2)
+                .build();
+
+        List<OFBsnControllerConnection> connections = new ArrayList<OFBsnControllerConnection>();
+        connections.add(connection1);
+        connections.add(connection2);
+
+        OFBsnControllerConnectionsReply reply = factory.buildBsnControllerConnectionsReply()
+                .setConnections(connections)
+                .build();
+
+        sw.updateControllerConnections(reply);
+    }
+
+    /**
+     * This test ensures that the switch accurately determined if another master
+     * exists in the cluster by examining the controller connections it has.
+     */
+    @Test
+    public void testHasAnotherMaster() {
+        URI cokeUri = URIUtil.createURI("1.2.3.4", 6653);
+        InetSocketAddress address = (InetSocketAddress) sw.getConnection(OFAuxId.MAIN).getLocalInetAddress();
+        URI pepsiUri = URIUtil.createURI(address.getHostName(), address.getPort());
+
+        updateControllerConnections(sw, OFControllerRole.ROLE_SLAVE, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, cokeUri.toString(),
+                                    OFControllerRole.ROLE_MASTER, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, pepsiUri.toString());
+
+        // From the perspective of pepsi, the cluster currently does NOT have another master controller
+        assertFalse(sw.hasAnotherMaster());
+
+        // Switch the controller connections so that pepsi is no longer master
+        updateControllerConnections(sw, OFControllerRole.ROLE_MASTER, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, cokeUri.toString(),
+                                    OFControllerRole.ROLE_SLAVE, OFBsnControllerConnectionState.BSN_CONTROLLER_CONNECTION_STATE_CONNECTED, pepsiUri.toString());
+
+        // From the perspective of pepsi, the cluster currently has another master controller
+        assertTrue(sw.hasAnotherMaster());
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/RoleManagerTest.java b/src/test/java/net/floodlightcontroller/core/internal/RoleManagerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..861574b29ce04bde74fbfb1e220f45e559ead3ca
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/internal/RoleManagerTest.java
@@ -0,0 +1,236 @@
+/**
+*    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 static org.easymock.EasyMock.anyObject;
+import static org.junit.Assert.*;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import net.floodlightcontroller.test.FloodlightTestCase;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+
+import java.util.HashMap;
+
+import org.junit.After;
+
+import net.floodlightcontroller.core.HARole;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitchBackend;
+import net.floodlightcontroller.core.IShutdownService;
+import net.floodlightcontroller.core.internal.Controller.IUpdate;
+import net.floodlightcontroller.core.test.MockSwitchManager;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import net.floodlightcontroller.debugcounter.MockDebugCounterService;
+import org.projectfloodlight.openflow.types.DatapathId;
+
+public class RoleManagerTest extends FloodlightTestCase {
+    private Controller controller;
+    private RoleManager roleManager;
+
+    private static DatapathId DATAPATH_ID_1 = DatapathId.of(1);
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        doSetUp(HARole.ACTIVE);
+    }
+
+    private void doSetUp(HARole role) {
+        controller = createMock(Controller.class);
+
+        // Mock controller behavior
+        reset(controller);
+        IDebugCounterService counterService = new MockDebugCounterService();
+        expect(controller.getDebugCounter()).andReturn(counterService).anyTimes();
+        replay(controller);
+
+
+        IShutdownService shutdownService = createMock(IShutdownService.class);
+        roleManager = new RoleManager(controller, shutdownService , role, "test");
+
+        // Make sure the desired role is set
+        assertTrue(roleManager.getRole().equals(role));
+    }
+
+    @After
+    public void tearDown() {
+        verify(controller);
+    }
+
+    @Test
+    public void testSetRoleStandbyToActive() throws Exception {
+        doSetUp(HARole.STANDBY);
+
+        this.setRoleAndMockController(HARole.ACTIVE);
+
+        assertTrue(roleManager.getRole() == HARole.ACTIVE);
+
+    }
+
+    @Test
+    public void testSetRoleActiveToStandby() throws Exception {
+        // Set by default
+        assertTrue(roleManager.getRole() == HARole.ACTIVE);
+
+        this.setRoleAndMockController(HARole.STANDBY);
+
+        assertTrue(roleManager.getRole() == HARole.STANDBY);
+
+    }
+
+    @Test
+    public void testSetRoleActiveToActive() throws Exception {
+        // Set by default
+        assertTrue(roleManager.getRole() == HARole.ACTIVE);
+
+        this.setRoleAndMockController(HARole.ACTIVE);
+
+        assertTrue(roleManager.getRole() == HARole.ACTIVE);
+
+    }
+
+    @Test
+    public void testSetRoleStandbyToStandby() throws Exception {
+        doSetUp(HARole.STANDBY);
+
+        this.setRoleAndMockController(HARole.STANDBY);
+
+        assertTrue(roleManager.getRole() == HARole.STANDBY);
+
+    }
+
+    /**
+     * Helper method that mocks up the controller and sets the supplied role
+     * @param role the desired role to pass to setRole
+     */
+    private void setRoleAndMockController(HARole role) {
+        reset(controller);
+        controller.addUpdateToQueue(anyObject(IUpdate.class));
+        expectLastCall().anyTimes();
+        replay(controller);
+
+        roleManager.setRole(role, "test");
+    }
+
+
+    @Test
+    public void testNotifyFollower() throws Exception {
+        // Set by default
+        assertTrue(roleManager.getRole() == HARole.ACTIVE);
+
+        reset(controller);
+        controller.addUpdateToQueue(anyObject(IUpdate.class));
+        expectLastCall().anyTimes();
+        replay(controller);
+
+        // Test ACTIVE
+        roleManager.notify();
+
+        assertTrue(roleManager.getRole() == HARole.STANDBY);
+
+        // Test STANDBY
+        roleManager.notify();
+
+        assertTrue(roleManager.getRole() == HARole.STANDBY);
+
+    }
+
+    @Test
+    public void testNotifyLeaderNoMaster() {
+        doSetUp(HARole.STANDBY);
+
+        // Another master does NOT exist
+        setupSwitchesForNotifyLeader(false);
+
+        roleManager.notify();
+
+        assertTrue(roleManager.getRole() == HARole.ACTIVE);
+    }
+
+    @Test
+    public void testNotifyLeaderAnotherMaster() {
+        doSetUp(HARole.STANDBY);
+
+        // Another master exists
+        setupSwitchesForNotifyLeader(true);
+
+        roleManager.notify();
+
+        assertTrue(roleManager.getRole() == HARole.STANDBY);
+    }
+
+    @Test
+    public void testNotifyLeaderSplitBrainProtection() throws Exception {
+        doSetUp(HARole.STANDBY);
+
+        /* Split brain protection should not allow a controller to become ACTIVE
+         * if another ACTIVE controller exists in the cluster.
+         */
+        setupSwitchesForNotifyLeader(true);
+
+        roleManager.notify();
+
+        assertTrue(roleManager.getRole() == HARole.STANDBY);
+
+        /* At this point if the leader in the split brain scenario goes down,
+        * the controller connections should be updated to reflect that and
+        * leader notification should succeed as no other ACTIVE controller exists.
+        */
+        setupSwitchesForNotifyLeader(false);
+
+        /* Since the roleManager has already been notified, the controller connections
+         * should prompt an update.
+         */
+        roleManager.notifyControllerConnectionUpdate();
+
+        assertTrue(roleManager.getRole() == HARole.ACTIVE);
+    }
+
+    /**
+     * Helper to setup switches to test NotifyLeader scenarios.
+     * @param hasAnotherMaster whether or not the switches should have another master
+     */
+    public void setupSwitchesForNotifyLeader(boolean hasAnotherMaster) {
+        reset(controller);
+        // Setup switches with another master
+        MockSwitchManager switchManager = new MockSwitchManager();
+
+        IOFSwitchBackend sw1 = createMock(IOFSwitchBackend.class);
+        reset(sw1);
+        expect(sw1.hasAnotherMaster()).andReturn(hasAnotherMaster).anyTimes();
+        replay(sw1);
+
+        HashMap<DatapathId, IOFSwitch> switches = new HashMap<DatapathId, IOFSwitch> ();
+        switches.put(DATAPATH_ID_1, sw1);
+        switchManager.setSwitches(switches);
+
+        expect(controller.getSwitchService()).andReturn(switchManager).once();
+        controller.addUpdateToQueue(anyObject(IUpdate.class));
+        expectLastCall().anyTimes();
+        replay(controller);
+
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java b/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java
deleted file mode 100644
index b40715a66ea3e418b534cc8f5d91eff70d68d7b5..0000000000000000000000000000000000000000
--- a/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java
+++ /dev/null
@@ -1,198 +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.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.sdnplatform.sync.test.MockSyncService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import net.floodlightcontroller.core.module.FloodlightModuleLoader;
-import net.floodlightcontroller.core.module.IFloodlightModule;
-import net.floodlightcontroller.core.test.MockFloodlightProvider;
-import net.floodlightcontroller.core.test.MockThreadPoolService;
-import net.floodlightcontroller.counter.NullCounterStore;
-import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier;
-import net.floodlightcontroller.devicemanager.test.MockDeviceManager;
-import net.floodlightcontroller.perfmon.NullPktInProcessingTime;
-import net.floodlightcontroller.storage.memory.MemoryStorageSource;
-import net.floodlightcontroller.topology.TopologyManager;
-
-public class FloodlightTestModuleLoader extends FloodlightModuleLoader {
-    protected static Logger log = LoggerFactory.getLogger(FloodlightTestModuleLoader.class);
-
-    // List of default modules to use unless specified otherwise
-    public static final Class<? extends IFloodlightModule> DEFAULT_STORAGE_SOURCE =
-            MemoryStorageSource.class;
-    public static final Class<? extends IFloodlightModule> DEFAULT_FLOODLIGHT_PRPOVIDER =
-            MockFloodlightProvider.class;
-    public static final Class<? extends IFloodlightModule> DEFAULT_TOPOLOGY_PROVIDER =
-            TopologyManager.class;
-    public static final Class<? extends IFloodlightModule> DEFAULT_DEVICE_SERVICE =
-            MockDeviceManager.class;
-    public static final Class<? extends IFloodlightModule> DEFAULT_COUNTER_STORE =
-            NullCounterStore.class;
-    public static final Class<? extends IFloodlightModule> DEFAULT_THREADPOOL =
-            MockThreadPoolService.class;
-    public static final Class<? extends IFloodlightModule> DEFAULT_ENTITY_CLASSIFIER =
-            DefaultEntityClassifier.class;
-    public static final Class<? extends IFloodlightModule> DEFAULT_PERFMON =
-            NullPktInProcessingTime.class;
-    public static final Class<? extends IFloodlightModule> DEFAULT_SYNC_SERVICE =
-            MockSyncService.class;
-
-    protected static final Collection<Class<? extends IFloodlightModule>> DEFAULT_MODULE_LIST;
-
-    static {
-        DEFAULT_MODULE_LIST = new ArrayList<Class<? extends IFloodlightModule>>();
-        DEFAULT_MODULE_LIST.add(DEFAULT_DEVICE_SERVICE);
-        DEFAULT_MODULE_LIST.add(DEFAULT_FLOODLIGHT_PRPOVIDER);
-        DEFAULT_MODULE_LIST.add(DEFAULT_STORAGE_SOURCE);
-        DEFAULT_MODULE_LIST.add(DEFAULT_TOPOLOGY_PROVIDER);
-        DEFAULT_MODULE_LIST.add(DEFAULT_COUNTER_STORE);
-        DEFAULT_MODULE_LIST.add(DEFAULT_THREADPOOL);
-        DEFAULT_MODULE_LIST.add(DEFAULT_ENTITY_CLASSIFIER);
-        DEFAULT_MODULE_LIST.add(DEFAULT_PERFMON);
-        DEFAULT_MODULE_LIST.add(DEFAULT_SYNC_SERVICE);
-    }
-
-    protected IFloodlightModuleContext fmc;
-
-    /**
-     * Adds default modules to the list of modules to load. This is done
-     * in order to avoid the module loader throwing errors about duplicate
-     * modules and neither one is specified by the user.
-     * @param userModules The list of user specified modules to add to.
-     */
-    protected void addDefaultModules(Collection<Class<? extends IFloodlightModule>> userModules) {
-        Collection<Class<? extends IFloodlightModule>> defaultModules =
-                new ArrayList<Class<? extends IFloodlightModule>>(DEFAULT_MODULE_LIST.size());
-        defaultModules.addAll(DEFAULT_MODULE_LIST);
-
-        Iterator<Class<? extends IFloodlightModule>> modIter = userModules.iterator();
-        while (modIter.hasNext()) {
-            Class<? extends IFloodlightModule> userMod = modIter.next();
-            Iterator<Class<? extends IFloodlightModule>> dmIter = defaultModules.iterator();
-            while (dmIter.hasNext()) {
-                Class<? extends IFloodlightModule> dmMod = dmIter.next();
-                Collection<Class<? extends IFloodlightService>> userModServs;
-                Collection<Class<? extends IFloodlightService>> dmModServs;
-                try {
-                    dmModServs = dmMod.newInstance().getModuleServices();
-                    userModServs = userMod.newInstance().getModuleServices();
-                } catch (InstantiationException e) {
-                    log.error(e.getMessage());
-                    break;
-                } catch (IllegalAccessException e) {
-                    log.error(e.getMessage());
-                    break;
-                }
-
-                // If either of these are null continue as they have no services
-                if (dmModServs == null || userModServs == null) continue;
-
-                // If the user supplied modules has a service
-                // that is in the default module list we remove
-                // the default module from the list.
-                boolean shouldBreak = false;
-                Iterator<Class<? extends IFloodlightService>> userModServsIter
-                    = userModServs.iterator();
-                while (userModServsIter.hasNext()) {
-                    Class<? extends IFloodlightService> userModServIntf = userModServsIter.next();
-                    Iterator<Class<? extends IFloodlightService>> dmModsServsIter
-                        = dmModServs.iterator();
-                    while (dmModsServsIter.hasNext()) {
-                        Class<? extends IFloodlightService> dmModServIntf
-                            = dmModsServsIter.next();
-
-                        if (dmModServIntf.getCanonicalName().equals(
-                                userModServIntf.getCanonicalName())) {
-                            logger.debug("Removing default module {} because it was " +
-                                    "overriden by an explicitly specified module",
-                                    dmModServIntf.getCanonicalName());
-                            dmIter.remove();
-                            shouldBreak = true;
-                            break;
-                        }
-                    }
-                    if (shouldBreak) break;
-                }
-                if (shouldBreak) break;
-            }
-        }
-
-        // Append the remaining default modules to the user specified ones.
-        // This avoids the module loader throwing duplicate module errors.
-        userModules.addAll(defaultModules);
-        log.debug("Using module set " + userModules.toString());
-    }
-
-    /**
-     * Sets up all modules and their dependencies.
-     * @param modules The list of modules that the user wants to load.
-     * @param mockedServices The list of services that will be mocked. Any
-     * module that provides this service will not be loaded.
-     */
-    public void setupModules(Collection<Class<? extends IFloodlightModule>> modules,
-            Collection<IFloodlightService> mockedServices) throws FloodlightModuleException {
-        addDefaultModules(modules);
-        Collection<String> modulesAsString = new ArrayList<String>();
-        for (Class<? extends IFloodlightModule> m : modules) {
-            modulesAsString.add(m.getCanonicalName());
-        }
-
-        fmc = loadModulesFromList(modulesAsString, null, mockedServices);
-    }
-
-    /**
-     * Gets the inited/started instance of a module from the context.
-     * @param ifl The name if the module to get, i.e. "LearningSwitch.class".
-     * @return The inited/started instance of the module.
-     */
-    public IFloodlightModule getModuleByName(Class<? extends IFloodlightModule> ifl) {
-        Collection<IFloodlightModule> modules = fmc.getAllModules();
-        for (IFloodlightModule m : modules) {
-            if (ifl.getCanonicalName().equals(m.getClass().getCanonicalName())) {
-                return m;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Gets an inited/started instance of a service from the context.
-     * @param ifs The name of the service to get, i.e. "ITopologyService.class".
-     * @return The inited/started instance of the service from teh context.
-     */
-    public IFloodlightService getModuleByService(Class<? extends IFloodlightService> ifs) {
-        Collection<IFloodlightModule> modules = fmc.getAllModules();
-        for (IFloodlightModule m : modules) {
-            Collection<Class<? extends IFloodlightService>> mServs = m.getModuleServices();
-            if (mServs == null) continue;
-            for (Class<? extends IFloodlightService> mServClass : mServs) {
-                if (mServClass.getCanonicalName().equals(ifs.getCanonicalName())) {
-                    assert(m instanceof IFloodlightService);
-                    return (IFloodlightService)m;
-                }
-            }
-        }
-        return null;
-    }
-}
diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
index 92e082b740c276bee6de2e19c3288783a76e387d..f5f89350abb048234cd368bc773f45187ff98f05 100644
--- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
+++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
@@ -17,45 +17,51 @@
 
 package net.floodlightcontroller.core.test;
 
-import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
+import static org.junit.Assert.fail;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
-import java.util.HashSet;
 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.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.jboss.netty.util.Timer;
 
 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.IInfoProvider;
+import net.floodlightcontroller.core.IListener.Command;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitchDriver;
-import net.floodlightcontroller.core.IOFSwitchListener;
-import net.floodlightcontroller.core.IListener.Command;
-import net.floodlightcontroller.core.IReadyForReconcileListener;
 import net.floodlightcontroller.core.RoleInfo;
+import net.floodlightcontroller.core.internal.Controller.IUpdate;
+import net.floodlightcontroller.core.internal.Controller.ModuleLoaderState;
+import net.floodlightcontroller.core.internal.RoleManager;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.util.ListenerDispatcher;
+
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFType;
+
 import net.floodlightcontroller.packet.Ethernet;
 
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.factory.BasicFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -64,26 +70,31 @@ import org.slf4j.LoggerFactory;
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
 public class MockFloodlightProvider implements IFloodlightModule, IFloodlightProviderService {
-    protected static Logger log = LoggerFactory.getLogger(MockFloodlightProvider.class);
+    private final static Logger log = LoggerFactory.getLogger(MockFloodlightProvider.class);
     protected ConcurrentMap<OFType, ListenerDispatcher<OFType,IOFMessageListener>> listeners;
-    protected List<IOFSwitchListener> switchListeners;
     protected ListenerDispatcher<HAListenerTypeMarker, IHAListener> haListeners;
-    protected Map<Long, IOFSwitch> switches;
-    protected BasicFactory factory;
-    private Role role;
+    private HARole role;
+    private final String openFlowHostname = "127.0.0.1";
+    private final int openFlowPort = 6653;
+    private final boolean useAsyncUpdates;
+    private volatile ExecutorService executorService;
+    private volatile Future<?> mostRecentUpdateFuture;
 
     /**
      *
      */
-    public MockFloodlightProvider() {
+    public MockFloodlightProvider(boolean useAsyncUpdates) {
         listeners = new ConcurrentHashMap<OFType, ListenerDispatcher<OFType,
                                    IOFMessageListener>>();
-        switches = new ConcurrentHashMap<Long, IOFSwitch>();
-        switchListeners = new CopyOnWriteArrayList<IOFSwitchListener>();
         haListeners =
                 new ListenerDispatcher<HAListenerTypeMarker, IHAListener>();
-        factory = BasicFactory.getInstance();
+
         role = null;
+        this.useAsyncUpdates = useAsyncUpdates;
+    }
+
+    public MockFloodlightProvider() {
+        this(false);
     }
 
     @Override
@@ -115,48 +126,17 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
     public Map<OFType, List<IOFMessageListener>> getListeners() {
         Map<OFType, List<IOFMessageListener>> lers =
                 new HashMap<OFType, List<IOFMessageListener>>();
-            for(Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e :
-                listeners.entrySet()) {
-                lers.put(e.getKey(), e.getValue().getOrderedListeners());
-            }
-            return Collections.unmodifiableMap(lers);
+        for(Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e :
+            listeners.entrySet()) {
+            lers.put(e.getKey(), e.getValue().getOrderedListeners());
+        }
+        return Collections.unmodifiableMap(lers);
     }
 
     public void clearListeners() {
         this.listeners.clear();
     }
 
-    @Override
-    public Map<Long,IOFSwitch> getAllSwitchMap() {
-        return Collections.unmodifiableMap(this.switches);
-    }
-
-    @Override
-    public Set<Long> getAllSwitchDpids() {
-        // the contract for getAllSwitchDpids says the caller will own the
-        // returned set
-        return new HashSet<Long>(this.switches.keySet());
-    }
-
-    @Override
-    public IOFSwitch getSwitch(long dpid) {
-        return this.switches.get(dpid);
-    }
-
-    public void setSwitches(Map<Long, IOFSwitch> switches) {
-        this.switches = switches;
-    }
-
-    @Override
-    public void addOFSwitchListener(IOFSwitchListener listener) {
-        switchListeners.add(listener);
-    }
-
-    @Override
-    public void removeOFSwitchListener(IOFSwitchListener listener) {
-        switchListeners.remove(listener);
-    }
-
     public void dispatchMessage(IOFSwitch sw, OFMessage msg) {
         dispatchMessage(sw, msg, new FloodlightContext());
     }
@@ -169,7 +149,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
             if (OFType.PACKET_IN.equals(msg.getType())) {
                 OFPacketIn pi = (OFPacketIn)msg;
                 Ethernet eth = new Ethernet();
-                eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length);
+                eth.deserialize(pi.getData(), 0, pi.getData().length);
                 IFloodlightProviderService.bcStore.put(bc,
                         IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
                         eth);
@@ -181,7 +161,8 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
     }
 
     @Override
-    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m, FloodlightContext bc) {
+    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m) {
+        FloodlightContext bc = new FloodlightContext();
         List<IOFMessageListener> msgListeners = null;
         if (listeners.containsKey(m.getType())) {
             msgListeners = listeners.get(m.getType()).getOrderedListeners();
@@ -198,42 +179,23 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
 
     public void handleOutgoingMessages(IOFSwitch sw, List<OFMessage> msglist, FloodlightContext bc) {
         for (OFMessage m:msglist) {
-            handleOutgoingMessage(sw, m, bc);
+            handleOutgoingMessage(sw, m);
         }
     }
 
-    /**
-     * @return the switchListeners
-     */
-    public List<IOFSwitchListener> getSwitchListeners() {
-        return switchListeners;
-    }
-
-    @Override
-    public void terminate() {
-    }
-
-    @Override
-    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) {
-        dispatchMessage(sw, msg);
-        return true;
-    }
-
-    @Override
-    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
-                                   FloodlightContext bContext) {
-        dispatchMessage(sw, msg, bContext);
-        return true;
-    }
-
-    @Override
-    public BasicFactory getOFMessageFactory() {
-        return factory;
-    }
-
     @Override
     public void run() {
         logListeners();
+        if (useAsyncUpdates)
+            executorService = Executors.newSingleThreadExecutor();
+    }
+
+    public void shutdown() {
+        if (executorService != null) {
+            executorService.shutdownNow();
+            executorService = null;
+            mostRecentUpdateFuture = null;
+        }
     }
 
     @Override
@@ -262,34 +224,62 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
     }
 
     @Override
-    public void init(FloodlightModuleContext context)
-                                                 throws FloodlightModuleException {
-        // TODO Auto-generated method stub
-
+    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+        // do nothing.
     }
 
     @Override
     public void startUp(FloodlightModuleContext context) {
-        // TODO Auto-generated method stub
-
+        // do nothing.
     }
 
     @Override
     public void addInfoProvider(String type, IInfoProvider provider) {
-        // TODO Auto-generated method stub
-
+        // do nothing.
     }
 
     @Override
     public void removeInfoProvider(String type, IInfoProvider provider) {
-        // TODO Auto-generated method stub
-
+        // do nothing.
     }
 
     @Override
     public Map<String, Object> getControllerInfo(String type) {
-        // TODO Auto-generated method stub
-        return null;
+        // mock up something
+        Map<String, Object> summary = new HashMap<String, Object>();
+        summary.put("test-summary-1", 2);
+        summary.put("test-summary-2", 5);
+        return summary;
+    }
+
+    @Override
+    public void addUpdateToQueue(final IUpdate update) {
+        if (useAsyncUpdates) {
+            mostRecentUpdateFuture = executorService.submit(new Runnable() {
+                @Override
+                public void run() {
+                    update.dispatch();
+                }
+            });
+        } else {
+            update.dispatch();
+        }
+    }
+
+    public void waitForUpdates(long timeout, TimeUnit unit) throws InterruptedException {
+
+        long timeoutNanos = unit.toNanos(timeout);
+        long start = System.nanoTime();
+        for (;;) {
+            Future<?> future = mostRecentUpdateFuture;
+            if ((future == null) || future.isDone())
+                break;
+            Thread.sleep(100);
+            long now = System.nanoTime();
+            if (now > start + timeoutNanos) {
+                fail("Timeout waiting for update tasks to complete");
+            }
+        }
     }
 
     @Override
@@ -303,7 +293,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
     }
 
     @Override
-    public Role getRole() {
+    public HARole getRole() {
         /* DISABLE THIS CHECK FOR NOW. OTHER UNIT TESTS NEED TO BE UPDATED
          * FIRST
         if (this.role == null)
@@ -315,7 +305,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
     }
 
     @Override
-    public void setRole(Role role, String roleChangeDescription) {
+    public void setRole(HARole role, String roleChangeDescription) {
         this.role = role;
     }
 
@@ -324,22 +314,25 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
      * @param oldRole
      * @param newRole
      */
-    public void transitionToMaster() {
-        for (IHAListener rl : haListeners.getOrderedListeners()) {
-            rl.transitionToMaster();
-        }
+    public void transitionToActive() {
+        IUpdate update = new IUpdate() {
+            @Override
+            public void dispatch() {
+                for (IHAListener rl : haListeners.getOrderedListeners()) {
+                    rl.transitionToActive();
+                }
+            }
+        };
+        addUpdateToQueue(update);
     }
 
-
     @Override
     public Map<String, String> getControllerNodeIPs() {
-        // TODO Auto-generated method stub
         return null;
     }
 
     @Override
     public long getSystemStartTime() {
-        // TODO Auto-generated method stub
         return 0;
     }
 
@@ -366,51 +359,67 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
     }
 
     @Override
-    public void setAlwaysClearFlowsOnSwActivate(boolean value) {
+    public RoleInfo getRoleInfo() {
         // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Map<String, Long> getMemory() {
+        Map<String, Long> m = new HashMap<String, Long>();
+        m.put("total", 1000000000L);
+        m.put("free", 20000000L);
+        return m;
+    }
 
+    @Override
+    public Long getUptime() {
+        return 1000000L;
     }
 
     @Override
-    public void addOFSwitchDriver(String desc, IOFSwitchDriver driver) {
-        // TODO Auto-generated method stub
+    public String getOFHostname() {
+        return openFlowHostname;
+    }
 
+    @Override
+    public int getOFPort() {
+        return openFlowPort;
     }
 
     @Override
-    public RoleInfo getRoleInfo() {
-        // TODO Auto-generated method stub
-        return null;
+    public void handleMessage(IOFSwitch sw, OFMessage m,
+                              FloodlightContext bContext) {
+        // do nothing
     }
 
     @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;
+    public Timer getTimer() {
+        return null;
     }
 
     @Override
-    public Long getUptime() {
-        RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
-        return rb.getUptime();
+    public RoleManager getRoleManager() {
+        return null;
     }
 
     @Override
-    public void addReadyForReconcileListener(IReadyForReconcileListener l) {
-        // do nothing.
+    public ModuleLoaderState getModuleLoaderState() {
+        return null;
     }
 
     @Override
-    public void addSwitchEvent(long switchDPID, String reason, boolean flushNow) {
-        // TODO Auto-generated method stub
+    public String getControllerId() {
+        return null;
     }
 
     @Override
     public Set<String> getUplinkPortPrefixSet() {
-        // TODO Auto-generated method stub
         return null;
     }
+
+    @Override
+    public int getWorkerThreads() {
+        return 0;
+    }
 }
diff --git a/src/test/java/net/floodlightcontroller/core/test/MockSwitchManager.java b/src/test/java/net/floodlightcontroller/core/test/MockSwitchManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..2bd6d0c376585831fb8d37f273a0aa0ed2ae71c3
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/test/MockSwitchManager.java
@@ -0,0 +1,253 @@
+package net.floodlightcontroller.core.test;
+
+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 java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import net.floodlightcontroller.core.FloodlightContext;
+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.internal.IAppHandshakePluginFactory;
+import net.floodlightcontroller.core.internal.IOFSwitchManager;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
+import net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler;
+import net.floodlightcontroller.core.internal.SwitchManagerCounters;
+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.DebugCounterServiceImpl;
+
+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 class MockSwitchManager implements IFloodlightModule, IOFSwitchManager, IOFSwitchService {
+
+    private Map<DatapathId, OFSwitchHandshakeHandler> switchHandlers;
+    private Map<DatapathId, IOFSwitch> switches;
+    private final SwitchManagerCounters counters;
+    //private final CopyOnWriteArrayList<IOFSwitchListener> switchListeners;
+
+    public MockSwitchManager(){
+        switchHandlers = new ConcurrentHashMap<DatapathId, OFSwitchHandshakeHandler>();
+        switches = new ConcurrentHashMap<DatapathId, IOFSwitch>();
+        counters = new SwitchManagerCounters(new DebugCounterServiceImpl());
+        //switchListeners = new CopyOnWriteArrayList<IOFSwitchListener>();
+    }
+
+    @Override
+    public void switchAdded(IOFSwitchBackend sw) {
+        // do nothing
+
+    }
+
+    @Override
+    public void switchDisconnected(IOFSwitchBackend sw) {
+     // do nothing
+
+    }
+
+    @Override
+    public void handshakeDisconnected(DatapathId dpid) {
+        // do nothing
+    }
+
+    @Override
+    public void notifyPortChanged(IOFSwitchBackend sw, OFPortDesc port,
+                                  PortChangeType type) {
+     // do nothing
+
+    }
+
+    @Override
+    public IOFSwitchBackend
+            getOFSwitchInstance(IOFConnectionBackend connection,
+                                SwitchDescription description,
+                                OFFactory factory, DatapathId datapathId) {
+        return null;
+    }
+
+    @Override
+    public void handleMessage(IOFSwitchBackend sw, OFMessage m,
+                              FloodlightContext bContext) {
+        // do nothing
+
+    }
+
+    public void setSwitchHandshakeHandlers(Map<DatapathId, OFSwitchHandshakeHandler> handlers) {
+        this.switchHandlers = handlers;
+    }
+    @Override
+    public ImmutableList<OFSwitchHandshakeHandler>
+            getSwitchHandshakeHandlers() {
+        return ImmutableList.copyOf(this.switchHandlers.values());
+    }
+
+    @Override
+    public void addOFSwitchDriver(String manufacturerDescriptionPrefix,
+                                  IOFSwitchDriver driver) {
+        // do nothing
+
+    }
+
+    @Override
+    public void switchStatusChanged(IOFSwitchBackend sw,
+                                    SwitchStatus oldStatus,
+                                    SwitchStatus newStatus) {
+        // do nothing
+
+    }
+
+    @Override
+    public int getNumRequiredConnections() {
+        return 0;
+    }
+
+    @Override
+    public void addSwitchEvent(DatapathId switchDpid, String reason,
+                               boolean flushNow) {
+        // do nothing
+
+    }
+
+    @Override
+    public List<IAppHandshakePluginFactory> getHandshakePlugins() {
+        return null;
+    }
+
+    @Override
+    public SwitchManagerCounters getCounters() {
+        return this.counters;
+    }
+
+    @Override
+    public boolean isCategoryRegistered(LogicalOFMessageCategory category) {
+        return false;
+    }
+
+    public void setSwitches(Map<DatapathId, IOFSwitch> switches) {
+        this.switches = switches;
+    }
+
+    @Override
+    public Map<DatapathId, IOFSwitch> getAllSwitchMap() {
+        return Collections.unmodifiableMap(switches);
+    }
+
+    @Override
+    public IOFSwitch getSwitch(DatapathId dpid) {
+        return this.switches.get(dpid);
+    }
+
+    @Override
+    public IOFSwitch getActiveSwitch(DatapathId dpid) {
+        IOFSwitch sw = this.switches.get(dpid);
+        if(sw != null && sw.getStatus().isVisible())
+            return sw;
+        else
+            return null;
+    }
+
+    @Override
+    public void addOFSwitchListener(IOFSwitchListener listener) {
+        // do nothing
+    }
+
+    @Override
+    public void removeOFSwitchListener(IOFSwitchListener listener) {
+        // do nothing
+    }
+
+    @Override
+    public void registerLogicalOFMessageCategory(LogicalOFMessageCategory category) {
+        // do nothing
+    }
+
+    @Override
+    public void registerHandshakePlugin(IAppHandshakePluginFactory plugin) {
+        // do nothing
+
+    }
+
+    @Override
+    public Set<DatapathId> getAllSwitchDpids() {
+        return this.switches.keySet();
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> services =
+                new ArrayList<Class<? extends IFloodlightService>>(1);
+        services.add(IOFSwitchService.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(IOFSwitchService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleDependencies() {
+        return null;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+        // do nothing
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
+        // do nothing
+    }
+
+    @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 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;
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/test/MockThreadPoolService.java b/src/test/java/net/floodlightcontroller/core/test/MockThreadPoolService.java
index 2e59ba4c8f7706db536a985caa3577b7e7ab6908..42017f4a4d97054af0b778e4e6a263817a67c694 100644
--- a/src/test/java/net/floodlightcontroller/core/test/MockThreadPoolService.java
+++ b/src/test/java/net/floodlightcontroller/core/test/MockThreadPoolService.java
@@ -79,5 +79,4 @@ public class MockThreadPoolService implements IFloodlightModule, IThreadPoolServ
     public void startUp(FloodlightModuleContext context) {
         // no-op
     }
-
 }
diff --git a/src/test/java/net/floodlightcontroller/core/test/PacketFactory.java b/src/test/java/net/floodlightcontroller/core/test/PacketFactory.java
index 07f8c3dd5295233dde8e5405816df12cc17bc031..a4779c1d3af0f30b520a3f195979ffeb4fe1b0d8 100644
--- a/src/test/java/net/floodlightcontroller/core/test/PacketFactory.java
+++ b/src/test/java/net/floodlightcontroller/core/test/PacketFactory.java
@@ -19,18 +19,20 @@ package net.floodlightcontroller.core.test;
 import java.util.ArrayList;
 import java.util.List;
 
+import net.floodlightcontroller.core.IOFSwitch;
+
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketInReason;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFPort;
+
 import net.floodlightcontroller.packet.DHCP;
 import net.floodlightcontroller.packet.DHCPOption;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.packet.UDP;
-import net.floodlightcontroller.util.MACAddress;
-
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPacketOut;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.OFPacketIn.OFPacketInReason;
-import org.openflow.protocol.factory.BasicFactory;
 
 /**
  * A class to that creates many types of L2/L3/L4 or OpenFlow packets.
@@ -41,88 +43,88 @@ import org.openflow.protocol.factory.BasicFactory;
 public class PacketFactory {
     public static String broadcastMac = "ff:ff:ff:ff:ff:ff";
     public static String broadcastIp = "255.255.255.255";
-    protected static BasicFactory OFMessageFactory = BasicFactory.getInstance();
-    
+
     /**
      * Generates a DHCP request OFPacketIn.
      * @param hostMac The host MAC address of for the request.
      * @return An OFPacketIn that contains a DHCP request packet.
      */
-    public static OFPacketIn DhcpDiscoveryRequestOFPacketIn(MACAddress hostMac) {
+    public static OFPacketIn DhcpDiscoveryRequestOFPacketIn(IOFSwitch sw,
+            MacAddress hostMac) {
         byte[] serializedPacket = DhcpDiscoveryRequestEthernet(hostMac).serialize();
-        return (((OFPacketIn)OFMessageFactory
-                .getMessage(OFType.PACKET_IN))
-                .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-                .setInPort((short) 1)
-                .setPacketData(serializedPacket)
+        OFFactory factory = sw.getOFFactory();
+        OFPacketIn packetIn = factory.buildPacketIn()
+                .setInPort(OFPort.of(1))
+                .setData(serializedPacket)
                 .setReason(OFPacketInReason.NO_MATCH)
-                .setTotalLength((short)serializedPacket.length));
+                .build();
+        return packetIn;
     }
-    
+
     /**
      * Generates a DHCP request Ethernet frame.
      * @param hostMac The host MAC address of for the request.
      * @returnAn An Ethernet frame that contains a DHCP request packet.
      */
-    public static Ethernet DhcpDiscoveryRequestEthernet(MACAddress hostMac) {
+    public static Ethernet DhcpDiscoveryRequestEthernet(MacAddress hostMac) {
         List<DHCPOption> optionList = new ArrayList<DHCPOption>();
-        
+
         byte[] requestValue = new byte[4];
         requestValue[0] = requestValue[1] = requestValue[2] = requestValue[3] = 0;
-        DHCPOption requestOption = 
+        DHCPOption requestOption =
                 new DHCPOption()
                     .setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.
                              getValue())
                     .setLength((byte)4)
                     .setData(requestValue);
-        
+
         byte[] msgTypeValue = new byte[1];
         msgTypeValue[0] = 1;    // DHCP request
-        DHCPOption msgTypeOption = 
+        DHCPOption msgTypeOption =
                 new DHCPOption()
                     .setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.
                              getValue())
                     .setLength((byte)1)
                     .setData(msgTypeValue);
-        
+
         byte[] reqParamValue = new byte[4];
         reqParamValue[0] = 1;   // subnet mask
         reqParamValue[1] = 3;   // Router
         reqParamValue[2] = 6;   // Domain Name Server
         reqParamValue[3] = 42;  // NTP Server
-        DHCPOption reqParamOption = 
+        DHCPOption reqParamOption =
                 new DHCPOption()
                     .setCode(DHCP.DHCPOptionCode.OptionCode_RequestedParameters.
                              getValue())
                     .setLength((byte)4)
                     .setData(reqParamValue);
-        
+
         byte[] clientIdValue = new byte[7];
         clientIdValue[0] = 1;   // Ethernet
-        System.arraycopy(hostMac.toBytes(), 0, 
+        System.arraycopy(hostMac.getBytes(), 0,
                          clientIdValue, 1, 6);
-        DHCPOption clientIdOption = 
+        DHCPOption clientIdOption =
                 new DHCPOption()
                     .setCode(DHCP.DHCPOptionCode.OptionCode_ClientID.
                              getValue())
                              .setLength((byte)7)
                              .setData(clientIdValue);
-        
-        DHCPOption endOption = 
+
+        DHCPOption endOption =
                 new DHCPOption()
                     .setCode(DHCP.DHCPOptionCode.OptionCode_END.
                              getValue())
                              .setLength((byte)0)
                              .setData(null);
-                                    
+
         optionList.add(requestOption);
         optionList.add(msgTypeOption);
         optionList.add(reqParamOption);
         optionList.add(clientIdOption);
         optionList.add(endOption);
-        
+
         Ethernet requestPacket = new Ethernet();
-        requestPacket.setSourceMACAddress(hostMac.toBytes())
+        requestPacket.setSourceMACAddress(hostMac.getBytes())
         .setDestinationMACAddress(broadcastMac)
         .setEtherType(Ethernet.TYPE_IPv4)
         .setPayload(
@@ -133,7 +135,7 @@ public class PacketFactory {
                 .setFlags((byte)0)
                 .setFragmentOffset((short)0)
                 .setTtl((byte)250)
-                .setProtocol(IPv4.PROTOCOL_UDP)
+                .setProtocol(IpProtocol.UDP)
                 .setChecksum((short)0)
                 .setSourceAddress(0)
                 .setDestinationAddress(broadcastIp)
@@ -155,9 +157,9 @@ public class PacketFactory {
                                 .setYourIPAddress(0)
                                 .setServerIPAddress(0)
                                 .setGatewayIPAddress(0)
-                                .setClientHardwareAddress(hostMac.toBytes())
+                                .setClientHardwareAddress(hostMac.getBytes())
                                 .setOptions(optionList))));
-                
+
         return requestPacket;
     }
 }
diff --git a/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java b/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java
index 23c15a44e8b4517ea71269d786aaefde2471fd4a..5e0f87538b0a7f850446a826420418cdaa67e352 100644
--- a/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java
+++ b/src/test/java/net/floodlightcontroller/core/util/AppCookieTest.java
@@ -20,6 +20,11 @@ package net.floodlightcontroller.core.util;
 import static org.junit.Assert.*;
 
 import org.junit.Test;
+import net.floodlightcontroller.core.util.AppCookie;
+import net.floodlightcontroller.core.util.AppIDInUseException;
+import net.floodlightcontroller.core.util.AppIDNotRegisteredException;
+import net.floodlightcontroller.core.util.InvalidAppIDValueException;
+import org.projectfloodlight.openflow.types.U64;
 
 
 public class AppCookieTest {
@@ -38,10 +43,10 @@ public class AppCookieTest {
     public void testAppCookie(){
         int user = 0xF123F123; // MSB set
         int user2 = 0x42;      // MSB cleared
-        long expectedCookie11 =  0xF4200000F123F123L; // app1, user1
-        long expectedCookie21 =  0x74300000F123F123L; // app2, user1
-        long expectedCookie12 =  0xF420000000000042L; // app1, user2
-        long expectedCookie22 =  0x7430000000000042L; // app2, user2
+        U64 expectedCookie11 =  U64.of(0xF4200000F123F123L); // app1, user1
+        U64 expectedCookie21 =  U64.of(0x74300000F123F123L); // app2, user1
+        U64 expectedCookie12 =  U64.of(0xF420000000000042L); // app1, user2
+        U64 expectedCookie22 =  U64.of(0x7430000000000042L); // app2, user2
         String name = "FooBar";
         String name2 = "FooFooFoo";
 
@@ -54,7 +59,7 @@ public class AppCookieTest {
 
         AppCookie.registerApp(appId, name);
 
-        long cookie = AppCookie.makeCookie(appId, user);
+        U64 cookie = AppCookie.makeCookie(appId, user);
         assertEquals(expectedCookie11, cookie);
         assertEquals(appId, AppCookie.extractApp(cookie));
         assertEquals(user, AppCookie.extractUser(cookie));
diff --git a/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java b/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java
index 0829aa447f4d211b0e207c45a0527b7a825906b9..9ea34ce70933726c08a9fa3e695a70216b64b680 100644
--- a/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java
+++ b/src/test/java/net/floodlightcontroller/core/util/MessageDispatcherTest.java
@@ -18,6 +18,12 @@
 package net.floodlightcontroller.core.util;
 
 import static org.easymock.EasyMock.createNiceMock;
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import net.floodlightcontroller.test.FloodlightTestCase;
+
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
@@ -26,11 +32,9 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
 
-import org.junit.Test;
-import org.openflow.protocol.OFType;
-
+import org.projectfloodlight.openflow.protocol.OFType;
 import net.floodlightcontroller.core.IOFMessageListener;
-import net.floodlightcontroller.test.FloodlightTestCase;
+import net.floodlightcontroller.core.util.ListenerDispatcher;
 
 public class MessageDispatcherTest extends FloodlightTestCase {
 
diff --git a/src/test/java/net/floodlightcontroller/core/util/SingletonTaskTest.java b/src/test/java/net/floodlightcontroller/core/util/SingletonTaskTest.java
index fa04b741496d801dfb7c3fe417a61083acab3f93..70560cc312d347b7c1f6ae02e55b79e025d4570c 100644
--- a/src/test/java/net/floodlightcontroller/core/util/SingletonTaskTest.java
+++ b/src/test/java/net/floodlightcontroller/core/util/SingletonTaskTest.java
@@ -17,6 +17,8 @@
 
 package net.floodlightcontroller.core.util;
 
+import static org.junit.Assert.*;
+
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -72,7 +74,6 @@ public class SingletonTaskTest extends FloodlightTestCase {
                 time = System.nanoTime();
             }
         });
-        long start = System.nanoTime();
         st1.reschedule(10, TimeUnit.MILLISECONDS);
         assertFalse("Check that task hasn't run yet", ran > 0);
 
@@ -80,8 +81,6 @@ public class SingletonTaskTest extends FloodlightTestCase {
         ses.awaitTermination(5, TimeUnit.SECONDS);
 
         assertEquals("Check that task ran", 1, ran);
-        assertTrue("Check that time passed appropriately",
-                   (time - start) >= TimeUnit.NANOSECONDS.convert(10, TimeUnit.MILLISECONDS));
     }
 
     @Test
@@ -99,7 +98,7 @@ public class SingletonTaskTest extends FloodlightTestCase {
                 time = System.nanoTime();
             }
         });
-        long start = System.nanoTime();
+
         st1.reschedule(20, TimeUnit.MILLISECONDS);
         Thread.sleep(5);
         assertFalse("Check that task hasn't run yet", ran > 0);
@@ -129,8 +128,6 @@ public class SingletonTaskTest extends FloodlightTestCase {
         ses.awaitTermination(5, TimeUnit.SECONDS);
 
         assertEquals("Check that task ran only once", 1, ran);
-        assertTrue("Check that time passed appropriately: " + (time - start),
-                (time - start) >= TimeUnit.NANOSECONDS.convert(55, TimeUnit.MILLISECONDS));
     }
 
     @Test
@@ -157,7 +154,6 @@ public class SingletonTaskTest extends FloodlightTestCase {
             }
         });
 
-        long start = System.nanoTime();
         st1.reschedule(5, TimeUnit.MILLISECONDS);
         Thread.sleep(20);
         assertEquals("Check that task started", 1, ran);
@@ -175,13 +171,8 @@ public class SingletonTaskTest extends FloodlightTestCase {
         assertEquals("Check that task ran exactly twice", 2, ran);
         assertEquals("Check that task finished exactly twice", 2, finished);
 
-        assertTrue("Check that time passed appropriately: " + (time - start),
-                (time - start) >= TimeUnit.NANOSECONDS.convert(130, TimeUnit.MILLISECONDS));
-        assertTrue("Check that time passed appropriately: " + (time - start),
-                (time - start) <= TimeUnit.NANOSECONDS.convert(160, TimeUnit.MILLISECONDS));
-
         ses.shutdown();
-        ses.awaitTermination(5, TimeUnit.SECONDS);
+        ses.awaitTermination(15, TimeUnit.SECONDS);
     }
 
     @Test
@@ -209,7 +200,6 @@ public class SingletonTaskTest extends FloodlightTestCase {
             }
         });
 
-        long start = System.nanoTime();
         st1.reschedule(5, TimeUnit.MILLISECONDS);
         Thread.sleep(20);
         assertEquals("Check that task started", 1, ran);
@@ -227,11 +217,6 @@ public class SingletonTaskTest extends FloodlightTestCase {
         assertEquals("Check that task ran exactly twice", 2, ran);
         assertEquals("Check that task finished exactly twice", 2, finished);
 
-        assertTrue("Check that time passed appropriately: " + (time - start),
-                (time - start) >= TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS));
-        assertTrue("Check that time passed appropriately: " + (time - start),
-                (time - start) <= TimeUnit.NANOSECONDS.convert(125, TimeUnit.MILLISECONDS));
-
         ses.shutdown();
         ses.awaitTermination(5, TimeUnit.SECONDS);
     }
@@ -262,7 +247,6 @@ public class SingletonTaskTest extends FloodlightTestCase {
             }
         });
 
-        long start = System.nanoTime();
         st1.reschedule(0, null);
         Thread.sleep(20);
         assertEquals("Check that task started", 1, ran);
@@ -280,11 +264,6 @@ public class SingletonTaskTest extends FloodlightTestCase {
         assertEquals("Check that task ran exactly twice", 2, ran);
         assertEquals("Check that task finished exactly twice", 2, finished);
 
-        assertTrue("Check that time passed appropriately: " + (time - start),
-                (time - start) >= TimeUnit.NANOSECONDS.convert(90, TimeUnit.MILLISECONDS));
-        assertTrue("Check that time passed appropriately: " + (time - start),
-                (time - start) <= TimeUnit.NANOSECONDS.convert(130, TimeUnit.MILLISECONDS));
-
         ses.shutdown();
         ses.awaitTermination(5, TimeUnit.SECONDS);
     }
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index ecd145f969176aafb8e7a0ede3dcbc87bd5fb731..43317cc8d84152149e0781378f014fb83fa3cb19 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -53,8 +53,8 @@ import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IListener.Command;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IFloodlightProviderService.Role;
-import net.floodlightcontroller.core.ImmutablePort;
+import net.floodlightcontroller.core.internal.RoleManager;
+import net.floodlightcontroller.core.HARole;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.test.MockThreadPoolService;
@@ -90,11 +90,12 @@ import net.floodlightcontroller.topology.ITopologyService;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPacketIn.OFPacketInReason;
-import org.openflow.protocol.OFPort;
-import org.openflow.protocol.OFType;
-import org.openflow.util.HexString;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketInReason;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.protocol.OFType;
 import org.sdnplatform.sync.IClosableIterator;
 import org.sdnplatform.sync.IStoreClient;
 import org.sdnplatform.sync.ISyncService;
@@ -121,14 +122,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
     MemoryStorageSource storageSource;
     FlowReconcileManager flowReconcileMgr;
 
-    private IOFSwitch makeSwitchMock(long id) {
+    private IOFSwitch makeSwitchMock(DatapathId id) {
         IOFSwitch mockSwitch = createMock(IOFSwitch.class);
-        ImmutablePort port = ImmutablePort.create("p1", (short)1);
+        OFPort port = OFPort.of(1);
         expect(mockSwitch.getId()).andReturn(id).anyTimes();
-        expect(mockSwitch.getStringId())
-                .andReturn(HexString.toHexString(id, 6)).anyTimes();
-        expect(mockSwitch.getPort(anyShort()))
-                .andReturn(port).anyTimes();
+        expect(mockSwitch.getStringId()).andReturn(id.toString()).anyTimes();
+        expect(mockSwitch.getPort(OFPort.of(anyShort())).getPortNo()).andReturn(port).anyTimes();
         return mockSwitch;
     }
 
@@ -141,16 +140,15 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
      */
     private ITopologyService makeMockTopologyAllPortsAp() {
         ITopologyService mockTopology = createMock(ITopologyService.class);
-        mockTopology.isAttachmentPointPort(anyLong(), anyShort());
+        mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()));
         expectLastCall().andReturn(true).anyTimes();
-        mockTopology.getL2DomainId(anyLong());
+        mockTopology.getL2DomainId(DatapathId.of(anyLong()));
         expectLastCall().andReturn(1L).anyTimes();
-        mockTopology.isBroadcastDomainPort(anyLong(), anyShort());
+        mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort()));
         expectLastCall().andReturn(false).anyTimes();
-        mockTopology.isConsistent(anyLong(), anyShort(), anyLong(), anyShort());
+        mockTopology.isConsistent(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(anyShort()));
         expectLastCall().andReturn(false).anyTimes();
-        mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(),
-                                             anyLong(), anyShort());
+        mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(anyShort()));
         expectLastCall().andReturn(false).anyTimes();
         return mockTopology;
     }
@@ -158,10 +156,10 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
     @Override
     @Before
     public void setUp() throws Exception {
-        doSetUp(Role.MASTER);
+        doSetUp(HARole.ACTIVE);
     }
 
-    public void doSetUp(Role initialRole) throws Exception {
+    public void doSetUp(HARole initialRole) throws Exception {
         super.setUp();
 
         this.syncService = new MockSyncService();
@@ -173,6 +171,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         fmc.addService(IThreadPoolService.class, tp);
         mockFloodlightProvider = getMockFloodlightProvider();
         mockFloodlightProvider.setRole(initialRole, "");
+        
 
         deviceManager = new DeviceManagerImpl();
         flowReconcileMgr = new FlowReconcileManager();
@@ -209,15 +208,15 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         expectLastCall().anyTimes();
         replay(topology);
 
-        IOFSwitch mockSwitch1 = makeSwitchMock(1L);
-        IOFSwitch mockSwitch10 = makeSwitchMock(10L);
-        IOFSwitch mockSwitch5 = makeSwitchMock(5L);
-        IOFSwitch mockSwitch50 = makeSwitchMock(50L);
-        Map<Long, IOFSwitch> switches = new HashMap<Long,IOFSwitch>();
-        switches.put(1L, mockSwitch1);
-        switches.put(10L, mockSwitch10);
-        switches.put(5L, mockSwitch5);
-        switches.put(50L, mockSwitch50);
+        IOFSwitch mockSwitch1 = makeSwitchMock(DatapathId.of(1L));
+        IOFSwitch mockSwitch10 = makeSwitchMock(DatapathId.of(10L));
+        IOFSwitch mockSwitch5 = makeSwitchMock(DatapathId.of(5L));
+        IOFSwitch mockSwitch50 = makeSwitchMock(DatapathId.of(50L));
+        Map<DatapathId, IOFSwitch> switches = new HashMap<DatapathId, IOFSwitch>();
+        switches.put(DatapathId.of(1L), mockSwitch1);
+        switches.put(DatapathId.of(10L), mockSwitch10);
+        switches.put(DatapathId.of(5L), mockSwitch5);
+        switches.put(DatapathId.of(50L), mockSwitch50);
         mockFloodlightProvider.setSwitches(switches);
 
         replay(mockSwitch1, mockSwitch5, mockSwitch10, mockSwitch50);
diff --git a/src/test/java/net/floodlightcontroller/hub/HubTest.java b/src/test/java/net/floodlightcontroller/hub/HubTest.java
index 22dfd855ffb94d0cbb0587b769ecb47eaefde552..ecef81215eb24b6ff2a2f1e625585a2184481817 100644
--- a/src/test/java/net/floodlightcontroller/hub/HubTest.java
+++ b/src/test/java/net/floodlightcontroller/hub/HubTest.java
@@ -21,10 +21,11 @@ import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 import static org.easymock.EasyMock.capture;
+import static org.junit.Assert.*;
 
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
 
-import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.test.MockFloodlightProvider;
@@ -39,14 +40,18 @@ import org.easymock.Capture;
 import org.easymock.CaptureType;
 import org.junit.Before;
 import org.junit.Test;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPacketIn.OFPacketInReason;
-import org.openflow.protocol.OFMessage;
-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.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketInReason;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketOut;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
 
 /**
  *
@@ -56,7 +61,7 @@ public class HubTest extends FloodlightTestCase {
     protected OFPacketIn packetIn;
     protected IPacket testPacket;
     protected byte[] testPacketSerialized;
-    private   MockFloodlightProvider mockFloodlightProvider;
+    private MockFloodlightProvider mockFloodlightProvider;
     private Hub hub;
     
     @Before
@@ -85,33 +90,36 @@ public class HubTest extends FloodlightTestCase {
         this.testPacketSerialized = testPacket.serialize();
 
         // Build the PacketIn
-        this.packetIn = ((OFPacketIn) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN))
-            .setBufferId(-1)
-            .setInPort((short) 1)
-            .setPacketData(this.testPacketSerialized)
+        //TODO @Ryan should this just be OF_13 or include OF_10 too?
+        this.packetIn = (OFPacketIn) OFFactories.getFactory(OFVersion.OF_13).buildPacketIn()
+            .setBufferId(OFBufferId.NO_BUFFER)
+            .setMatch(OFFactories.getFactory(OFVersion.OF_13).buildMatch()
+            		.setExact(MatchField.IN_PORT, OFPort.of(1))
+            		.build())
+            .setData(this.testPacketSerialized)
             .setReason(OFPacketInReason.NO_MATCH)
-            .setTotalLength((short) this.testPacketSerialized.length);
+            .setTotalLen((short) this.testPacketSerialized.length).build();
     }
 
     @Test
     public void testFloodNoBufferId() throws Exception {
-        // build our expected flooded packetOut
-        OFPacketOut po = ((OFPacketOut) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT))
-            .setActions(Arrays.asList(new OFAction[] {new OFActionOutput().setPort(OFPort.OFPP_FLOOD.getValue())}))
-            .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
-            .setBufferId(-1)
-            .setInPort((short) 1)
-            .setPacketData(this.testPacketSerialized);
-        po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLengthU()
-                + this.testPacketSerialized.length);
-
         // Mock up our expected behavior
         IOFSwitch mockSwitch = createMock(IOFSwitch.class);
         
+        // build our expected flooded packetOut
+    	OFActionOutput ao = OFFactories.getFactory(OFVersion.OF_13).actions().buildOutput().setPort(OFPort.FLOOD).build();
+    	List<OFAction> al = new ArrayList<OFAction>();
+    	al.add(ao);
+        OFPacketOut po = OFFactories.getFactory(OFVersion.OF_13).buildPacketOut()
+            .setActions(al)
+            .setBufferId(OFBufferId.NO_BUFFER)
+            .setXid(1)
+            .setInPort(OFPort.of(1))
+            .setData(this.testPacketSerialized).build();
+        
         Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL);
-        Capture<FloodlightContext> bc1 = new Capture<FloodlightContext>(CaptureType.ALL);
         
-        mockSwitch.write(capture(wc1), capture(bc1));
+        mockSwitch.write(capture(wc1));
 
         // Start recording the replay on the mocks
         replay(mockSwitch);
@@ -126,28 +134,34 @@ public class HubTest extends FloodlightTestCase {
         
         assertTrue(wc1.hasCaptured());
         OFMessage m = wc1.getValue();
+        //TODO @Ryan the wc1 message has inport=ANY and the next xid
+        // Can this be asserted anymore with OF1.3?
         assertEquals(po, m);
     }
 
     @Test
     public void testFloodBufferId() throws Exception {
         MockFloodlightProvider mockFloodlightProvider = getMockFloodlightProvider();
-        this.packetIn.setBufferId(10);
-
+        this.packetIn = this.packetIn.createBuilder()
+        		.setBufferId(OFBufferId.of(10))
+        		.setXid(1)
+        		.build();
+
+        OFActionOutput ao = OFFactories.getFactory(OFVersion.OF_13).actions().buildOutput().setPort(OFPort.FLOOD).build();
+    	List<OFAction> al = new ArrayList<OFAction>();
+    	al.add(ao);
         // build our expected flooded packetOut
-        OFPacketOut po = ((OFPacketOut) mockFloodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT))
-            .setActions(Arrays.asList(new OFAction[] {new OFActionOutput().setPort(OFPort.OFPP_FLOOD.getValue())}))
-            .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
-            .setBufferId(10)
-            .setInPort((short) 1);
-        po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLengthU());
+        OFPacketOut po = OFFactories.getFactory(OFVersion.OF_13).buildPacketOut()
+        	.setActions(al)
+            .setXid(1)
+            .setBufferId(OFBufferId.of(10))
+            .setInPort(OFPort.of(1))
+            .build();
 
         // Mock up our expected behavior
         IOFSwitch mockSwitch = createMock(IOFSwitch.class);
-        Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL);
-        Capture<FloodlightContext> bc1 = new Capture<FloodlightContext>(CaptureType.ALL);
-        
-        mockSwitch.write(capture(wc1), capture(bc1));
+        Capture<OFPacketOut> wc1 = new Capture<OFPacketOut>(CaptureType.ALL);
+        mockSwitch.write(capture(wc1));
 
         // Start recording the replay on the mocks
         replay(mockSwitch);
@@ -161,6 +175,9 @@ public class HubTest extends FloodlightTestCase {
         verify(mockSwitch);
         
         assertTrue(wc1.hasCaptured());
+        //TODO @Ryan the wc1 message has inport=ANY,
+        // bufferid=NONE, and the next xid
+        // Can this be asserted anymore with OF1.3?
         OFMessage m = wc1.getValue();
         assertEquals(po, m);
     }
diff --git a/src/test/java/net/floodlightcontroller/storage/tests/StorageTest.java b/src/test/java/net/floodlightcontroller/storage/tests/StorageTest.java
index d127181907f0ca7036132f039006fd89b5eb3653..99e2d4e44458d4f123b8d7ca7a7978ffe85ff3ce 100644
--- a/src/test/java/net/floodlightcontroller/storage/tests/StorageTest.java
+++ b/src/test/java/net/floodlightcontroller/storage/tests/StorageTest.java
@@ -30,6 +30,10 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+
 import net.floodlightcontroller.restserver.RestApiServer;
 import net.floodlightcontroller.storage.CompoundPredicate;
 import net.floodlightcontroller.storage.IStorageExceptionHandler;
@@ -44,7 +48,6 @@ import net.floodlightcontroller.storage.RowOrdering;
 import net.floodlightcontroller.storage.nosql.NoSqlStorageSource;
 import net.floodlightcontroller.test.FloodlightTestCase;
 
-import org.junit.Test;
 
 public abstract class StorageTest extends FloodlightTestCase {
     
diff --git a/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java b/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java
index 94496dc2266131b7499085087b29d58eaf785cfa..299f97a60fc34c8695550ec97110d5ad92a293f9 100644
--- a/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java
+++ b/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java
@@ -17,88 +17,71 @@
 
 package net.floodlightcontroller.test;
 
-import junit.framework.TestCase;
+import org.junit.Before;
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.test.MockFloodlightProvider;
-import net.floodlightcontroller.devicemanager.IDevice;
-import net.floodlightcontroller.devicemanager.IDeviceService;
+import net.floodlightcontroller.core.test.MockSwitchManager;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFPort;
 import net.floodlightcontroller.packet.Ethernet;
 
-import org.junit.Test;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.protocol.OFType;
-
 /**
  * This class gets a handle on the application context which is used to
  * retrieve Spring beans from during tests
  *
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
-public class FloodlightTestCase extends TestCase {
+public class FloodlightTestCase {
     protected MockFloodlightProvider mockFloodlightProvider;
+    protected MockSwitchManager mockSwitchManager;
 
     public MockFloodlightProvider getMockFloodlightProvider() {
         return mockFloodlightProvider;
     }
 
-    public void setMockFloodlightProvider(MockFloodlightProvider mockFloodlightProvider) {
-        this.mockFloodlightProvider = mockFloodlightProvider;
+    public MockSwitchManager getMockSwitchService() {
+        return mockSwitchManager;
     }
 
-    public FloodlightContext parseAndAnnotate(OFMessage m,
-                                              IDevice srcDevice,
-                                              IDevice dstDevice) {
-        FloodlightContext bc = new FloodlightContext();
-        return parseAndAnnotate(bc, m, srcDevice, dstDevice);
+    public void setMockFloodlightProvider(MockFloodlightProvider mockFloodlightProvider) {
+        this.mockFloodlightProvider = mockFloodlightProvider;
     }
 
     public FloodlightContext parseAndAnnotate(OFMessage m) {
-        return parseAndAnnotate(m, null, null);
+        FloodlightContext bc = new FloodlightContext();
+        return parseAndAnnotate(bc, m);
     }
 
-    public FloodlightContext parseAndAnnotate(FloodlightContext bc,
-                                              OFMessage m,
-                                              IDevice srcDevice,
-                                              IDevice dstDevice) {
+    public static FloodlightContext parseAndAnnotate(FloodlightContext bc, OFMessage m) {
         if (OFType.PACKET_IN.equals(m.getType())) {
             OFPacketIn pi = (OFPacketIn)m;
             Ethernet eth = new Ethernet();
-            eth.deserialize(pi.getPacketData(), 0, pi.getPacketData().length);
+            eth.deserialize(pi.getData(), 0, pi.getData().length);
             IFloodlightProviderService.bcStore.put(bc,
                     IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
                     eth);
         }
-        if (srcDevice != null) {
-            IDeviceService.fcStore.put(bc,
-                    IDeviceService.CONTEXT_SRC_DEVICE,
-                    srcDevice);
-        }
-        if (dstDevice != null) {
-            IDeviceService.fcStore.put(bc,
-                    IDeviceService.CONTEXT_DST_DEVICE,
-                    dstDevice);
-        }
         return bc;
     }
 
-    @Override
+    @Before
     public void setUp() throws Exception {
         mockFloodlightProvider = new MockFloodlightProvider();
+        mockSwitchManager = new MockSwitchManager();
     }
 
-    @Test
-    public void testSanity() throws Exception {
-    	assertTrue(true);
-    }
-
-    public static OFPhysicalPort createOFPhysicalPort(String name, int number) {
-        OFPhysicalPort p = new OFPhysicalPort();
-        p.setHardwareAddress(new byte [] { 0, 0, 0, 0, 0, 0 });
-        p.setPortNumber((short)number);
-        p.setName(name);
-        return p;
+    public static OFPortDesc createOFPortDesc(IOFSwitch sw, String name, int number) {
+        OFPortDesc portDesc = sw.getOFFactory().buildPortDesc()
+                .setHwAddr(MacAddress.NONE)
+                .setPortNo(OFPort.of(number))
+                .setName(name)
+                .build();
+        return portDesc;
     }
 }
diff --git a/src/test/java/net/floodlightcontroller/util/FutureTestUtils.java b/src/test/java/net/floodlightcontroller/util/FutureTestUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..62dbe00f8c9c3d29186208bec52494414321ff40
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/util/FutureTestUtils.java
@@ -0,0 +1,30 @@
+package net.floodlightcontroller.util;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertThat;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import junit.framework.AssertionFailedError;
+
+public class FutureTestUtils {
+
+    private FutureTestUtils() { }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends Exception> T assertFutureFailedWithException(Future<?> future,
+            Class<T> clazz) throws InterruptedException {
+
+        assertThat("Future should be complete ", future.isDone(), equalTo(true));
+        try {
+            future.get();
+            throw new AssertionFailedError("Expected ExecutionExcepion");
+        } catch(ExecutionException e) {
+            assertThat(e.getCause(), instanceOf(clazz));
+            return (T) e.getCause();
+        }
+    }
+
+}
diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
index c3cc59ed3c6cb5d50b2abbf047bd54d5a221c883..547371cc0ba2e3694c2c810d8dd928f5f12059c0 100644
--- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
+++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
@@ -28,20 +28,19 @@ import java.util.concurrent.Future;
 import net.floodlightcontroller.core.FloodlightContext;
 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.HARole;
 import net.floodlightcontroller.core.internal.Controller;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 
 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;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
 
 
 /**
@@ -357,7 +356,7 @@ public class OFMessageDamperMockSwitch implements IOFSwitch {
     }
 
     @Override
-    public void setFloodlightProvider(Controller controller) {
+    public void setFloodlightProvider(OLD__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
deleted file mode 100644
index 350d4be39c3f1148c7a6c4191085bbe8bb9132a5..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/BasicFactoryTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
-*    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
deleted file mode 100644
index ed8386cd745dd7db691e334d6bd64fec81e67745..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFActionTypeTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 7e447bb071bf477448823d085db1d6a9e7e72701..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFBarrierReplyTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 3aa9cb4a789f6ea2202878a6d92da898d76a4490..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFBarrierRequestTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
-*    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
deleted file mode 100644
index f4a57269826d81cf17b47b547e4b7588afeb873f..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFErrorTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 62e491a995a3f232be6027043144f6544d70e1d8..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFFeaturesReplyTest.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 11746e72411a663170e7ebbf4a8571fb68f8b13f..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFFlowRemovedTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
-*    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
deleted file mode 100644
index c1f1f671a6767bb11dc3993c65fc21845d0820ab..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFGetConfigReplyTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 94d9036e68dd1e0b6573148e068fb4380f9946ef..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFGetConfigRequestTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
-*    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
deleted file mode 100644
index fd7863acc12d49e89054ced08111def1c5559b6d..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFMatchTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 60a9e732b05ba2d03ccbf1c4b9793634cafdeb8a..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFMessageContextStoreTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 55b54552fe03b279f20f076dd8857994dded0e09..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFPacketOutTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-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
deleted file mode 100644
index 9b115ebc40027a15bfe2f1589d39855bc1051ba2..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFPortConfigTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 4fab64e03568194784f6b7eaf4518ece9a5017c0..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFPortStatusTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 2a9e86f7720fb44baf87acaf487d901a2218e026..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFSetConfigTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 1885cae7b3d4731ccae5bfbe4fdb295951b1a760..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFStatisticsReplyTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
-*    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
deleted file mode 100644
index fceb8955eb755a12bb03c68bd1102513874b06ab..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFStatisticsRequestTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
-*    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
deleted file mode 100644
index d44ef7f8e4553f3556efb0bb52ad193578c07bbf..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFStatisticsTypeTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
-*    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
deleted file mode 100644
index c6bf0a347454064d99f0f4ec1064d17cca23da9a..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFTypeTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
-*    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
deleted file mode 100644
index c0385f4415824d1c79408e93ac31de4be40f3e52..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/OFVendorTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 5bf8d12314a070bc301a8ffda6a36ad02ff7d6a0..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/WildcardsTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-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
deleted file mode 100644
index 49b69fb8181d4a6dd6959a40786d643fe05ead20..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/action/MockVendorAction.java
+++ /dev/null
@@ -1,41 +0,0 @@
-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
deleted file mode 100644
index bbc254ca0074cc9e418c5541f976d000074cf0b1..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java
+++ /dev/null
@@ -1,15 +0,0 @@
-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
deleted file mode 100644
index 31ad675d6a0a708c5a69a7ae3b0dcb21bc24e5c5..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-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
deleted file mode 100644
index a8f8ba4b89760e797255da01e3cecb162f0da41b..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/util/HexStringTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 07bee2d589a1901ad1f77afc3a2ee262a48be429..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/util/OFTestCase.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
-*    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
deleted file mode 100644
index ba87e7b122d5cdb101a6d5a74898a612cb57fcdd..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/util/U16Test.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 223c1034e74cef66403f3c786a30f771a88b970b..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/util/U32Test.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 0a97e302f78e84700a0407b5770766eea339ffd4..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/util/U64Test.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 2c06c4db31f56699dbcac37d1f4296d1ad16342d..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/util/U8Test.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
-*    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
deleted file mode 100644
index 7cdf7391bccd390ca941338cf99563dbb9da229c..0000000000000000000000000000000000000000
--- a/src/test/java/org/openflow/util/UnsignedTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
-*    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);
-    }
-  }
-}