diff --git a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
index 347bf5bb9bcbd167c3b812804f40dbac05154bf3..624483a8d412308dde64c964b2baa7596a0d482a 100644
--- a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
+++ b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
@@ -11,6 +11,7 @@ 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.flowcache.IFlowCacheService;
 import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.storage.IStorageSourceService;
@@ -48,6 +49,7 @@ public class FloodlightProvider implements IFloodlightModule {
         dependencies.add(IPktInProcessingTimeService.class);
         dependencies.add(IRestApiService.class);
         dependencies.add(ICounterStoreService.class);
+        dependencies.add(IFlowCacheService.class);
         dependencies.add(IThreadPoolService.class);
         return dependencies;
     }
@@ -60,6 +62,8 @@ public class FloodlightProvider implements IFloodlightModule {
            context.getServiceImpl(IPktInProcessingTimeService.class));
        controller.setCounterStore(
            context.getServiceImpl(ICounterStoreService.class));
+       controller.setFlowCacheMgr(
+           context.getServiceImpl(IFlowCacheService.class));
        controller.setRestApiService(
            context.getServiceImpl(IRestApiService.class));
        controller.setThreadPoolService(
diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
index 1e3ec6f91af7f7d7550515b6c05ee42675a54f58..b9a628ba84d16c812d6b7309696eb05251f885f1 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -33,7 +33,8 @@ import org.openflow.protocol.factory.BasicFactory;
  *
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
-public interface IFloodlightProviderService extends IFloodlightService {
+public interface IFloodlightProviderService extends
+        IFloodlightService {
 
     /**
      * A value stored in the floodlight context containing a parsed packet
@@ -206,5 +207,13 @@ public interface IFloodlightProviderService extends IFloodlightService {
     * switch over to ACTIVE role
     */
    public void setAlwaysClearFlowsOnSwAdd(boolean value);
+   
+   /**
+    * Adds an OFSwitch driver
+    * @param desc The starting portion of switch's manufacturer string
+    * @param driver The object implementing OFSwitchDriver interface
+    */
+   public void addOFSwitchDriver(String desc, IOFSwitchDriver driver);
+
 
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
index 60df97b40d5b858ac3e2cc8a8ac60a8100aced8a..68e025b807cc8212a432f343a732714497eadd97 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -23,7 +23,11 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Future;
+import java.util.concurrent.locks.Lock;
+
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.internal.Controller;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
 
 import org.jboss.netty.channel.Channel;
 import org.openflow.protocol.OFFeaturesReply;
@@ -375,5 +379,39 @@ public interface IOFSwitch {
      * Flush all flows queued for this switch in the current thread.
      * NOTE: The contract is limited to the current thread
      */
-     public void flush();
+    public void flush();
+
+    /**
+     * Send HA role request
+     * 
+     * @param role
+     * @param cookie
+     * @return 
+     * @throws IOException 
+     */
+    public int sendNxRoleRequest(Role role, long cookie) throws IOException;
+
+    /**
+     * Check HA role request cookie
+     * 
+     * @param cookie
+     * @return
+     */
+    public boolean checkFirstPendingRoleRequestCookie(long cookie);
+
+    public void setChannel(Channel channel);
+
+    public void setFloodlightProvider(Controller controller);
+
+    public void setThreadPoolService(IThreadPoolService threadPool);
+
+    public void deliverRoleReply(int xid, Role role);
+
+    public void deliverRoleRequestNotSupported(int xid);
+
+    public Lock getListenerReadLock();
+
+    public boolean checkFirstPendingRoleRequestXid(int xid);
+
+    public Lock getListenerWriteLock();
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
new file mode 100644
index 0000000000000000000000000000000000000000..197642959516a2b2353cdf695d2217efbcd856c1
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
@@ -0,0 +1,12 @@
+package net.floodlightcontroller.core;
+
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+
+public interface IOFSwitchDriver {
+    /**
+     * Return an IOFSwitch object based on switch's manufacturer description
+     * from OFDescriptionStatitics.
+     * @param description
+     */
+    public IOFSwitch getOFSwitchImpl(OFDescriptionStatistics description);
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 6cb369f7bc52fa8067cd3c5f8034991a0b15c097..cfe1d85bb60a96ef5e60ec732fd7b1953560c328 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -39,12 +39,8 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IHAListener;
@@ -52,6 +48,7 @@ import net.floodlightcontroller.core.IInfoProvider;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IListener.Command;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitchDriver;
 import net.floodlightcontroller.core.IOFSwitchFilter;
 import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
@@ -60,6 +57,7 @@ import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState;
 import net.floodlightcontroller.core.util.ListenerDispatcher;
 import net.floodlightcontroller.core.web.CoreWebRoutable;
 import net.floodlightcontroller.counter.ICounterStoreService;
+import net.floodlightcontroller.flowcache.IFlowCacheService;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
 import net.floodlightcontroller.restserver.IRestApiService;
@@ -73,6 +71,7 @@ import net.floodlightcontroller.util.LoadMonitor;
 import org.jboss.netty.bootstrap.ServerBootstrap;
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.Channel;
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.ChannelPipelineFactory;
 import org.jboss.netty.channel.ChannelStateEvent;
@@ -97,12 +96,14 @@ import org.openflow.protocol.OFError.OFPortModFailedCode;
 import org.openflow.protocol.OFError.OFQueueOpFailedCode;
 import org.openflow.protocol.OFFeaturesReply;
 import org.openflow.protocol.OFGetConfigReply;
+import org.openflow.protocol.OFGetConfigRequest;
 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.OFSwitchConfig;
 import org.openflow.protocol.OFType;
@@ -139,6 +140,10 @@ public class Controller implements IFloodlightProviderService,
     protected ConcurrentMap<OFType,
                             ListenerDispatcher<OFType,IOFMessageListener>> 
                                 messageListeners;
+    // OFSwitch driver binding map and order
+    protected Map<String, IOFSwitchDriver>switchBindingMap;
+    protected List<String> switchDescSortedList;
+    
     // The activeSwitches map contains only those switches that are actively
     // being controlled by us -- it doesn't contain switches that are
     // in the slave role
@@ -148,7 +153,7 @@ public class Controller implements IFloodlightProviderService,
     // send role request messages to switches when our role changes to master
     // We add a switch to this set after it successfully completes the
     // handshake. Access to this Set needs to be synchronized with roleChanger
-    protected HashSet<OFSwitchImpl> connectedSwitches;
+    protected HashSet<IOFSwitch> connectedSwitches;
     
     // The controllerNodeIPsCache maps Controller IDs to their IP address. 
     // It's only used by handleControllerNodeIPsChanged
@@ -162,6 +167,7 @@ public class Controller implements IFloodlightProviderService,
     // Module dependencies
     protected IRestApiService restApi;
     protected ICounterStoreService counterStore = null;
+    protected IFlowCacheService bigFlowCacheMgr;
     protected IStorageSourceService storageSource;
     protected IPktInProcessingTimeService pktinProcTime;
     protected IThreadPoolService threadPool;
@@ -333,6 +339,10 @@ public class Controller implements IFloodlightProviderService,
         this.counterStore = counterStore;
     }
     
+    public void setFlowCacheMgr(IFlowCacheService flowCacheMgr) {
+        this.bigFlowCacheMgr = flowCacheMgr;
+    }
+    
     public void setPktInProcessingService(IPktInProcessingTimeService pits) {
         this.pktinProcTime = pits;
     }
@@ -404,7 +414,8 @@ public class Controller implements IFloodlightProviderService,
      */
     protected class OFChannelHandler 
         extends IdleStateAwareChannelUpstreamHandler {
-        protected OFSwitchImpl sw;
+        protected IOFSwitch sw;
+        protected Channel channel;
         protected OFChannelState state;
         
         public OFChannelHandler(OFChannelState state) {
@@ -416,19 +427,11 @@ public class Controller implements IFloodlightProviderService,
                        explanation="A new switch has connected from the " + 
                                 "specified IP address")
         public void channelConnected(ChannelHandlerContext ctx,
-                                     ChannelStateEvent e) throws Exception {
+                                     ChannelStateEvent e) throws Exception {            
+            channel = e.getChannel();
             log.info("New switch connection from {}",
-                     e.getChannel().getRemoteAddress());
-            
-            sw = new OFSwitchImpl();
-            sw.setChannel(e.getChannel());
-            sw.setFloodlightProvider(Controller.this);
-            sw.setThreadPoolService(threadPool);
-            
-            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-            msglist.add(factory.getMessage(OFType.HELLO));
-            e.getChannel().write(msglist);
-
+                     channel.getRemoteAddress());
+            sendHandShakeMessage(OFType.HELLO);
         }
 
         @Override
@@ -623,6 +626,7 @@ public class Controller implements IFloodlightProviderService,
                 // Flush all flow-mods/packet-out/stats generated from this "train"
                 OFSwitchImpl.flush_all();
                 counterStore.updateFlush();
+                bigFlowCacheMgr.updateFlush();
             }
         }
         
@@ -634,73 +638,21 @@ public class Controller implements IFloodlightProviderService,
                         " during handshake {exception}",
                 explanation="Could not process the switch description string",
                 recommendation=LogMessageDoc.CHECK_SWITCH)
-        void processSwitchDescReply() {
+        void processSwitchDescReply(OFStatisticsReply m) {
             try {
                 // Read description, if it has been updated
-                @SuppressWarnings("unchecked")
-                Future<List<OFStatistics>> desc_future =
-                    (Future<List<OFStatistics>>)sw.
-                        getAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE);
-                List<OFStatistics> values = 
-                        desc_future.get(0, TimeUnit.MILLISECONDS);
-                if (values != null) {
-                    OFDescriptionStatistics description = 
-                            new OFDescriptionStatistics();
-                    ChannelBuffer data = 
-                            ChannelBuffers.buffer(description.getLength());
-                    for (OFStatistics f : values) {
-                        f.writeTo(data);
-                        description.readFrom(data);
-                        break; // SHOULD be a list of length 1
-                    }
-                    sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA, 
-                                    description);
-                    sw.setSwitchProperties(description);
-                    data = null;
-
-                    // At this time, also set other switch properties from storage
-                    boolean is_core_switch = false;
-                    IResultSet resultSet = null;
-                    try {
-                        String swid = sw.getStringId();
-                        resultSet = 
-                                storageSource.getRow(SWITCH_CONFIG_TABLE_NAME, swid);
-                        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();
-                            if (row.containsKey(SWITCH_CONFIG_CORE_SWITCH)) {
-                                if (log.isDebugEnabled()) {
-                                    log.debug("Reading SWITCH_IS_CORE_SWITCH " + 
-                                              "config for switch={}, is-core={}",
-                                              sw, row.get(SWITCH_CONFIG_CORE_SWITCH));
-                                }
-                                String ics = 
-                                        (String)row.get(SWITCH_CONFIG_CORE_SWITCH);
-                                is_core_switch = ics.equals("true");
-                            }
-                        }
-                    }
-                    finally {
-                        if (resultSet != null)
-                            resultSet.close();
-                    }
-                    if (is_core_switch) {
-                        sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, 
-                                        new Boolean(true));
-                    }
-                }
-                sw.removeAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE);
+                OFDescriptionStatistics description = 
+                        new OFDescriptionStatistics();
+                ChannelBuffer data = 
+                        ChannelBuffers.buffer(description.getLength());
+                OFStatistics f = m.getFirstStatistics();
+                f.writeTo(data);
+                description.readFrom(data);
+                state.description = description;
                 state.hasDescription = true;
                 checkSwitchReady();
             }
-            catch (InterruptedException ex) {
-                // Ignore
-            }
-            catch (TimeoutException ex) {
-                // Ignore
-            } catch (Exception ex) {
+            catch (Exception ex) {
                 log.error("Exception in reading description " + 
                           " during handshake", ex);
             }
@@ -711,9 +663,11 @@ public class Controller implements IFloodlightProviderService,
          * the switch
          * @throws IOException
          */
-        void sendHelloConfiguration() throws IOException {
+        private void sendHandShakeMessage(OFType type) throws IOException {
             // Send initial Features Request
-            sw.write(factory.getMessage(OFType.FEATURES_REQUEST), null);
+            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+            msglist.add(factory.getMessage(type));
+            channel.write(msglist);
         }
         
         /**
@@ -721,30 +675,40 @@ public class Controller implements IFloodlightProviderService,
          * the features reply
          * @throws IOException
          */
-        void sendFeatureReplyConfiguration() throws IOException {
+        private void sendFeatureReplyConfiguration() throws IOException {
+            List<OFMessage> msglist = new ArrayList<OFMessage>(3);
+
             // Ensure we receive the full packet via PacketIn
-            OFSetConfig config = (OFSetConfig) factory
+            OFSetConfig configSet = (OFSetConfig) factory
                     .getMessage(OFType.SET_CONFIG);
-            config.setMissSendLength((short) 0xffff)
-            .setLengthU(OFSwitchConfig.MINIMUM_LENGTH);
-            sw.write(config, null);
-            sw.write(factory.getMessage(OFType.GET_CONFIG_REQUEST),
-                    null);
+            configSet.setMissSendLength((short) 0xffff)
+                .setLengthU(OFSwitchConfig.MINIMUM_LENGTH);
+            configSet.setXid(-4);
+            msglist.add(configSet);
+            
+            // Verify (need barrier?)
+            OFGetConfigRequest configReq = (OFGetConfigRequest)
+                    factory.getMessage(OFType.GET_CONFIG_REQUEST);
+            configReq.setXid(-3);
+            msglist.add(configReq);
 
             // Get Description to set switch-specific flags
             OFStatisticsRequest req = new OFStatisticsRequest();
             req.setStatisticType(OFStatisticsType.DESC);
+            req.setXid(-2);  // something "large"
             req.setLengthU(req.getLengthU());
-            Future<List<OFStatistics>> dfuture = 
-                    sw.getStatistics(req);
-            sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE,
-                    dfuture);
-
+            msglist.add(req);
+            
+            channel.write(msglist);
         }
         
         protected void checkSwitchReady() {
+            if (!state.switchBindingDone) {
+                bindSwitchToDriver();
+            }
+
             if (state.hsState == HandshakeState.FEATURES_REPLY &&
-                    state.hasDescription && state.hasGetConfigReply) {
+                    state.switchBindingDone) {
                 
                 state.hsState = HandshakeState.READY;
                 
@@ -769,10 +733,10 @@ public class Controller implements IFloodlightProviderService,
                         log.debug("This controller's role is {}, " + 
                                 "sending initial role request msg to {}",
                                 role, sw);
-                        Collection<OFSwitchImpl> swList = new ArrayList<OFSwitchImpl>(1);
+                        Collection<IOFSwitch> swList = new ArrayList<IOFSwitch>(1);
                         swList.add(sw);
                         roleChanger.submitRequest(swList, role);
-                    } 
+                    }
                     else {
                         // Role supported not enabled on controller (for now)
                         // automatically promote switch to active state. 
@@ -788,6 +752,86 @@ public class Controller implements IFloodlightProviderService,
             }
         }
                 
+        protected void bindSwitchToDriver() {
+            if (!state.hasGetConfigReply) {
+                log.debug("Waiting for config reply from switch {}",
+                        channel.getRemoteAddress());
+                return;
+            }
+            if (!state.hasDescription) {
+                log.debug("Waiting for switch description from switch {}",
+                        channel.getRemoteAddress());
+                return;
+            }
+            
+            for (String desc : switchDescSortedList) {
+                if (state.description.getManufacturerDescription()
+                        .startsWith(desc)) {
+                    sw = switchBindingMap.get(desc)
+                            .getOFSwitchImpl(state.description);
+                    if (sw != null) {
+                        break;
+                    }
+                }
+            }
+            if (sw == null) {
+                sw = new OFSwitchImpl();
+            }
+
+            // set switch information
+            sw.setChannel(channel);
+            sw.setFloodlightProvider(Controller.this);
+            sw.setThreadPoolService(threadPool);
+            sw.setFeaturesReply(state.featuresReply);
+            sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA,
+                        state.description);
+            sw.setSwitchProperties(state.description);
+            readPropertyFromStorage();
+
+            state.featuresReply = null;
+            state.description = null;
+            state.switchBindingDone = true;
+
+            log.info("Switch {} bound to class {}",
+                    HexString.toHexString(sw.getId()), sw.getClass().getName());
+            return;
+        }
+        
+        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 = 
+                        storageSource.getRow(SWITCH_CONFIG_TABLE_NAME, swid);
+                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();
+                    if (row.containsKey(SWITCH_CONFIG_CORE_SWITCH)) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("Reading SWITCH_IS_CORE_SWITCH " + 
+                                    "config for switch={}, is-core={}",
+                                    sw, row.get(SWITCH_CONFIG_CORE_SWITCH));
+                        }
+                        String ics = 
+                                (String)row.get(SWITCH_CONFIG_CORE_SWITCH);
+                        is_core_switch = ics.equals("true");
+                    }
+                }
+            }
+            finally {
+                if (resultSet != null)
+                    resultSet.close();
+            }
+            if (is_core_switch) {
+                sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, 
+                        new Boolean(true));
+            }
+        }
+
         /* Handle a role reply message we received from the switch. Since
          * netty serializes message dispatch we don't need to synchronize 
          * against other receive operations from the same switch, so no need
@@ -950,7 +994,7 @@ public class Controller implements IFloodlightProviderService,
                     
                     if (state.hsState.equals(HandshakeState.START)) {
                         state.hsState = HandshakeState.HELLO;
-                        sendHelloConfiguration();
+                        sendHandShakeMessage(OFType.FEATURES_REQUEST);
                     } else {
                         throw new SwitchStateException("Unexpected HELLO from " 
                                                        + sw);
@@ -960,7 +1004,9 @@ public class Controller implements IFloodlightProviderService,
                     OFEchoReply reply =
                         (OFEchoReply) factory.getMessage(OFType.ECHO_REPLY);
                     reply.setXid(m.getXid());
-                    sw.write(reply, null);
+                    List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+                    msglist.add(reply);
+                    channel.write(msglist);
                     break;
                 case ECHO_REPLY:
                     break;
@@ -968,15 +1014,16 @@ public class Controller implements IFloodlightProviderService,
                     if (log.isTraceEnabled())
                         log.trace("Features Reply from {}", sw);
                     
-                    sw.setFeaturesReply((OFFeaturesReply) m);
                     if (state.hsState.equals(HandshakeState.HELLO)) {
                         sendFeatureReplyConfiguration();
+                        state.featuresReply = (OFFeaturesReply) m;
                         state.hsState = HandshakeState.FEATURES_REPLY;
                         // uncomment to enable "dumb" switches like cbench
                         // state.hsState = HandshakeState.READY;
                         // addSwitch(sw);
                     } else {
                         // return results to rest api caller
+                        sw.setFeaturesReply((OFFeaturesReply) m);
                         sw.deliverOFFeaturesReply(m);
                     }
                     break;
@@ -1036,14 +1083,15 @@ public class Controller implements IFloodlightProviderService,
                             state.firstRoleReplyReceived = true;
                             sw.deliverRoleRequestNotSupported(error.getXid());
                             synchronized(roleChanger) {
-                                if (sw.role == null && Controller.this.role==Role.SLAVE) {
+                                if (sw.getRole() == null &&
+                                        Controller.this.role==Role.SLAVE) {
                                     // the switch doesn't understand role request
                                     // messages and the current controller role is
                                     // slave. We need to disconnect the switch. 
                                     // @see RoleChanger for rationale
                                     sw.getChannel().close();
                                 }
-                                else if (sw.role == null) {
+                                else if (sw.getRole() == null) {
                                     // Controller's role is master: add to
                                     // active 
                                     // TODO: check if clearing flow table is
@@ -1090,9 +1138,10 @@ public class Controller implements IFloodlightProviderService,
                         String em = "Unexpected STATS_REPLY from " + sw;
                         throw new SwitchStateException(em);
                     }
-                    sw.deliverStatisticsReply(m);
-                    if (sw.hasAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE)) {
-                        processSwitchDescReply();
+                    if (sw == null) { 
+                        processSwitchDescReply((OFStatisticsReply) m);
+                    } else {
+                        sw.deliverStatisticsReply(m);
                     }
                     break;
                 case PORT_STATUS:
@@ -1106,41 +1155,44 @@ public class Controller implements IFloodlightProviderService,
             }
             
             if (shouldHandleMessage) {
-                sw.getListenerReadLock().lock();
-                try {
-                    if (sw.isConnected()) {
-                        if (!state.hsState.equals(HandshakeState.READY)) {
-                            log.debug("Ignoring message type {} received " + 
-                                      "from switch {} before switch is " + 
-                                      "fully configured.", m.getType(), sw);
-                        }
-                        // Check if the controller is in the slave role for the 
-                        // switch. If it is, then don't dispatch the message to 
-                        // the listeners.
-                        // TODO: Should we dispatch messages that we expect to 
-                        // receive when we're in the slave role, e.g. port 
-                        // status messages? Since we're "hiding" switches from 
-                        // the listeners when we're in the slave role, then it 
-                        // seems a little weird to dispatch port status messages
-                        // to them. On the other hand there might be special 
-                        // modules that care about all of the connected switches
-                        // and would like to receive port status notifications.
-                        else if (sw.getRole() == Role.SLAVE) {
-                            // Don't log message if it's a port status message 
-                            // since we expect to receive those from the switch 
-                            // and don't want to emit spurious messages.
-                            if (m.getType() != OFType.PORT_STATUS) {
-                                log.debug("Ignoring message type {} received " +
-                                        "from switch {} while in the slave role.",
-                                        m.getType(), sw);
+                // WARNING: sw is null if handshake is not complete
+                if (!state.hsState.equals(HandshakeState.READY)) {
+                    log.debug("Ignoring message type {} received " + 
+                              "from switch {} before switch is " + 
+                              "fully configured.", m.getType(), sw);
+                } else {
+                    sw.getListenerReadLock().lock();
+                    try {
+
+                        if (sw.isConnected()) {
+                            // Check if the controller is in the slave role for the 
+                            // switch. If it is, then don't dispatch the message to 
+                            // the listeners.
+                            // TODO: Should we dispatch messages that we expect to 
+                            // receive when we're in the slave role, e.g. port 
+                            // status messages? Since we're "hiding" switches from 
+                            // the listeners when we're in the slave role, then it 
+                            // seems a little weird to dispatch port status messages
+                            // to them. On the other hand there might be special 
+                            // modules that care about all of the connected switches
+                            // and would like to receive port status notifications.
+                            if (sw.getRole() == Role.SLAVE) {
+                                // Don't log message if it's a port status message 
+                                // since we expect to receive those from the switch 
+                                // and don't want to emit spurious messages.
+                                if (m.getType() != OFType.PORT_STATUS) {
+                                    log.debug("Ignoring message type {} received " +
+                                            "from switch {} while in the slave role.",
+                                            m.getType(), sw);
+                                }
+                            } else {
+                                handleMessage(sw, m, null);
                             }
-                        } else {
-                            handleMessage(sw, m, null);
                         }
                     }
-                }
-                finally {
-                    sw.getListenerReadLock().unlock();
+                    finally {
+                        sw.getListenerReadLock().unlock();
+                    }
                 }
             }
         }
@@ -1390,7 +1442,7 @@ public class Controller implements IFloodlightProviderService,
     protected void addSwitch(IOFSwitch sw, boolean shouldClearFlowMods) {
         // TODO: is it safe to modify the HashMap without holding 
         // the old switch's lock?
-        OFSwitchImpl oldSw = (OFSwitchImpl) this.activeSwitches.put(sw.getId(), sw);
+        IOFSwitch oldSw = this.activeSwitches.put(sw.getId(), sw);
         if (sw == oldSw) {
             // Note == for object equality, not .equals for value
             log.info("New add switch for pre-existing switch {}", sw);
@@ -1854,8 +1906,11 @@ public class Controller implements IFloodlightProviderService,
                                                          IOFMessageListener>>();
         this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
         this.haListeners = new CopyOnWriteArraySet<IHAListener>();
+        this.switchBindingMap =
+                new ConcurrentHashMap<String, IOFSwitchDriver>();
+        this.switchDescSortedList = new ArrayList<String>();
         this.activeSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
-        this.connectedSwitches = new HashSet<OFSwitchImpl>();
+        this.connectedSwitches = new HashSet<IOFSwitch>();
         this.controllerNodeIPsCache = new HashMap<String, String>();
         this.updates = new LinkedBlockingQueue<IUpdate>();
         this.factory = new BasicFactory();
@@ -2050,4 +2105,29 @@ public class Controller implements IFloodlightProviderService,
     public boolean getAlwaysClearFlowsOnSwAdd() {
         return this.alwaysClearFlowsOnSwAdd;
     }
+
+    @Override
+    public void addOFSwitchDriver(String description, IOFSwitchDriver driver) {
+        IOFSwitchDriver existingDriver = switchBindingMap.get(description);
+        if (existingDriver != null) {
+            log.warn("Failed to add OFSwitch driver for {}, " +
+                     "already registered", description);
+            return;
+        }
+        switchBindingMap.put(description, driver);
+
+        // Sort so we match the longest string first
+        int index = -1;
+        for (String desc : switchDescSortedList) {
+            if (description.compareTo(desc) < 0) {
+                index = switchDescSortedList.indexOf(desc);
+                switchDescSortedList.add(index, description);
+                break;
+            }
+        }
+        if (index == -1) {  // append to list
+            switchDescSortedList.add(description);
+        }
+    }
+
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java
index ad5a3772fa6e47ae6f1356d93455d597b1a36530..9a1f071f849569afb930b02d2728699878c489f3 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java
@@ -17,6 +17,9 @@
 
 package net.floodlightcontroller.core.internal;
 
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.statistics.OFDescriptionStatistics;
+
 /**
  * Wrapper class to hold state for the OpenFlow switch connection
  * @author readams
@@ -53,6 +56,10 @@ class OFChannelState {
     protected volatile HandshakeState hsState = HandshakeState.START;
     protected boolean hasGetConfigReply = false;
     protected boolean hasDescription = false;
+    protected boolean switchBindingDone = false;
+    
+    protected OFFeaturesReply featuresReply = null;
+    protected OFDescriptionStatistics description = null;
     
     // The firstRoleReplyRecevied flag indicates if we have received the
     // first role reply message on this connection (in response to the 
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
index 83fc182dc2bb3af03283fdc72a9229dd4f3458e5..0909709c2c5460c51f20bd87a0246e760b655d3f 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
@@ -129,12 +129,12 @@ public class OFSwitchImpl implements IOFSwitch {
     protected long datapathId;
 
     public static IOFSwitchFeatures switchFeatures;
-    protected static final ThreadLocal<Map<OFSwitchImpl,List<OFMessage>>> local_msg_buffer =
-            new ThreadLocal<Map<OFSwitchImpl,List<OFMessage>>>() {
-            @Override
-            protected Map<OFSwitchImpl,List<OFMessage>> initialValue() {
-                return new HashMap<OFSwitchImpl,List<OFMessage>>();
-            }
+    protected static final 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>>();
+        }
     };
     
     // for managing our map sizes
@@ -214,7 +214,7 @@ public class OFSwitchImpl implements IOFSwitch {
     
     @Override
     public void write(OFMessage m, FloodlightContext bc) throws IOException {
-        Map<OFSwitchImpl,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        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>();
@@ -569,7 +569,7 @@ public class OFSwitchImpl implements IOFSwitch {
 
     @Override
     public void flush() {
-        Map<OFSwitchImpl,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        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)) {
             try {
@@ -583,8 +583,8 @@ public class OFSwitchImpl implements IOFSwitch {
     }
 
     public static void flush_all() {
-        Map<OFSwitchImpl,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
-        for (OFSwitchImpl sw : msg_buffer_map.keySet()) {
+        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        for (IOFSwitch sw : msg_buffer_map.keySet()) {
             sw.flush();
         }
     }
@@ -634,7 +634,7 @@ public class OFSwitchImpl implements IOFSwitch {
      *        RoleChanger can check for timeouts.
      * @return transaction id of the role request message that was sent
      */
-    protected int sendNxRoleRequest(Role role, long cookie)
+    public int sendNxRoleRequest(Role role, long cookie)
             throws IOException {
         synchronized(pendingRoleRequests) {
             // Convert the role enum to the appropriate integer constant used
@@ -713,7 +713,7 @@ public class OFSwitchImpl implements IOFSwitch {
                 explanation="The switch sent an unexpected HA role reply",
                 recommendation=HA_CHECK_SWITCH)                           
     })
-    protected void deliverRoleReply(int xid, Role role) {
+    public void deliverRoleReply(int xid, Role role) {
         synchronized(pendingRoleRequests) {
             PendingRoleRequestEntry head = pendingRoleRequests.poll();
             if (head == null) {
@@ -755,7 +755,7 @@ public class OFSwitchImpl implements IOFSwitch {
      * @param xid
      * @return 
      */
-    protected boolean checkFirstPendingRoleRequestXid (int xid) {
+    public boolean checkFirstPendingRoleRequestXid (int xid) {
         synchronized(pendingRoleRequests) {
             PendingRoleRequestEntry head = pendingRoleRequests.peek();
             if (head == null)
@@ -771,7 +771,7 @@ public class OFSwitchImpl implements IOFSwitch {
      * @param cookie
      * @return
      */
-    protected boolean checkFirstPendingRoleRequestCookie(long cookie) {
+    public boolean checkFirstPendingRoleRequestCookie(long cookie) {
         synchronized(pendingRoleRequests) {
             PendingRoleRequestEntry head = pendingRoleRequests.peek();
             if (head == null)
@@ -788,7 +788,7 @@ public class OFSwitchImpl implements IOFSwitch {
      * Otherwise we ignore it.
      * @param xid
      */
-    protected void deliverRoleRequestNotSupported(int xid) {
+    public void deliverRoleRequestNotSupported(int xid) {
         synchronized(pendingRoleRequests) {
             PendingRoleRequestEntry head = pendingRoleRequests.poll();
             this.role = null;
@@ -857,4 +857,10 @@ public class OFSwitchImpl implements IOFSwitch {
     public byte getTables() {
         return tables;
     }
+
+
+    @Override
+    public void setFloodlightProvider(Controller controller) {
+        floodlightProvider = controller;
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
index 6378136e9f5022f55b10db866a497d5484c2f3ec..008e54232cfbe0bf2dd47e20f3690b11d57ad42e 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
@@ -133,12 +133,12 @@ public class RoleChanger {
             TIMEOUT
         }
         // The set of switches to work on
-        public Collection<OFSwitchImpl> switches;
+        public Collection<IOFSwitch> switches;
         public Role role;
         public Type type;
         // the time when the task should run as nanoTime() 
         public long deadline;
-        public RoleChangeTask(Collection<OFSwitchImpl> switches, Role role, long deadline) {
+        public RoleChangeTask(Collection<IOFSwitch> switches, Role role, long deadline) {
             this.switches = switches;
             this.role = role;
             this.type = Type.REQUEST;
@@ -209,14 +209,14 @@ public class RoleChanger {
     }
     
     
-    public synchronized void submitRequest(Collection<OFSwitchImpl> switches, Role role) {
+    public synchronized void submitRequest(Collection<IOFSwitch> switches, Role role) {
         long deadline = System.nanoTime();
         // Grrr. stupid DelayQueue. Make sre we have at least 10ms between 
         // role request messages.
         if (deadline - lastSubmitTime < 10 * 1000*1000) 
             deadline = lastSubmitTime + 10 * 1000*1000;
         // make a copy of the list 
-        ArrayList<OFSwitchImpl> switches_copy = new ArrayList<OFSwitchImpl>(switches);
+        ArrayList<IOFSwitch> switches_copy = new ArrayList<IOFSwitch>(switches);
         RoleChangeTask req = new RoleChangeTask(switches_copy, role, deadline);
         pendingTasks.put(req);
         lastSubmitTime = deadline;
@@ -237,7 +237,7 @@ public class RoleChanger {
             explanation="An I/O error occurred while attempting to change " +
             		"the switch HA role.",
             recommendation=LogMessageDoc.CHECK_SWITCH)                              
-    protected void sendRoleRequest(Collection<OFSwitchImpl> switches,
+    protected void sendRoleRequest(Collection<IOFSwitch> switches,
                                    Role role, long cookie) {
         // There are three cases to consider:
         //
@@ -267,9 +267,9 @@ public class RoleChanger {
         //    controller in its list of controllers. Eventually (hopefully, if
         //    things are configured correctly) it will walk down its list of
         //    controllers and connect to the current master controller.
-        Iterator<OFSwitchImpl> iter = switches.iterator();
+        Iterator<IOFSwitch> iter = switches.iterator();
         while(iter.hasNext()) {
-            OFSwitchImpl sw = iter.next();
+            IOFSwitch sw = iter.next();
             try {
                 Boolean supportsNxRole = (Boolean)
                         sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
@@ -308,9 +308,9 @@ public class RoleChanger {
             explanation="Timed out waiting for the switch to respond to " +
             		"a request to change the HA role.",
             recommendation=LogMessageDoc.CHECK_SWITCH)                              
-    protected void verifyRoleReplyReceived(Collection<OFSwitchImpl> switches,
+    protected void verifyRoleReplyReceived(Collection<IOFSwitch> switches,
                                    long cookie) {
-        for (OFSwitchImpl sw: switches) {
+        for (IOFSwitch sw: switches) {
             if (sw.checkFirstPendingRoleRequestCookie(cookie)) {
                 sw.getChannel().close();
                 log.warn("Timeout while waiting for role reply from switch {}."
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java
index ad29a947fbed2a3af94e24259fe58701f7c5e778..e161825a6ad5bea2c23732c3f898d03f25fcb0fe 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/IDeviceService.java
@@ -97,9 +97,13 @@ public interface IDeviceService extends IFloodlightService {
      * the given source device.  The source device is important since
      * there could be ambiguity in the destination device without the
      * attachment point information. 
+     * Search for a device in a given entity class. This is the same as 
+     * the lookup process for destination devices. 
      * 
-     * @param source the source device.  The returned destination will be
-     * in the same entity class as the source.
+     * Only the key fields as defined by the reference entity class will
+     * be important in this search. All key fields MUST be supplied.
+     * 
+     * @param entityClass The entity class in which to perform the lookup.
      * @param macAddress The MAC address for the destination
      * @param vlan the VLAN if available
      * @param ipv4Address The IP address if available.
@@ -109,10 +113,10 @@ public interface IDeviceService extends IFloodlightService {
      * @throws IllegalArgumentException if not all key fields of the
      * source's {@link IEntityClass} are specified.
      */
-    public IDevice findDestDevice(IDevice source,
-                                  long macAddress, Short vlan,
-                                  Integer ipv4Address)
-                                  throws IllegalArgumentException;
+    public IDevice findClassDevice(IEntityClass entityClass,
+                                   long macAddress, Short vlan,
+                                   Integer ipv4Address)
+                                   throws IllegalArgumentException;
 
     /**
      * Get an unmodifiable collection view over all devices currently known.
@@ -158,14 +162,13 @@ public interface IDeviceService extends IFloodlightService {
 
     /**
      * Find devices that match the provided query.  Only the index for
-     * the class of the specified reference device will be searched.  
+     * the specified class will be searched.  
      * Any fields that are null will not be included in the query.  If
      * there is an index for the query, then it will be performed
      * efficiently using the index. Otherwise, there will be a full scan
      * of the device list.
      * 
-     * @param reference The reference device to refer to when finding
-     * entity classes.
+     * @param entityClass The entity class in which to perform the query
      * @param macAddress The MAC address
      * @param vlan the VLAN
      * @param ipv4Address the ipv4 address
@@ -175,7 +178,7 @@ public interface IDeviceService extends IFloodlightService {
      * @see IDeviceService#queryClassDevices(Long, 
      * Short, Integer, Long, Integer)
      */
-    public Iterator<? extends IDevice> queryClassDevices(IDevice reference,
+    public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass,
                                                          Long macAddress,
                                                          Short vlan,
                                                          Integer ipv4Address, 
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
index 033d0c11e5c824db6da6fd8a0b64ece435fdb7fe..9f836b1c8c6d7b162d693da0dfc8093dbd3fd82c 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
@@ -345,7 +345,7 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
     }
 
     @Override
-    public IDevice findDestDevice(IDevice source, long macAddress,
+    public IDevice findClassDevice(IEntityClass entityClass, long macAddress,
                                   Short vlan, Integer ipv4Address) 
                                   throws IllegalArgumentException {
         if (vlan != null && vlan.shortValue() <= 0)
@@ -354,13 +354,13 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
             ipv4Address = null;
         Entity e = new Entity(macAddress, vlan, ipv4Address,
                               null, null, null);
-        if (source == null || 
-                !allKeyFieldsPresent(e, source.getEntityClass().getKeyFields())) {
+        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(source, e);
+        return findDestByEntity(entityClass, e);
     }
 
     @Override
@@ -421,13 +421,12 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
     }
 
     @Override
-    public Iterator<? extends IDevice> queryClassDevices(IDevice reference,
+    public Iterator<? extends IDevice> queryClassDevices(IEntityClass entityClass,
                                                          Long macAddress,
                                                          Short vlan,
                                                          Integer ipv4Address,
                                                          Long switchDPID,
                                                          Integer switchPort) {
-        IEntityClass entityClass = reference.getEntityClass();
         ArrayList<Iterator<Device>> iterators =
                 new ArrayList<Iterator<Device>>();
         ClassState classState = getClassState(entityClass);
@@ -604,7 +603,7 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
         Entity dstEntity = getEntityFromFlowMod(ofm.ofmWithSwDpid, false);
         Device dstDevice = null;
         if (dstEntity != null) {
-            dstDevice = findDestByEntity(srcDevice, dstEntity);
+            dstDevice = findDestByEntity(srcDevice.getEntityClass(), dstEntity);
             if (dstDevice != null)
                 fcStore.put(ofm.cntx, CONTEXT_DST_DEVICE, dstDevice);
         }
@@ -769,7 +768,7 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
         Device dstDevice = null;
         if (dstEntity != null) {
             dstDevice =
-                    findDestByEntity(srcDevice, dstEntity);
+                    findDestByEntity(srcDevice.getEntityClass(), dstEntity);
             if (dstDevice != null)
                 fcStore.put(cntx, CONTEXT_DST_DEVICE, dstDevice);
         }
@@ -980,13 +979,13 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
      * @param dstEntity the entity to look up
      * @return an {@link Device} or null if no device is found.
      */
-    protected Device findDestByEntity(IDevice source,
+    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
@@ -996,7 +995,7 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
             // For the second case, we'll need to match up the
             // destination device with the class of the source
             // device.
-            ClassState classState = getClassState(source.getEntityClass());
+            ClassState classState = getClassState(reference);
             if (classState.classIndex == null) {
                 return null;
             }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowCache.java b/src/main/java/net/floodlightcontroller/flowcache/FlowCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e3afe548f80d91f783764c066e344afbee0ca77
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowCache.java
@@ -0,0 +1,87 @@
+package net.floodlightcontroller.flowcache;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.openflow.protocol.OFMatchWithSwDpid;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.devicemanager.SwitchPort;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+
+public class FlowCache implements IFloodlightModule, IFlowCacheService {
+
+    @Override
+    public void submitFlowCacheQuery(FCQueryObj query) {}
+
+    @Override
+    public void deleteFlowCacheBySwitch(long switchDpid) {}
+
+    @Override
+    public void updateFlush() {}
+    
+    @Override
+    public boolean addFlow(String appInstName, OFMatchWithSwDpid ofm, 
+                           Long cookie, long srcSwDpid, 
+                           short inPort, short priority, byte action) {
+        return true;
+    }
+
+    @Override
+    public boolean addFlow(FloodlightContext cntx, OFMatchWithSwDpid ofm, 
+                           Long cookie, SwitchPort swPort, 
+                           short priority, byte action) {
+        return true;
+    }
+
+    @Override
+    public boolean moveFlowToDifferentApplInstName(OFMatchReconcile ofMRc) {
+        return true;
+    }
+
+    @Override
+    public void deleteAllFlowsAtASourceSwitch(IOFSwitch sw) {}
+    
+    @Override
+    public void querySwitchFlowTable(long swDpid) {}
+    
+    // IFloodlightModule
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l = 
+                new ArrayList<Class<? extends IFloodlightService>>();
+       l.add(IFlowCacheService.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(IFlowCacheService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> 
+                                                    getModuleDependencies() {
+        return null;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {}
+
+    @Override
+    public void startUp(FloodlightModuleContext context) {}
+}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
index d5d323d75f3c27da63a4d452cbee78c82aafac84..98f0f88804bebd8f39f3fac5044db84cc4a8dbed 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
@@ -60,9 +60,9 @@ public class FlowReconcileManager
     String controllerPktInCounterName;
     protected SimpleCounter lastPacketInCounter;
     
-    protected static int MAX_SYSTEM_LOAD_PER_SECOND = 50000;
+    protected static int MAX_SYSTEM_LOAD_PER_SECOND = 10000;
     /** a minimum flow reconcile rate so that it won't stave */
-    protected static int MIN_FLOW_RECONCILE_PER_SECOND = 1000;
+    protected static int MIN_FLOW_RECONCILE_PER_SECOND = 200;
     
     /** once per second */
     protected static int FLOW_RECONCILE_DELAY_MILLISEC = 10;
@@ -251,6 +251,9 @@ public class FlowReconcileManager
                                            packetInName);
     }
     
+    protected void updateFlush() {
+        // No-OP
+    }
     /**
      * Feed the flows into the flow reconciliation pipeline.
      * @return true if more flows to be reconciled
@@ -309,6 +312,8 @@ public class FlowReconcileManager
                 }
             }
             flowReconcileThreadRunCount++;
+            // Flush the flowCache counters.
+            updateFlush();
         } else {
             if (logger.isTraceEnabled()) {
                 logger.trace("No flow to be reconciled.");
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java
index 8e44ed3303d054e78b6e40107f7ea0fbeb1ac2a5..4082ef6f982ae07c6f05a75d980b31df7cb27492 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowCacheService.java
@@ -84,15 +84,6 @@ public interface IFlowCacheService extends IFloodlightService {
      */
     public void submitFlowCacheQuery(FCQueryObj query);
 
-    /**
-     * Deactivates all flows in the flow cache for which the source switch
-     * matches the given switchDpid. Note that the flows are NOT deleted
-     * from the cache.
-     *
-     * @param switchDpid Data-path identifier of the source switch
-     */
-    public void deactivateFlowCacheBySwitch(long switchDpid);
-
     /**
      * Deletes all flows in the flow cache for which the source switch
      * matches the given switchDpid. 
@@ -101,6 +92,12 @@ public interface IFlowCacheService extends IFloodlightService {
      */
     public void deleteFlowCacheBySwitch(long switchDpid);
 
+    /**
+     * Flush Local Counter Updates
+     *
+     */
+    public void updateFlush();
+    
     /**
      * Add a flow to the flow-cache - called when a flow-mod is about to be
      * written to a set of switches. If it returns false then it should not
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index be71dd1c4e774be390438a59db7489736c38d962..45e02915901cb759c3dd6b76efb439e4e14e344d 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -127,6 +127,10 @@ IFloodlightModule, IInfoProvider, IHAListener {
     protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
 
     // 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";
@@ -194,7 +198,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
      * Flag to indicate if automatic port fast is enabled or not.
      * Default is set to false -- Initialized in the init method as well.
      */
-    boolean autoPortFastFeature = false;
+    public final boolean AUTOPORTFAST_DEFAULT= false;
+    boolean autoPortFastFeature = AUTOPORTFAST_DEFAULT;
 
     /**
      * Map from link to the most recent time it was verified functioning
@@ -1723,6 +1728,12 @@ IFloodlightModule, IInfoProvider, IHAListener {
 
     @Override
     public void rowsModified(String tableName, Set<Object> rowKeys) {
+
+        if (tableName.equals(TOPOLOGY_TABLE_NAME)) {
+            readTopologyConfigFromStorage();
+            return;
+        }
+
         Map<Long, IOFSwitch> switches = floodlightProvider.getSwitches();
         ArrayList<IOFSwitch> updated_switches = new ArrayList<IOFSwitch>();
         for(Object key: rowKeys) {
@@ -1782,7 +1793,9 @@ IFloodlightModule, IInfoProvider, IHAListener {
 
     @Override
     public void rowsDeleted(String tableName, Set<Object> rowKeys) {
-        // Ignore delete events, the switch delete will do the right thing on it's own
+        // Ignore delete events, the switch delete will do the 
+        // right thing on it's own.
+        readTopologyConfigFromStorage();
     }
 
     // IFloodlightModule classes
@@ -1882,12 +1895,17 @@ IFloodlightModule, IInfoProvider, IHAListener {
             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);
@@ -2068,6 +2086,7 @@ IFloodlightModule, IInfoProvider, IHAListener {
                                 "to HA change from SLAVE->MASTER");
                     }
                     clearAllLinks();
+                    readTopologyConfigFromStorage();
                     log.debug("Role Change to Master: Rescheduling discovery task.");
                     discoveryTask.reschedule(1, TimeUnit.MICROSECONDS);
                 }
@@ -2103,4 +2122,21 @@ IFloodlightModule, IInfoProvider, IHAListener {
     public void setAutoPortFastFeature(boolean autoPortFastFeature) {
         this.autoPortFastFeature = autoPortFastFeature;
     }
+
+    public 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");
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
index 85ac6b8446eecb1594e861535b348fb8f57a00e4..752c7f82cb1604fe6480eb12d76b7ee60418d967 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
@@ -72,19 +72,19 @@ public class TopologyInstance {
         this.blockedPorts = new HashSet<NodePortTuple>();
         this.blockedLinks = new HashSet<Link>();
     }
-    
+
     public TopologyInstance(Map<Long, Set<Short>> switchPorts,
                             Map<NodePortTuple, Set<Link>> switchPortLinks)
     {
         this.switches = new HashSet<Long>(switchPorts.keySet());
         this.switchPorts = new HashMap<Long, Set<Short>>(switchPorts);
         this.switchPortLinks = new HashMap<NodePortTuple, 
-                                           Set<Link>>(switchPortLinks);
+                Set<Link>>(switchPortLinks);
         this.broadcastDomainPorts = new HashSet<NodePortTuple>();
         this.tunnelPorts = new HashSet<NodePortTuple>();
         this.blockedPorts = new HashSet<NodePortTuple>();
         this.blockedLinks = new HashSet<Link>();
-        
+
         clusters = new HashSet<Cluster>();
         switchClusterMap = new HashMap<Long, Cluster>();
     }
@@ -147,18 +147,20 @@ public class TopologyInstance {
         calculateBroadcastNodePortsInClusters();
 
         // Step 4. print topology.
-        // printTopology();
+        printTopology();
     }
 
     public void printTopology() {
-        log.trace("-----------------------------------------------");
-        log.trace("Links: {}",this.switchPortLinks);
-        log.trace("broadcastDomainPorts: {}", broadcastDomainPorts);
-        log.trace("tunnelPorts: {}", tunnelPorts);
-        log.trace("clusters: {}", clusters);
-        log.trace("destinationRootedTrees: {}", destinationRootedTrees);
-        log.trace("clusterBroadcastNodePorts: {}", clusterBroadcastNodePorts);
-        log.trace("-----------------------------------------------");
+        if (log.isTraceEnabled()) {
+            log.trace("-----------------------------------------------");
+            log.trace("Links: {}",this.switchPortLinks);
+            log.trace("broadcastDomainPorts: {}", broadcastDomainPorts);
+            log.trace("tunnelPorts: {}", tunnelPorts);
+            log.trace("clusters: {}", clusters);
+            log.trace("destinationRootedTrees: {}", destinationRootedTrees);
+            log.trace("clusterBroadcastNodePorts: {}", clusterBroadcastNodePorts);
+            log.trace("-----------------------------------------------");
+        }
     }
 
     protected void addLinksToOpenflowDomains() {
@@ -257,6 +259,8 @@ public class TopologyInstance {
         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>();
 
         //Assign the DFS object with right values.
         currDFS.setVisited(true);
@@ -296,13 +300,16 @@ public class TopologyInstance {
                     } else if (!dstDFS.isVisited()) {
                         // make a DFS visit
                         currIndex = dfsTraverse(currDFS.getDfsIndex(), currIndex, dstSw,
-                                                dfsList, currSet);
+                                                dfsList, myCurrSet);
 
                         if (currIndex < 0) return -1;
 
                         // update lowpoint after the visit
                         if (dstDFS.getLowpoint() < currDFS.getLowpoint())
                             currDFS.setLowpoint(dstDFS.getLowpoint());
+
+                        nodesInMyCluster.addAll(myCurrSet);
+                        myCurrSet.clear();
                     }
                     // else, it is a node already visited with a higher
                     // dfs index, just ignore.
@@ -310,8 +317,8 @@ public class TopologyInstance {
             }
         }
 
-        // Add current node to currSet.
-        currSet.add(currSw);
+        nodesInMyCluster.add(currSw);
+        currSet.addAll(nodesInMyCluster);
 
         // Cluster computation.
         // If the node's lowpoint is greater than its parent's DFS index,
@@ -431,9 +438,32 @@ public class TopologyInstance {
 
         public int compareTo(NodeDist o) {
             if (o.dist == this.dist) {
-                return (int)(o.node - this.node);
+                return (int)(this.node - o.node);
             }
-            return o.dist - this.dist;
+            return this.dist - o.dist;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            NodeDist other = (NodeDist) obj;
+            if (!getOuterType().equals(other.getOuterType()))
+                return false;
+            if (node == null) {
+                if (other.node != null)
+                    return false;
+            } else if (!node.equals(other.node))
+                return false;
+            return true;
+        }
+
+        private TopologyInstance getOuterType() {
+            return TopologyInstance.this;
         }
     }
 
@@ -465,13 +495,15 @@ public class TopologyInstance {
 
             for (Link link: c.links.get(cnode)) {
                 Long neighbor;
-                
+
                 if (isDstRooted == true) neighbor = link.getSrc();
                 else neighbor = link.getDst();
-                
+
                 // links directed toward cnode will result in this condition
-                // if (neighbor == cnode) continue;
-                
+                if (neighbor.equals(cnode)) continue;
+
+                if (seen.containsKey(neighbor)) continue;
+
                 if (linkCost == null || linkCost.get(link)==null) w = 1;
                 else w = linkCost.get(link);
 
@@ -480,7 +512,13 @@ public class TopologyInstance {
                     cost.put(neighbor, ndist);
                     nexthoplinks.put(neighbor, link);
                     //nexthopnodes.put(neighbor, cnode);
-                    nodeq.add(new NodeDist(neighbor, ndist));
+                    NodeDist ndTemp = new NodeDist(neighbor, ndist);
+                    // Remove an object that's already in there.
+                    // Note that the comparison is based on only the node id,
+                    // and not node id and distance.
+                    nodeq.remove(ndTemp);
+                    // add the current object to the queue.
+                    nodeq.add(ndTemp);
                 }
             }
         }
@@ -744,7 +782,8 @@ public class TopologyInstance {
 
     public NodePortTuple getIncomingSwitchPort(long src, short srcPort,
                                                long dst, short dstPort) {
-     // Use this function to reinject traffic from a different port if needed.
+        // Use this function to reinject traffic from a 
+        // different port if needed.
         return new NodePortTuple(src, srcPort);
     }
 
@@ -768,8 +807,8 @@ public class TopologyInstance {
     }
 
     public NodePortTuple
-            getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst,
-                                            short dstPort) {
+    getAllowedOutgoingBroadcastPort(long src, short srcPort, long dst,
+                                    short dstPort) {
         // TODO Auto-generated method stub
         return null;
     }
@@ -780,3 +819,4 @@ public class TopologyInstance {
         return null;
     }
 }
+
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 0225a2b25a00e0e13c491d4af6de790db232a072..07985a1268a9a66755c1745fc9696c9272c290ec 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
@@ -4,6 +4,7 @@ net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl
 net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager
 net.floodlightcontroller.topology.TopologyManager
 net.floodlightcontroller.forwarding.Forwarding
+net.floodlightcontroller.flowcache.FlowCache
 net.floodlightcontroller.flowcache.FlowReconcileManager
 net.floodlightcontroller.core.OFMessageFilterManager
 net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher
diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties
index 56d42eb82b94eed17ac16d73f20f6e9bbf34dff0..5bb2e28832f44fd7c4db3984002c102f71bc7933 100644
--- a/src/main/resources/floodlightdefault.properties
+++ b/src/main/resources/floodlightdefault.properties
@@ -2,9 +2,14 @@ floodlight.modules = net.floodlightcontroller.storage.memory.MemoryStorageSource
 net.floodlightcontroller.core.FloodlightProvider,\
 net.floodlightcontroller.threadpool.ThreadPool,\
 net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
+net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier,\
 net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
 net.floodlightcontroller.firewall.Firewall,\
 net.floodlightcontroller.forwarding.Forwarding,\
+net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager, \
+net.floodlightcontroller.topology.TopologyManager, \
+net.floodlightcontroller.flowcache.FlowCache, \
+net.floodlightcontroller.flowcache.FlowReconcileManager, \
 net.floodlightcontroller.jython.JythonDebugInterface,\
 net.floodlightcontroller.counter.CounterStore,\
 net.floodlightcontroller.perfmon.PktInProcessingTime,\
diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
index 899f57834cfcd777d4c1a08104c3871822e8bd33..177c46dbb5bcd534d8f4426b4a24a0be012c5d44 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
@@ -21,7 +21,6 @@ import static org.easymock.EasyMock.*;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -39,6 +38,7 @@ import net.floodlightcontroller.core.IOFMessageFilterManagerService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IListener.Command;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitchDriver;
 import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.OFMessageFilterManager;
 import net.floodlightcontroller.core.internal.Controller.IUpdate;
@@ -64,6 +64,7 @@ import net.floodlightcontroller.test.FloodlightTestCase;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 
 import org.easymock.Capture;
+import org.easymock.EasyMock;
 import org.jboss.netty.channel.Channel;
 import org.junit.Test;
 import org.openflow.protocol.OFError;
@@ -83,6 +84,7 @@ import org.openflow.protocol.OFVendor;
 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.protocol.statistics.OFFlowStatisticsReply;
 import org.openflow.protocol.statistics.OFStatistics;
 import org.openflow.protocol.statistics.OFStatisticsType;
@@ -94,7 +96,8 @@ import org.openflow.vendor.nicira.OFRoleReplyVendorData;
  *
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
-public class ControllerTest extends FloodlightTestCase {
+public class ControllerTest extends FloodlightTestCase
+        implements IOFSwitchDriver {
    
     private Controller controller;
     private MockThreadPoolService tp;
@@ -763,42 +766,45 @@ public class ControllerTest extends FloodlightTestCase {
     public void testCheckSwitchReady() {
         OFChannelState state = new OFChannelState();
         Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
-        chdlr.sw = createMock(OFSwitchImpl.class);
+        Channel channel = createMock(Channel.class);
+        chdlr.channel = channel;
+        OFDescriptionStatistics desc = new OFDescriptionStatistics();
+        OFFeaturesReply featuresReply = new OFFeaturesReply();
+        featuresReply.setPorts(new ArrayList<OFPhysicalPort>());
         
         // Wrong current state 
         // Should not go to READY
         state.hsState = OFChannelState.HandshakeState.HELLO;
-        state.hasDescription = true;
-        state.hasGetConfigReply = true;
-        replay(chdlr.sw);  // nothing called on sw
+        state.hasDescription = false;
+        state.hasGetConfigReply = false;
+        state.switchBindingDone = false;
+        expect(channel.getRemoteAddress()).andReturn(null).anyTimes();
+        expect(channel.write(EasyMock.anyObject())).andReturn(null).anyTimes();
+        replay(channel);
         chdlr.checkSwitchReady();
-        verify(chdlr.sw);
         assertSame(OFChannelState.HandshakeState.HELLO, state.hsState);
-        reset(chdlr.sw);
         
         // Have only config reply
         state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
         state.hasDescription = false;
         state.hasGetConfigReply = true;
-        replay(chdlr.sw); 
+        state.featuresReply = featuresReply;
+        state.switchBindingDone = false;
         chdlr.checkSwitchReady();
-        verify(chdlr.sw);
         assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState);
         assertTrue(controller.connectedSwitches.isEmpty());
         assertTrue(controller.activeSwitches.isEmpty());
-        reset(chdlr.sw);
         
         // Have only desc reply
         state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
         state.hasDescription = true;
+        state.description = desc;
         state.hasGetConfigReply = false;
-        replay(chdlr.sw); 
+        state.switchBindingDone = false;
         chdlr.checkSwitchReady();
-        verify(chdlr.sw);
         assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState);
         assertTrue(controller.connectedSwitches.isEmpty());
         assertTrue(controller.activeSwitches.isEmpty());
-        reset(chdlr.sw);
         
         //////////////////////////////////////////
         // Finally, everything is right. Should advance to READY
@@ -806,19 +812,22 @@ public class ControllerTest extends FloodlightTestCase {
         controller.roleChanger = createMock(RoleChanger.class);
         state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
         state.hasDescription = true;
+        state.description = desc;
         state.hasGetConfigReply = true;
+        state.featuresReply = featuresReply;
+        state.switchBindingDone = false;
         // Role support disabled. Switch should be promoted to active switch
         // list. 
-        setupSwitchForAddSwitch(chdlr.sw, 0L);
-        chdlr.sw.clearAllFlowMods();
-        replay(controller.roleChanger, chdlr.sw);
+        // setupSwitchForAddSwitch(chdlr.sw, 0L);
+        // chdlr.sw.clearAllFlowMods();
+        desc.setManufacturerDescription("test vendor");
+        replay(controller.roleChanger);
         chdlr.checkSwitchReady();
-        verify(controller.roleChanger, chdlr.sw);
+        verify(controller.roleChanger);
         assertSame(OFChannelState.HandshakeState.READY, state.hsState);
         assertSame(chdlr.sw, controller.activeSwitches.get(0L));
         assertTrue(controller.connectedSwitches.contains(chdlr.sw));
         assertTrue(state.firstRoleReplyReceived);
-        reset(chdlr.sw);
         reset(controller.roleChanger);
         controller.connectedSwitches.clear();
         controller.activeSwitches.clear();
@@ -827,22 +836,77 @@ public class ControllerTest extends FloodlightTestCase {
         // Role support enabled. 
         state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
         controller.role = Role.MASTER;
-        Capture<Collection<OFSwitchImpl>> swListCapture = 
-                    new Capture<Collection<OFSwitchImpl>>();
+        Capture<Collection<IOFSwitch>> swListCapture = 
+                    new Capture<Collection<IOFSwitch>>();
         controller.roleChanger.submitRequest(capture(swListCapture), 
                     same(Role.MASTER));
-        replay(controller.roleChanger, chdlr.sw);
+        replay(controller.roleChanger);
         chdlr.checkSwitchReady();
-        verify(controller.roleChanger, chdlr.sw);
+        verify(controller.roleChanger);
         assertSame(OFChannelState.HandshakeState.READY, state.hsState);
         assertTrue(controller.activeSwitches.isEmpty());
-        assertTrue(controller.connectedSwitches.contains(chdlr.sw));
+        assertFalse(controller.connectedSwitches.isEmpty());
         assertTrue(state.firstRoleReplyReceived);
-        Collection<OFSwitchImpl> swList = swListCapture.getValue();
+        Collection<IOFSwitch> swList = swListCapture.getValue();
         assertEquals(1, swList.size());
-        assertTrue("swList must contain this switch", swList.contains(chdlr.sw));
+    }
+    
+    public class TestSwitchClass extends OFSwitchImpl {
     }
 
+    public class Test11SwitchClass extends OFSwitchImpl {
+    }
+
+    @Test
+    public void testBindSwitchToDriver() {
+        controller.addOFSwitchDriver("test", this);
+        
+        OFChannelState state = new OFChannelState();
+        Controller.OFChannelHandler chdlr =
+                controller.new OFChannelHandler(state);
+        OFSwitchImpl sw = new OFSwitchImpl();
+        sw.stringId = "1";
+        chdlr.sw = sw;
+        
+        // Swith should be bound of OFSwitchImpl (default)
+        state.hsState = OFChannelState.HandshakeState.HELLO;
+        state.hasDescription = true;
+        state.hasGetConfigReply = true;
+        state.switchBindingDone = false;
+        OFDescriptionStatistics desc = new OFDescriptionStatistics();
+        desc.setManufacturerDescription("test switch");
+        desc.setHardwareDescription("version 0.9");
+        state.description = desc;
+        OFFeaturesReply featuresReply = new OFFeaturesReply();
+        featuresReply.setPorts(new ArrayList<OFPhysicalPort>());
+        state.featuresReply = featuresReply;
+
+        chdlr.bindSwitchToDriver();
+        assertTrue(chdlr.sw instanceof OFSwitchImpl);
+        assertTrue(!(chdlr.sw instanceof TestSwitchClass));
+        
+        // Switch should be bound to TestSwitchImpl
+        chdlr.sw = sw;
+        state.switchBindingDone = false;
+        desc.setManufacturerDescription("test1 switch");
+        desc.setHardwareDescription("version 1.0");
+        state.description = desc;
+        state.featuresReply = featuresReply;
+
+        chdlr.bindSwitchToDriver();
+        assertTrue(chdlr.sw instanceof TestSwitchClass);
+
+        // Switch should be bound to Test11SwitchImpl
+        chdlr.sw = sw;
+        state.switchBindingDone = false;
+        desc.setManufacturerDescription("test11 switch");
+        desc.setHardwareDescription("version 1.1");
+        state.description = desc;
+        state.featuresReply = featuresReply;
+
+        chdlr.bindSwitchToDriver();
+        assertTrue(chdlr.sw instanceof Test11SwitchClass);
+    }
     
     @Test
     public void testChannelDisconnected() throws Exception {
@@ -935,6 +999,7 @@ public class ControllerTest extends FloodlightTestCase {
         expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
         chdlr.sw.deliverRoleRequestNotSupported(xid);
         expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes();
+        expect(chdlr.sw.getRole()).andReturn(null).anyTimes();
         expect(ch.close()).andReturn(null);
         
         replay(ch, chdlr.sw);
@@ -955,6 +1020,7 @@ public class ControllerTest extends FloodlightTestCase {
         expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
         chdlr.sw.deliverRoleRequestNotSupported(xid);
         expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes();
+        expect(chdlr.sw.getRole()).andReturn(null).anyTimes();
         expect(ch.close()).andReturn(null);
         replay(ch, chdlr.sw);
         
@@ -975,6 +1041,7 @@ public class ControllerTest extends FloodlightTestCase {
         chdlr.sw.deliverRoleRequestNotSupported(xid);
         setupSwitchForAddSwitch(chdlr.sw, 0L);
         chdlr.sw.clearAllFlowMods();
+        expect(chdlr.sw.getRole()).andReturn(null).anyTimes();
         replay(ch, chdlr.sw);
         
         chdlr.processOFMessage(msg);
@@ -1252,4 +1319,16 @@ public class ControllerTest extends FloodlightTestCase {
         verifyPortChangedUpdateInQueue(sw);
         reset(sw);
     }
+
+    @Override
+    public IOFSwitch getOFSwitchImpl(OFDescriptionStatistics description) {
+        String hw_desc = description.getHardwareDescription();
+        if (hw_desc.equals("version 1.1")) {
+            return new Test11SwitchClass();
+        }
+        if (hw_desc.equals("version 1.0")) {
+            return new TestSwitchClass();
+        }
+        return null;
+    }
 }
diff --git a/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java b/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java
index 991afffc282aef54b03076582dc9cafcef6b1dc6..d7d981449d95d4e934d7610232f8977c5afa025a 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java
@@ -32,7 +32,7 @@ public class RoleChangerTest {
      */
     @Test
     public void testSendRoleRequestSlaveNotSupported() {
-        LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>();
+        LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // a switch that doesn't support role requests
         OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
@@ -59,7 +59,7 @@ public class RoleChangerTest {
      */
     @Test
     public void testSendRoleRequestMasterNotSupported() {
-        LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>();
+        LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // a switch that doesn't support role requests
         OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
@@ -81,7 +81,7 @@ public class RoleChangerTest {
      */
     @Test
     public void testSendRoleRequestErrorHandling () throws Exception {
-        LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>();
+        LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // a switch that supports role requests
         OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
@@ -108,7 +108,7 @@ public class RoleChangerTest {
      */
     @Test
     public void testSendRoleRequestSupported() throws Exception {
-        LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>();
+        LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // a switch that supports role requests
         OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
@@ -136,7 +136,7 @@ public class RoleChangerTest {
     
     @Test
     public void testVerifyRoleReplyReceived() {
-        LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>();
+        Collection<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // Add a switch that has received a role reply
         OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
@@ -164,7 +164,7 @@ public class RoleChangerTest {
     @Test
     public void testRoleChangeTask() {
         @SuppressWarnings("unchecked")
-        Collection<OFSwitchImpl> switches = 
+        Collection<IOFSwitch> switches = 
                 EasyMock.createMock(Collection.class);
         long now = System.nanoTime();
         long dt1 = 10 * 1000*1000*1000L;
@@ -186,7 +186,7 @@ public class RoleChangerTest {
     
     @Test
     public void testSubmitRequest() throws Exception {
-        LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>();
+        LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         roleChanger.timeout = 500*1000*1000; // 500 ms
         
         // a switch that supports role requests
diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
index e83fc583d53deb296b61432a892163eb6202f99d..301832f6a9400f29f28a0d7c6fa9c871e2ffc449 100644
--- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
+++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
@@ -35,6 +35,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.IOFSwitchDriver;
 import net.floodlightcontroller.core.IOFSwitchFilter;
 import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.IListener.Command;
@@ -347,4 +348,11 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
         // TODO Auto-generated method stub
         
     }
+
+    @Override
+    public void addOFSwitchDriver(String desc, IOFSwitchDriver driver) {
+        // TODO Auto-generated method stub
+        
+    }
+
 }
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index e266d4a0a0d464493418de1d65b9244ce82bd381..430a1bdfafbbbe4bcac775af9fb0ed1a99b6cabe 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -738,7 +738,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 
         Device result = null;
         Iterator<? extends IDevice> dstiter =
-                deviceManager.queryClassDevices(device, null, null, ipaddr,
+                deviceManager.queryClassDevices(device.getEntityClass(),
+                                                null, null, ipaddr,
                                                 null, null);
         if (dstiter.hasNext()) {
             result = (Device)dstiter.next();
@@ -832,10 +833,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
                                              new SwitchPort(5L, 1)},
                                              d.getAttachmentPoints());
         Iterator<? extends IDevice> diter =
-                deviceManager.queryClassDevices(d, null, null, 1, null, null);
+                deviceManager.queryClassDevices(d.getEntityClass(),
+                                                null, null, 1, null, null);
         assertTrue(diter.hasNext());
         assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
-        diter = deviceManager.queryClassDevices(d, null, null, 2, null, null);
+        diter = deviceManager.queryClassDevices(d.getEntityClass(), 
+                                                null, null, 2, null, null);
         assertTrue(diter.hasNext());
         assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
 
@@ -851,10 +854,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1),
                                              new SwitchPort(5L, 1) },
                           d.getAttachmentPoints());
-        diter = deviceManager.queryClassDevices(d, null, null, 2, null, null);
+        diter = deviceManager.queryClassDevices(d.getEntityClass(),
+                                                null, null, 2, null, null);
         assertTrue(diter.hasNext());
         assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
-        diter = deviceManager.queryClassDevices(d, null, null, 1, null, null);
+        diter = deviceManager.queryClassDevices(d.getEntityClass(),
+                                                null, null, 1, null, null);
         assertFalse(diter.hasNext());
 
         d = deviceManager.findDevice(1L, null, null, null, null);
@@ -908,7 +913,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         IDevice r = deviceManager.getDevice(d.getDeviceKey());
         assertNull(r);
         Iterator<? extends IDevice> diter =
-                deviceManager.queryClassDevices(d, null, null, 1, null, null);
+                deviceManager.queryClassDevices(d.getEntityClass(),
+                                                null, null, 1, null, null);
         assertFalse(diter.hasNext());
 
         r = deviceManager.findDevice(1L, null, null, null, null);
@@ -1299,7 +1305,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         deviceManager.learnDeviceByEntity(entity4);
 
         Iterator<? extends IDevice> iter =
-                deviceManager.queryClassDevices(d, null,
+                deviceManager.queryClassDevices(d.getEntityClass(), null,
                                                 (short)1, 1, null, null);
         int count = 0;
         while (iter.hasNext()) {
@@ -1308,7 +1314,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         }
         assertEquals(1, count);
 
-        iter = deviceManager.queryClassDevices(d, null,
+        iter = deviceManager.queryClassDevices(d.getEntityClass(), null,
                                                (short)3, 3, null, null);
         count = 0;
         while (iter.hasNext()) {
@@ -1317,7 +1323,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         }
         assertEquals(1, count);
 
-        iter = deviceManager.queryClassDevices(d, null,
+        iter = deviceManager.queryClassDevices(d.getEntityClass(), null,
                                                (short)1, 3, null, null);
         count = 0;
         while (iter.hasNext()) {
@@ -1327,7 +1333,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         assertEquals(0, count);
 
         deviceManager.learnDeviceByEntity(entity5);
-        iter = deviceManager.queryClassDevices(d, null,
+        iter = deviceManager.queryClassDevices(d.getEntityClass(), null,
                                                (short)4, 3, null, null);
         count = 0;
         while (iter.hasNext()) {
@@ -1480,15 +1486,15 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         
         
         // Now look up destination devices
-        assertEquals(d1, deviceManager.findDestDevice(d2, 
+        assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), 
                                                   entity1.getMacAddress(), 
                                                   entity1.getVlan(),
                                                   entity1.getIpv4Address()));
-        assertEquals(d1, deviceManager.findDestDevice(d2, 
+        assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), 
                                                   entity1.getMacAddress(), 
                                                   entity1.getVlan(),
                                                   null));
-        assertEquals(null, deviceManager.findDestDevice(d2, 
+        assertEquals(null, deviceManager.findClassDevice(d2.getEntityClass(), 
                                                   entity1.getMacAddress(), 
                                                   (short) -1,
                                                   0));
diff --git a/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java b/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java
index 042782804e7772b6a805ca00bf6db4fc279820a5..0dcbb357e3c5fa81483f6663422d3654a224a0e5 100644
--- a/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java
+++ b/src/test/java/net/floodlightcontroller/flowcache/FlowReconcileMgrTest.java
@@ -36,7 +36,7 @@ public class FlowReconcileMgrTest extends FloodlightTestCase {
     OFStatisticsRequest ofStatsRequest;
 
     protected int NUM_FLOWS_PER_THREAD = 100;
-    protected int NUM_THREADS = 100;
+    protected int NUM_THREADS = 20;
     
     @Before
     public void setUp() throws Exception {
@@ -330,7 +330,7 @@ public class FlowReconcileMgrTest extends FloodlightTestCase {
             flowReconcileMgr.controllerPktInCounterName))
         .andReturn(newCnt)
         .times(1);
-        long initPktInCount = 10000;
+        long initPktInCount = 1000;
         newCnt.increment(currentTime, initPktInCount);
     
         replay(counterStore);
@@ -338,15 +338,15 @@ public class FlowReconcileMgrTest extends FloodlightTestCase {
         verify(counterStore);
     
         /** Now the lastPacketInCounter has been set.
-         *  lastCounter = 100,000 and newCounter = 300,000, t = 1 second
-         *  packetInRate = 200,000/sec.
-         *  capacity should be 500k - 200k = 300k
+         *  lastCounter = 1,000 and newCounter = 3,000, t = 1 second
+         *  packetInRate = 2,000/sec.
+         *  capacity should be 10k - 2k = 8k
          */
         reset(counterStore);
         newCnt = (SimpleCounter)SimpleCounter.createCounter(
                     currentTime, CounterType.LONG);
         currentTime = new Date(currentTime.getTime() + 200);
-        long nextPktInCount = 30000;
+        long nextPktInCount = 3000;
         newCnt.increment(currentTime, nextPktInCount);
     
         expect(counterStore.getCounter(
@@ -365,17 +365,6 @@ public class FlowReconcileMgrTest extends FloodlightTestCase {
         assertEquals(expectedCap, capacity);
     }
     
-    private class FlowReconcileWorker implements Runnable {
-    @Override
-        public void run() {
-            OFMatchReconcile ofmRc = new OFMatchReconcile();
-            // push large number of flows to be reconciled.
-            for (int i = 0; i < NUM_FLOWS_PER_THREAD; i++) {
-                flowReconcileMgr.reconcileFlow(ofmRc);
-            }
-        }
-    }
-    
     /** Verify the flows are sent to the reconcile pipeline in order.
      */
     @SuppressWarnings("unchecked")
@@ -491,10 +480,21 @@ public class FlowReconcileMgrTest extends FloodlightTestCase {
         }
         while (flowReconcileMgr.flowQueue.size() != totalFlows) {
             Date currTime = new Date();
-            assertTrue((currTime.getTime() - startTime.getTime()) < 2000);
+            assertTrue((currTime.getTime() - startTime.getTime()) < 1000);
         }
     
         // Make sure all flows are in the queue.
         assertEquals(totalFlows, flowReconcileMgr.flowQueue.size());
     }
+    
+    private class FlowReconcileWorker implements Runnable {
+    @Override
+        public void run() {
+            OFMatchReconcile ofmRc = new OFMatchReconcile();
+            // push large number of flows to be reconciled.
+            for (int i = 0; i < NUM_FLOWS_PER_THREAD; i++) {
+                flowReconcileMgr.reconcileFlow(ofmRc);
+            }
+        }
+    }
 }
diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
index 616d4377c6058d8a79008b2c4dabc3cd9236efe3..d1bcf2b16e89a55bff0469271a74e6c53894c0b2 100644
--- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
+++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
@@ -8,11 +8,14 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Future;
+import java.util.concurrent.locks.Lock;
 
 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.internal.Controller;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
 
 import org.jboss.netty.channel.Channel;
 import org.openflow.protocol.OFFeaturesReply;
@@ -346,4 +349,64 @@ public class OFMessageDamperMockSwitch implements IOFSwitch {
         return 0;
     }
 
+    @Override
+    public int sendNxRoleRequest(Role role, long cookie) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public boolean checkFirstPendingRoleRequestCookie(long cookie) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public void setChannel(Channel channel) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public void setFloodlightProvider(Controller controller) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public void setThreadPoolService(IThreadPoolService threadPool) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public void deliverRoleReply(int xid, Role role) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public void deliverRoleRequestNotSupported(int xid) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public Lock getListenerReadLock() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean checkFirstPendingRoleRequestXid(int xid) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public Lock getListenerWriteLock() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
 }
\ No newline at end of file