Giant patch of changes to support OpenFlow 1.3

The following people have contributed to this patch:
- Ali Al-Shabibi <alshabibi.ali@gmail.com>
- Ayaka Koshibe <ayaka@onlab.us>
- Brian O'Connor <bocon@onlab.us>
- Jonathan Hart <jono@onlab.us>
- Matteo Gerola <mgerola@create-net.org>
- Michele Santuari <michele.santuari@create-net.org>
- Pavlin Radoslavov <pavlin@onlab.us>
- Saurav Das <sauravdas@alumni.stanford.edu>
- Toshio Koide <t-koide@onlab.us>
- Yuta HIGUCHI <y-higuchi@onlab.us>

The patch includes the following changes:
- New Floodlight I/O loop / state machine
- New switch/port handling
- New role management (incl. Role.EQUAL)
- Added Floodlight debug framework
- Updates to Controller.java
- Move to Loxigen's OpenflowJ library
- Added OF1.3 support
- Added support for different switches (via DriverManager)
- Updated ONOS modules to use new APIs
- Added and updated unit tests

Change-Id: Ic70a8d50f7136946193d2ba2e4dc0b4bfac5f599
diff --git a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
index 4183877..0ee2904 100644
--- a/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
+++ b/src/main/java/net/floodlightcontroller/core/FloodlightProvider.java
@@ -1,3 +1,19 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
 package net.floodlightcontroller.core;
 
 import java.util.ArrayList;
@@ -10,6 +26,8 @@
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import net.floodlightcontroller.debugevent.IDebugEventService;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
@@ -28,13 +46,13 @@
 
     @Override
     public Map<Class<? extends IFloodlightService>,
-            IFloodlightService> getServiceImpls() {
+               IFloodlightService> getServiceImpls() {
         controller = new Controller();
 
         Map<Class<? extends IFloodlightService>,
-                IFloodlightService> m =
+            IFloodlightService> m =
                 new HashMap<Class<? extends IFloodlightService>,
-                        IFloodlightService>();
+                            IFloodlightService>();
         m.put(IFloodlightProviderService.class, controller);
         return m;
     }
@@ -42,33 +60,36 @@
     @Override
     public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
         Collection<Class<? extends IFloodlightService>> dependencies =
-                new ArrayList<Class<? extends IFloodlightService>>(4);
+            new ArrayList<Class<? extends IFloodlightService>>(4);
         dependencies.add(IRestApiService.class);
+        dependencies.add(IDebugCounterService.class);
+        dependencies.add(IDebugEventService.class);
         dependencies.add(IThreadPoolService.class);
-        // Following added by ONOS
-        // dependencies.add(IControllerRegistryService.class);
-        // dependencies.add(ILinkDiscoveryService.class);
-
         return dependencies;
     }
 
     @Override
     public void init(FloodlightModuleContext context) throws FloodlightModuleException {
-        controller.setRestApiService(
-                context.getServiceImpl(IRestApiService.class));
-        controller.setThreadPoolService(
-                context.getServiceImpl(IThreadPoolService.class));
-        // Following added by ONOS
-        controller.setMastershipService(
-                context.getServiceImpl(IControllerRegistryService.class));
-        controller.setLinkDiscoveryService(
-                context.getServiceImpl(ILinkDiscoveryService.class));
+       controller.setDebugCounter(
+           context.getServiceImpl(IDebugCounterService.class));
+       controller.setDebugEvent(
+           context.getServiceImpl(IDebugEventService.class));
+       controller.setRestApiService(
+           context.getServiceImpl(IRestApiService.class));
+       controller.setThreadPoolService(
+           context.getServiceImpl(IThreadPoolService.class));
+       // Following added by ONOS
+       controller.setMastershipService(
+               context.getServiceImpl(IControllerRegistryService.class));
+       controller.setLinkDiscoveryService(
+               context.getServiceImpl(ILinkDiscoveryService.class));
 
-        controller.init(context.getConfigParams(this));
+       controller.init(context.getConfigParams(this));
     }
 
     @Override
-    public void startUp(FloodlightModuleContext context) {
+    public void startUp(FloodlightModuleContext context)
+            throws FloodlightModuleException {
         controller.startupComponents();
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
index 1194e18..7f4f77d 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -1,5 +1,5 @@
 /**
- *    Copyright 2011, Big Switch Networks, Inc. 
+ *    Copyright 2011, Big Switch Networks, Inc.
  *    Originally created by David Erickson, Stanford University
  *
  *    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -19,15 +19,16 @@
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import net.floodlightcontroller.core.internal.Controller.Counters;
 import net.floodlightcontroller.core.module.IFloodlightService;
-import net.onrc.onos.api.registry.ILocalSwitchMastershipListener;
 import net.onrc.onos.core.packet.Ethernet;
 import net.onrc.onos.core.util.OnosInstanceId;
 
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.factory.BasicFactory;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFType;
 
 /**
  * The interface exposed by the core bundle that allows you to interact
@@ -43,13 +44,41 @@
      */
     public static final String CONTEXT_PI_PAYLOAD =
             "net.floodlightcontroller.core.IFloodlightProvider.piPayload";
-
+    public static final String CONTEXT_PI_INPORT =
+            "net.floodlightcontroller.core.IFloodlightProvider.piInPort";;
     /**
-     * The role of the controller as used by the OF 1.2 and OVS failover and
-     * load-balancing mechanism.
+     * The role of the controller as it pertains to a particular switch.
+     * Note that this definition of the role enum is different from the
+     * OF1.3 definition. It is maintained here to be backward compatible to
+     * earlier versions of the controller code. This enum is translated
+     * to the OF1.3 enum, before role messages are sent to the switch.
+     * See sendRoleRequestMessage method in OFSwitchImpl
      */
     public static enum Role {
-        EQUAL, MASTER, SLAVE
+        EQUAL(OFControllerRole.ROLE_EQUAL),
+        MASTER(OFControllerRole.ROLE_MASTER),
+        SLAVE(OFControllerRole.ROLE_SLAVE);
+
+        private final int nxRole;
+
+        private Role(OFControllerRole nxRole) {
+            this.nxRole = nxRole.ordinal();
+        }
+        /*
+        private static Map<Integer,Role> nxRoleToEnum
+                = new HashMap<Integer,Role>();
+        static {
+            for(Role r: Role.values())
+                nxRoleToEnum.put(r.toNxRole(), r);
+        }
+        public int toNxRole() {
+            return nxRole;
+        }
+        // Return the enum representing the given nxRole or null if no
+        // such role exists
+        public static Role fromNxRole(int nxRole) {
+            return nxRoleToEnum.get(nxRole);
+        }*/
     }
 
     /**
@@ -59,6 +88,40 @@
     public static final FloodlightContextStore<Ethernet> bcStore =
             new FloodlightContextStore<Ethernet>();
 
+
+    //************************
+    //  Controller related
+    //************************
+
+    /**
+     * Get the current mapping of controller IDs to their IP addresses
+     * Returns a copy of the current mapping.
+     *
+     * @see IHAListener
+     */
+    public Map<String, String> getControllerNodeIPs();
+
+    /**
+     * Return the controller start time in  milliseconds
+     *
+     * @return
+     */
+    public long getSystemStartTime();
+
+    /**
+     * Run the main I/O loop of the Controller.
+     */
+    public void run();
+
+//    /**
+//     * Terminate the process
+//     */
+//    public void terminate();
+
+    //************************
+    //  OF Message Listener related
+    //************************
+
     /**
      * Adds an OpenFlow message listener
      *
@@ -82,23 +145,9 @@
      */
     public Map<OFType, List<IOFMessageListener>> getListeners();
 
-    /**
-     * Adds a switch mastership listener for controller role changes for
-     * local switches.
-     *
-     * @param listener the listener to add.
-     */
-    public void addLocalSwitchMastershipListener(
-                ILocalSwitchMastershipListener listener);
-
-    /**
-     * Removes a switch mastership listener for controller role changes for
-     * local switches.
-     *
-     * @param listener the listener to remove.
-     */
-    public void removeLocalSwitchMastershipListener(
-                ILocalSwitchMastershipListener listener);
+    //************************
+    //  Switch & SwitchListener related
+    //************************
 
     /**
      * Returns an unmodifiable map of all actively connected OpenFlow switches. This doesn't
@@ -109,12 +158,12 @@
     public Map<Long, IOFSwitch> getSwitches();
 
     /**
-     * Get the current mapping of controller IDs to their IP addresses
-     * Returns a copy of the current mapping.
-     *
-     * @see IHAListener
+     * Configure controller to always clear the flow table on the switch,
+     * when it connects to controller. This will be true for first time switch
+     * reconnect, as well as a switch re-attaching to Controller after HA
+     * switch over to ACTIVE role
      */
-    public Map<String, String> getControllerNodeIPs();
+    public void setAlwaysClearFlowsOnSwAdd(boolean value);
 
     /**
      * Gets the unique ID used to identify this ONOS instance in the cluster.
@@ -137,67 +186,19 @@
      */
     public void removeOFSwitchListener(IOFSwitchListener listener);
 
-    /**
-     * Terminate the process
-     */
-    public void terminate();
+
+
+    //************************
+    //  Utility methods
+    //************************
 
     /**
-     * Re-injects an OFMessage back into the packet processing chain
-     *
-     * @param sw  The switch to use for the message
-     * @param msg the message to inject
-     * @return True if successfully re-injected, false otherwise
-     */
-    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg);
-
-    /**
-     * Re-injects an OFMessage back into the packet processing chain
-     *
-     * @param sw       The switch to use for the message
-     * @param msg      the message to inject
-     * @param bContext a floodlight context to use if required
-     * @return True if successfully re-injected, false otherwise
-     */
-    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
-                                   FloodlightContext bContext);
-
-    /**
-     * Process written messages through the message listeners for the controller
-     *
-     * @param sw The switch being written to
-     * @param m  the message
-     * @param bc any accompanying context object
-     */
-    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
-                                      FloodlightContext bc);
-
-    /**
-     * Gets the BasicFactory
+     * Gets the Factory
      *
      * @return an OpenFlow message factory
      */
-    public BasicFactory getOFMessageFactory();
-
-    /**
-     * Run the main I/O loop of the Controller.
-     */
-    public void run();
-
-    /**
-     * Return the controller start time in  milliseconds
-     *
-     * @return
-     */
-    public long getSystemStartTime();
-
-    /**
-     * Configure controller to always clear the flow table on the switch,
-     * when it connects to controller. This will be true for first time switch
-     * reconnect, as well as a switch re-attaching to Controller after HA
-     * switch over to ACTIVE role
-     */
-    public void setAlwaysClearFlowsOnSwAdd(boolean value);
+    public OFFactory getOFMessageFactory_13();
+    public OFFactory getOFMessageFactory_10();
 
     /**
      * Publish updates to Controller updates queue
@@ -206,4 +207,66 @@
      */
     public void publishUpdate(IUpdate update);
 
+//    /**
+//     * Re-injects an OFMessage back into the packet processing chain
+//     *
+//     * @param sw  The switch to use for the message
+//     * @param msg the message to inject
+//     * @return True if successfully re-injected, false otherwise
+//     */
+//    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg);
+//
+//    /**
+//     * Re-injects an OFMessage back into the packet processing chain
+//     *
+//     * @param sw       The switch to use for the message
+//     * @param msg      the message to inject
+//     * @param bContext a floodlight context to use if required
+//     * @return True if successfully re-injected, false otherwise
+//     */
+//    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
+//                                   FloodlightContext bContext);
+//
+//    /**
+//     * Process written messages through the message listeners for the controller
+//     *
+//     * @param sw The switch being written to
+//     * @param m  the message
+//     * @param bc any accompanying context object
+//     */
+//    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
+//                                      FloodlightContext bc);
+
+
+    /**
+     * Return the default set of counters
+     * @return
+     */
+    public Counters getCounters();
+
+    void setAlwaysClearFlowsOnSwActivate(boolean value);
+
+    Map<String, Long> getMemory();
+
+    Long getUptime();
+
+    Set<Long> getAllSwitchDpids();
+
+    IOFSwitch getSwitch(long dpid);
+
+    /**
+     * Record a switch event in in-memory debug-event
+     * @param switchDPID
+     * @param reason Reason for this event
+     * @param flushNow see debug-event flushing in IDebugEventService
+     */
+    public void addSwitchEvent(long switchDPID, String reason, boolean flushNow);
+
+    Set<Long> getAllMasterSwitchDpids();
+
+    Set<Long> getAllEqualSwitchDpids();
+
+    IOFSwitch getMasterSwitch(long dpid);
+
+    IOFSwitch getEqualSwitch(long dpid);
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOFMessageListener.java b/src/main/java/net/floodlightcontroller/core/IOFMessageListener.java
index b14af57..3bf7988 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFMessageListener.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFMessageListener.java
@@ -17,8 +17,8 @@
 
 package net.floodlightcontroller.core;
 
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
 
 /**
  * @author David Erickson (daviderickson@cs.stanford.edu)
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
index e28d7be..54e4408 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -22,32 +22,52 @@
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Future;
 
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.util.OrderedCollection;
 
 import org.jboss.netty.channel.Channel;
-import org.openflow.protocol.OFFeaturesReply;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.protocol.OFStatisticsRequest;
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
-import org.openflow.protocol.statistics.OFStatistics;
+import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.projectfloodlight.openflow.protocol.OFCapabilities;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.U64;
 
-/**
- * @author David Erickson (daviderickson@cs.stanford.edu)
- */
+
 public interface IOFSwitch {
-    // Attribute keys
-    public static final String SWITCH_DESCRIPTION_FUTURE = "DescriptionFuture";
-    public static final String SWITCH_DESCRIPTION_DATA = "DescriptionData";
+
+	/**
+	 * OF1.3 switches should support role-request messages as in the 1.3 spec.
+     * OF1.0 switches may or may not support the Nicira role request extensions.
+     * To indicate the support, this property should be set by the associated
+	 * OF1.0 switch driver in the net.onrc.onos.core.drivermanager package.
+	 * The property will be ignored for OF1.3 switches.
+	 */
     public static final String SWITCH_SUPPORTS_NX_ROLE = "supportsNxRole";
-    public static final String SWITCH_IS_CORE_SWITCH = "isCoreSwitch";
-    public static final String PROP_FASTWILDCARDS = "FastWildcards";
-    public static final String PROP_REQUIRES_L3_MATCH = "requiresL3Match";
-    public static final String PROP_SUPPORTS_OFPP_TABLE = "supportsOfppTable";
-    public static final String PROP_SUPPORTS_OFPP_FLOOD = "supportsOfppFlood";
-    public static final String PROP_SUPPORTS_NETMASK_TBL = "supportsNetmaskTbl";
+
+
+    //************************
+    // Channel related
+    //************************
+
+    /**
+     * Disconnects the switch by closing the TCP connection. Results in a call
+     * to the channel handler's channelDisconnected method for cleanup
+     * @throws IOException
+     */
+    public void disconnectSwitch();
 
     /**
      * Writes to the OFMessage to the output stream.
@@ -61,7 +81,7 @@
     public void write(OFMessage m, FloodlightContext bc) throws IOException;
 
     /**
-     * Writes the list of messages to the output stream
+     * Writes the list of messages to the output stream.
      * The message will be handed to the floodlightProvider for possible filtering
      * and processing by message listeners.
      *
@@ -72,45 +92,210 @@
     public void write(List<OFMessage> msglist, FloodlightContext bc) throws IOException;
 
     /**
-     * @throws IOException
-     */
-    public void disconnectOutputStream();
-
-    /**
-     * FIXME: remove getChannel(). All access to the channel should be through
-     * wrapper functions in IOFSwitch
+     * Gets the date the switch connected to this controller.
      *
-     * @return the channel to the switch
+     * @return the date
      */
-    public Channel getChannel();
+    public Date getConnectedSince();
 
     /**
-     * Returns switch features from features Reply
+     * Gets the next available transaction id.
+     *
+     * @return the next transaction ID
+     */
+    public int getNextTransactionId();
+
+    /**
+     * Checks if the switch is still connected.
+     * Only call while holding processMessageLock
+     *
+     * @return whether the switch is still disconnected
+     */
+    public boolean isConnected();
+
+    /**
+     * Sets whether the switch is connected.
+     * Only call while holding modifySwitchLock
+     *
+     * @param connected whether the switch is connected
+     */
+    public void setConnected(boolean connected);
+
+    /**
+     * Flushes all flows queued for this switch in the current thread.
+     * NOTE: The contract is limited to the current thread
+     */
+    public void flush();
+
+    /**
+     * Sets the Netty Channel this switch instance is associated with.
+     * <p>
+     * Called immediately after instantiation
+     *
+     * @param channel
+     */
+    public void setChannel(Channel channel);
+
+    //************************
+    // Switch features related
+    //************************
+
+    /**
+     * Gets the datapathId of the switch.
      *
      * @return the switch buffers
      */
-    public int getBuffers();
-
-    public int getActions();
-
-    public int getCapabilities();
-
-    public byte getTables();
+    public long getId();
 
     /**
-     * Set the OFFeaturesReply message returned by the switch during initial
-     * handshake.
+     * Gets a string version of the ID for this switch.
      *
-     * @param featuresReply
+     * @return string version of the ID
      */
-    public void setFeaturesReply(OFFeaturesReply featuresReply);
+    public String getStringId();
 
     /**
-     * Set the SwitchProperties based on it's description
+     * Gets the number of buffers.
      *
-     * @param description
+     * @return the number of buffers
      */
-    public void setSwitchProperties(OFDescriptionStatistics description);
+    public int getNumBuffers();
+
+    public Set<OFCapabilities> getCapabilities();
+
+    public byte getNumTables();
+
+    /**
+     * Returns an OFDescStatsReply message object. Use the methods contained
+     * to retrieve switch descriptions for Manufacturer, Hw/Sw version etc.
+     */
+    public OFDescStatsReply getSwitchDescription();
+
+//    /**
+//     * Returns a Future object that can be used to retrieve the asynchronous
+//     * OFStatisticsReply when it is available.
+//     *
+//     * @param request statistics request
+//     * @return Future object wrapping OFStatisticsReply
+//     * @throws IOException
+//     */
+//    public Future<OFFeaturesReply> getFeaturesReplyFromSwitch()
+//            throws IOException;
+//
+//    /**
+//     * Deliver the featuresReply future reply
+//     *
+//     * @param reply the reply to deliver
+//     */
+//    void deliverOFFeaturesReply(OFMessage reply);
+
+    /**
+     * Cancel features reply with a specific transaction ID
+     * @param transactionId the transaction ID
+     */
+    public void cancelFeaturesReply(int transactionId);
+
+    /**
+     * Gets the OFActionType set.
+     * <p>
+     * getActions has relevance only for an OpenFlow 1.0 switch.
+     * For OF1.3, each table can support different actions
+     *
+     * @return the action set
+     */
+    public Set<OFActionType> getActions();
+
+    public void setOFVersion(OFVersion ofv);
+
+    public OFVersion getOFVersion();
+
+
+    //************************
+    //  Switch port related
+    //************************
+
+    /**
+     * the type of change that happened to an open flow port
+     */
+    public enum PortChangeType {
+        /** Either a new port has been added by the switch, or we are
+         * adding a port we just deleted (via a prior notification) due to
+         * a change in the portNumber-portName mapping.
+         */
+        ADD,
+	    /** some other feature of the port has changed (eg. speed)*/
+        OTHER_UPDATE,
+        /** Either a port has been deleted by the switch, or we are deleting
+         * a port whose portNumber-portName mapping has changed. Note that in
+         * the latter case, a subsequent notification will be sent out to add a
+         * port with the new portNumber-portName mapping.
+         */
+        DELETE,
+        /** Port is up (i.e. enabled). Presumably an earlier notification had
+         * indicated that it was down. To be UP implies that the port is
+         * administratively considered UP (see ofp_port_config) AND the port
+         * link is up AND the port is no longer blocked (see ofp_port_state).
+         */
+        UP,
+        /** Port is down (i.e. disabled). Presumably an earlier notification had
+         * indicated that it was up, or the port was always up.
+         * To be DOWN implies that the port has been either
+         * administratively brought down (see ofp_port_config) OR the port
+         * link is down OR the port is blocked (see ofp_port_state).
+         */
+        DOWN,
+    }
+
+    /**
+     * Describes a change of an open flow port.
+     */
+    public static class PortChangeEvent {
+        public final OFPortDesc port;
+        public final PortChangeType type;
+        /**
+         * @param port
+         * @param type
+         */
+        public PortChangeEvent(OFPortDesc port,
+                               PortChangeType type) {
+            this.port = port;
+            this.type = type;
+        }
+        /* (non-Javadoc)
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((port == null) ? 0 : port.hashCode());
+            result = prime * result + ((type == null) ? 0 : type.hashCode());
+            return result;
+        }
+        /* (non-Javadoc)
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (obj == null) return false;
+            if (getClass() != obj.getClass()) return false;
+            PortChangeEvent other = (PortChangeEvent) obj;
+            if (port == null) {
+                if (other.port != null) return false;
+            } else if (!port.equals(other.port)) return false;
+            if (type != other.type) return false;
+            return true;
+        }
+        /* (non-Javadoc)
+         * @see java.lang.Object#toString()
+         */
+        @Override
+        public String toString() {
+            return "[" + type + " " + port.toString() + "]";
+        }
+    }
+
 
     /**
      * Get list of all enabled ports. This will typically be different from
@@ -121,7 +306,7 @@
      *
      * @return Unmodifiable list of ports not backed by the underlying collection
      */
-    public Collection<OFPhysicalPort> getEnabledPorts();
+    public Collection<OFPortDesc> getEnabledPorts();
 
     /**
      * Get list of the port numbers of all enabled ports. This will typically
@@ -132,7 +317,7 @@
      *
      * @return Unmodifiable list of ports not backed by the underlying collection
      */
-    public Collection<Short> getEnabledPortNumbers();
+    public Collection<Integer> getEnabledPortNumbers();
 
     /**
      * Retrieve the port object by the port number. The port object
@@ -142,7 +327,7 @@
      * @param portNumber
      * @return port object
      */
-    public OFPhysicalPort getPort(short portNumber);
+    public OFPortDesc getPort(int portNumber);
 
     /**
      * Retrieve the port object by the port name. The port object
@@ -152,34 +337,28 @@
      * @param portName
      * @return port object
      */
-    public OFPhysicalPort getPort(String portName);
+    public OFPortDesc getPort(String portName);
 
     /**
      * Add or modify a switch port. This is called by the core controller
      * code in response to a OFPortStatus message. It should not typically be
      * called by other floodlight applications.
      *
-     * @param port
-     */
-    public void setPort(OFPhysicalPort port);
-
-    /**
-     * Delete a port for the switch. This is called by the core controller
-     * code in response to a OFPortStatus message. It should not typically be
-     * called by other floodlight applications.
+     * OFPPR_MODIFY and OFPPR_ADD will be treated as equivalent. The OpenFlow
+     * spec is not clear on whether portNames are portNumbers are considered
+     * authoritative identifiers. We treat portNames <-> portNumber mappings
+     * as fixed. If they change, we delete all previous conflicting ports and
+     * add all new ports.
      *
-     * @param portNumber
+     * @param ps the port status message
+     * @return the ordered Collection of changes "applied" to the old ports
+     * of the switch according to the PortStatus message. A single PortStatus
+     * message can result in multiple changes.
+     * If portName <-> portNumber mappings have
+     * changed, the iteration order ensures that delete events for old
+     * conflicting appear before before events adding new ports
      */
-    public void deletePort(short portNumber);
-
-    /**
-     * Delete a port for the switch. This is called by the core controller
-     * code in response to a OFPortStatus message. It should not typically be
-     * called by other floodlight applications.
-     *
-     * @param portName
-     */
-    public void deletePort(String portName);
+    public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps);
 
     /**
      * Get list of all ports. This will typically be different from
@@ -190,14 +369,14 @@
      *
      * @return Unmodifiable list of ports
      */
-    public Collection<OFPhysicalPort> getPorts();
+    public Collection<OFPortDesc> getPorts();
 
     /**
      * @param portName
      * @return Whether a port is enabled per latest port status message
      * (not configured down nor link down nor in spanning tree blocking state)
      */
-    public boolean portEnabled(short portName);
+    public boolean portEnabled(int portName);
 
     /**
      * @param portNumber
@@ -207,150 +386,82 @@
     public boolean portEnabled(String portName);
 
     /**
-     * @param port
-     * @return Whether a port is enabled per latest port status message
-     * (not configured down nor link down nor in spanning tree blocking state)
+     * Compute the changes that would be required to replace the old ports
+     * of this switch with the new ports
+     * @param ports new ports to set
+     * @return the ordered collection of changes "applied" to the old ports
+     * of the switch in order to set them to the new set.
+     * If portName <-> portNumber mappings have
+     * changed, the iteration order ensures that delete events for old
+     * conflicting appear before before events adding new ports
      */
-    public boolean portEnabled(OFPhysicalPort port);
+    public OrderedCollection<PortChangeEvent>
+            comparePorts(Collection<OFPortDesc> ports);
 
     /**
-     * Get the datapathId of the switch
-     *
-     * @return switch dpid as a long
+     * Replace the ports of this switch with the given ports.
+     * @param ports new ports to set
+     * @return the ordered collection of changes "applied" to the old ports
+     * of the switch in order to set them to the new set.
+     * If portName <-> portNumber mappings have
+     * changed, the iteration order ensures that delete events for old
+     * conflicting appear before before events adding new ports
      */
-    public long getId();
+    public OrderedCollection<PortChangeEvent>
+            setPorts(Collection<OFPortDesc> ports);
+
+//  XXX S The odd use of providing an API call to 'set ports' (above) would
+//  logically suggest that there should be a way to delete or unset the ports.
+//  Right now we forbid this. We should probably not use setPorts too.
+//
+//  /**
+//   * Delete a port for the switch. This is called by the core controller
+//   * code in response to a OFPortStatus message. It should not typically be
+//   * called by other floodlight applications.
+//   *
+//   * @param portNumber
+//   */
+//  public void deletePort(short portNumber);
+//
+//  /**
+//   * Delete a port for the switch. This is called by the core controller
+//   * code in response to a OFPortStatus message. It should not typically be
+//   * called by other floodlight applications.
+//   *
+//   * @param portName
+//   */
+//  public void deletePort(String portName);
+
+
+    //*******************************************
+    //  IOFSwitch object attributes
+    //************************
 
     /**
-     * Get a string version of the ID for this switch
-     *
-     * @return switch dpid as a String
-     */
-    public String getStringId();
-
-    /**
-     * Retrieves attributes of this switch
+     * Gets attributes of this switch.
      *
      * @return attributes of the switch
      */
     public Map<Object, Object> getAttributes();
 
-    /**
-     * Retrieves the date the switch connected to this controller
-     *
-     * @return the date
-     */
-    public Date getConnectedSince();
-
-    /**
-     * Returns the next available transaction id
-     *
-     * @return next available transaction id
-     */
-    public int getNextTransactionId();
-
-    /**
-     * Returns a Future object that can be used to retrieve the asynchronous
-     * OFStatisticsReply when it is available.
-     *
-     * @param request statistics request
-     * @return Future object wrapping OFStatisticsReply
-     * @throws IOException
-     */
-    public Future<List<OFStatistics>> getStatistics(OFStatisticsRequest request)
-            throws IOException;
-
-    /**
-     * Returns a Future object that can be used to retrieve the asynchronous
-     * OFStatisticsReply when it is available.
-     *
-     * @param request statistics request
-     * @return Future object wrapping OFStatisticsReply
-     * @throws IOException
-     */
-    public Future<OFFeaturesReply> getFeaturesReplyFromSwitch()
-            throws IOException;
-
-    /**
-     * Deliver the featuresReply future reply
-     *
-     * @param reply the reply to deliver
-     */
-    void deliverOFFeaturesReply(OFMessage reply);
-
-    /*
-     * Cancel features reply with a specific transction ID
-     * @param transactionId the transaction ID
-     */
-    public void cancelFeaturesReply(int transactionId);
-
-    /**
-     * Check if the switch is still connected;
-     * Only call while holding processMessageLock
-     *
-     * @return whether the switch is still disconnected
-     */
-    public boolean isConnected();
-
-    /**
-     * Set whether the switch is connected
-     * Only call while holding modifySwitchLock
-     *
-     * @param connected whether the switch is connected
-     */
-    public void setConnected(boolean connected);
-
-    /**
-     * Get the current role of the controller for the switch
-     *
-     * @return the role of the controller
-     */
-    public Role getRole();
-
-    /**
-     * Check if the controller is an active controller for the switch.
-     * The controller is active if its role is MASTER or EQUAL.
-     *
-     * @return whether the controller is active
-     */
-    public boolean isActive();
-
-    /**
-     * Deliver the statistics future reply
-     *
-     * @param reply the reply to deliver
-     */
-    public void deliverStatisticsReply(OFMessage reply);
-
-    /**
-     * Cancel the statistics reply with the given transaction ID
-     *
-     * @param transactionId the transaction ID
-     */
-    public void cancelStatisticsReply(int transactionId);
-
-    /**
-     * Cancel all statistics replies
-     */
-    public void cancelAllStatisticsReplies();
-
-    /**
-     * Checks if a specific switch property exists for this switch
-     *
+	/**
+	 * Checks if a specific switch property exists for this switch
+	 *
      * @param name name of property
      * @return value for name
      */
     boolean hasAttribute(String name);
 
     /**
-     * Set properties for switch specific behavior
+     * Gets properties for switch specific behavior.
      *
      * @param name name of property
-     * @return value for name
+     * @return 'value' for 'name', or null if no entry for 'name' exists
      */
     Object getAttribute(String name);
 
     /**
-     * Set properties for switch specific behavior
+     * Sets properties for switch specific behavior.
      *
      * @param name  name of property
      * @param value value for name
@@ -358,53 +469,142 @@
     void setAttribute(String name, Object value);
 
     /**
-     * Set properties for switch specific behavior
+     * Removes properties for switch specific behavior.
      *
      * @param name name of property
      * @return current value for name or null (if not present)
      */
     Object removeAttribute(String name);
 
+    //************************
+    //  Switch statistics
+    //************************
+
     /**
-     * Clear all flowmods on this switch
+     * Delivers the statistics future reply.
+     *
+     * @param reply the reply to deliver
+     */
+    public void deliverStatisticsReply(OFMessage reply);
+
+    /**
+     * Cancels the statistics reply with the given transaction ID.
+     *
+     * @param transactionId the transaction ID
+     */
+    public void cancelStatisticsReply(int transactionId);
+
+    /**
+     * Cancels all statistics replies.
+     */
+    public void cancelAllStatisticsReplies();
+
+    /**
+     * Gets a Future object that can be used to retrieve the asynchronous.
+     * OFStatisticsReply when it is available.
+     *
+     * @param request statistics request
+     * @return Future object wrapping OFStatisticsReply
+     * @throws IOException
+     */
+    public Future<List<OFStatsReply>> getStatistics(OFStatsRequest<?> request)
+            throws IOException;
+
+    //************************
+    //  Switch other utilities
+    //************************
+
+    /**
+     * Clears all flowmods on this switch.
      */
     public void clearAllFlowMods();
 
     /**
-     * Update broadcast cache
-     *
-     * @param data
-     * @return true if there is a cache hit
-     * false if there is no cache hit.
+     * Gets the current role of this controller for this IOFSwitch.
      */
-    public boolean updateBroadcastCache(Long entry, Short port);
+    public Role getRole();
 
     /**
-     * Get the portBroadcastCacheHits
+     * Sets this controller's Role for this IOFSwitch to role.
      *
-     * @return port broadcast cache hits
+     * @param role
      */
-    public Map<Short, Long> getPortBroadcastHits();
+    public void setRole(Role role);
 
     /**
-     * Send a flow statistics request to the switch. This call returns after
-     * sending the stats. request to the switch.
+     * Gets the next generation ID.
+     * <p>
+     * Note: relevant for role request messages in OF1.3
      *
-     * @param request flow statistics request message
-     * @param xid     transaction id, must be obtained by using the getXid() API.
-     * @param caller  the caller of the API. receive() callback of this
-     *                caller would be called when the reply from the switch is received.
-     * @return the transaction id for the message sent to the switch. The
-     * transaction id can be used to match the response with the request. Note
-     * that the transaction id is unique only within the scope of this switch.
-     * @throws IOException
+     * @return next generation ID
      */
-    public void sendStatsQuery(OFStatisticsRequest request, int xid,
-                               IOFMessageListener caller) throws IOException;
+    public U64 getNextGenerationId();
 
     /**
-     * Flush all flows queued for this switch in the current thread.
-     * NOTE: The contract is limited to the current thread
+     * Sets IFloodlightProviderService for this switch instance.
+     * <p>
+     * Called immediately after instantiation
+     *
+     * @param controller
      */
-    public void flush();
+    public void setFloodlightProvider(IFloodlightProviderService controller);
+
+    /**
+     * Sets IThreadPoolService for this switch instance.
+     * <p>
+     * Called immediately after instantiation
+     *
+     * @param threadPool
+     */
+    public void setThreadPoolService(IThreadPoolService threadPool);
+
+    /**
+     * Set debug counter service for per-switch counters
+     * Called immediately after instantiation
+     * @param debugCounters
+     * @throws CounterException
+     */
+	public void setDebugCounterService(IDebugCounterService debugCounter)
+			throws CounterException;
+
+	/**
+     * Start this switch driver's sub handshake. This might be a no-op but
+     * this method must be called at least once for the switch to be become
+     * ready.
+     * This method must only be called from the I/O thread
+	 * @throws IOException
+     * @throws SwitchDriverSubHandshakeAlreadyStarted if the sub-handshake has
+     * already been started
+     */
+    public void startDriverHandshake() throws IOException;
+
+    /**
+     * Check if the sub-handshake for this switch driver has been completed.
+     * This method can only be called after startDriverHandshake()
+     *
+     * This methods must only be called from the I/O thread
+     * @return true if the sub-handshake has been completed. False otherwise
+     * @throws SwitchDriverSubHandshakeNotStarted if startDriverHandshake() has
+     * not been called yet.
+     */
+    public boolean isDriverHandshakeComplete();
+
+    /**
+     * Pass the given OFMessage to the driver as part of this driver's
+     * sub-handshake. Must not be called after the handshake has been completed
+     * This methods must only be called from the I/O thread
+     * @param m The message that the driver should process
+     * @throws SwitchDriverSubHandshakeCompleted if isDriverHandshake() returns
+     * false before this method call
+     * @throws SwitchDriverSubHandshakeNotStarted if startDriverHandshake() has
+     * not been called yet.
+     */
+    public void processDriverHandshakeMessage(OFMessage m);
+
+    /**
+     * Set the flow table full flag in the switch
+     * XXX S Rethink this for multiple tables
+     */
+    public void setTableFull(boolean isFull);
+
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
index d874d75..caeb95f 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
@@ -17,36 +17,98 @@
 
 package net.floodlightcontroller.core;
 
+import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
+
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+
 /**
- * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ * Switch lifecycle notifications.
+ *
+ * These updates /happen-after/ the corresponding changes have been
+ * committed. I.e., the changes are visible when
+ * {@link IFloodlightProviderService#getSwitch(long)}
+ * {@link IFloodlightProviderService#getAllSwitchDpids()}
+ * {@link IFloodlightProviderService#getAllSwitchMap()}
+ * or any method on the IOFSwitch returned by these methods are
+ * called from the notification method or after it.
+ *
+ * Note however, that additional changes could have been committed before
+ * the notification for which the notification is still pending. E.g.,
+ * {@link IFloodlightProviderService#getSwitch(long)} might return null after
+ * a switchAdded() (which happens if the switch has been added and then
+ * removed and the remove hasn't been dispatched yet).
+ *
+ * These lifecycle notification methods are called by a single thread and they
+ * will always be called by the same thread.
+ * The calls are always in order.
+ *
  */
 public interface IOFSwitchListener {
 
     /**
-     * Fired when a switch is connected to the controller, and has sent
-     * a features reply.
-     *
-     * @param sw
-     */
-    public void addedSwitch(IOFSwitch sw);
-
-    /**
-     * Fired when a switch is disconnected from the controller.
-     *
-     * @param sw
-     */
-    public void removedSwitch(IOFSwitch sw);
-
-    /**
-     * Fired when ports on a switch change (any change to the collection
-     * of OFPhysicalPorts and/or to a particular port)
-     */
-    public void switchPortChanged(Long switchId);
-
-    /**
      * The name assigned to this listener
-     *
-     * @return the name of the listener
      */
     public String getName();
+
+	/**
+     * Fired when switch becomes active on the controller cluster and this
+     * controller instance has acquired MASTER role for this switch
+     * @param switchId the datapath Id of the new switch
+     */
+	public void switchActivatedMaster(long swId);
+
+	/**
+     * Fired when switch becomes active on the controller cluster and this
+     * controller instance has acquired EQUAL role for this switch
+     * @param switchId the datapath Id of the new switch
+     */
+	public void switchActivatedEqual(long swId);
+
+	/**
+     * Fired when the role of this controller for this switch, transitions
+     * from MASTER role to EQUAL role
+     * @param switchId the datapath Id of the new switch
+     */
+	public void switchMasterToEqual(long swId);
+
+	/**
+     * Fired when the role of this controller for this switch, transitions
+     * from EQUAL role to MASTER role
+     * @param switchId the datapath Id of the new switch
+     */
+	public void switchEqualToMaster(long swId);
+
+	/**
+	 * Fired when this switch has disconnected at this controller. It does NOT
+	 * imply that the switch has died, or it has disconnected from any or every
+	 * other controller it was connected to.
+	 * @param swId
+	 */
+	public void switchDisconnected(long swId);
+
+	/**
+     * Fired when a port on a known switch changes.
+     *
+     * A user of this notification needs to take care if the port and type
+     * information is used directly and if the collection of ports has been
+     * queried as well. This notification will only be dispatched after the
+     * the port changes have been committed to the IOFSwitch instance. However,
+     * if a user has previously called {@link IOFSwitch#getPorts()} or related
+     * method a subsequent update might already be present in the information
+     * returned by getPorts.
+     * @param switchId
+     * @param port
+     * @param type
+     */
+	public void switchPortChanged(long swId, OFPortDesc port,
+			PortChangeType changeType);
+
+	/**
+     * Fired when any non-port related information (e.g., attributes,
+     * features) change after a switchAdded XXX S needs more specific methods
+     * TODO: currently unused
+     * @param switchId
+     */
+	//public void switchChanged(long swId);
 }
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeAlreadyStarted.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeAlreadyStarted.java
new file mode 100644
index 0000000..eb5541b
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeAlreadyStarted.java
@@ -0,0 +1,15 @@
+package net.floodlightcontroller.core;
+
+/**
+ * Thrown when IOFSwitch.startDriverHandshake() is called more than once.
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeAlreadyStarted extends
+    SwitchDriverSubHandshakeException {
+    private static final long serialVersionUID = -5491845708752443501L;
+
+    public SwitchDriverSubHandshakeAlreadyStarted() {
+        super();
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeCompleted.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeCompleted.java
new file mode 100644
index 0000000..083eead
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeCompleted.java
@@ -0,0 +1,20 @@
+package net.floodlightcontroller.core;
+
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
+
+/**
+ * Indicates that a message was passed to a switch driver's subhandshake
+ * handling code but the driver has already completed the sub-handshake
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeCompleted
+        extends SwitchDriverSubHandshakeException {
+    private static final long serialVersionUID = -8817822245846375995L;
+
+    public SwitchDriverSubHandshakeCompleted(OFMessage m) {
+        super("Sub-Handshake is already complete but received message " +
+              m.getType());
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeException.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeException.java
new file mode 100644
index 0000000..0c0c873
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeException.java
@@ -0,0 +1,27 @@
+package net.floodlightcontroller.core;
+
+/**
+ * Base class for exception thrown by switch driver sub-handshake processing
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeException extends RuntimeException {
+    private static final long serialVersionUID = -6257836781419604438L;
+
+    protected SwitchDriverSubHandshakeException() {
+        super();
+    }
+
+    protected SwitchDriverSubHandshakeException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+    }
+
+    protected SwitchDriverSubHandshakeException(String arg0) {
+        super(arg0);
+    }
+
+    protected SwitchDriverSubHandshakeException(Throwable arg0) {
+        super(arg0);
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeNotStarted.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeNotStarted.java
new file mode 100644
index 0000000..67ec68b
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeNotStarted.java
@@ -0,0 +1,16 @@
+package net.floodlightcontroller.core;
+
+/**
+ * Thrown when a switch driver's sub-handshake has not been started but an
+ * operation requiring the sub-handshake has been attempted.
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeNotStarted extends
+    SwitchDriverSubHandshakeException {
+    private static final long serialVersionUID = -5491845708752443501L;
+
+    public SwitchDriverSubHandshakeNotStarted() {
+        super();
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeStateException.java b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeStateException.java
new file mode 100644
index 0000000..1f49aea
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/SwitchDriverSubHandshakeStateException.java
@@ -0,0 +1,16 @@
+package net.floodlightcontroller.core;
+
+/**
+ * Thrown when a switch driver's sub-handshake state-machine receives an
+ * unexpected OFMessage and/or is in an invald state
+ * @author gregor
+ *
+ */
+public class SwitchDriverSubHandshakeStateException extends
+    SwitchDriverSubHandshakeException {
+    private static final long serialVersionUID = -8249926069195147051L;
+
+    public SwitchDriverSubHandshakeStateException(String msg) {
+        super(msg);
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index a502711..e80311b 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -19,11 +19,10 @@
 
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
-import java.nio.channels.ClosedChannelException;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -39,30 +38,39 @@
 import java.util.concurrent.CopyOnWriteArrayList;
 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.IListener.Command;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
 import net.floodlightcontroller.core.IOFSwitchFilter;
 import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.IUpdate;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
 import net.floodlightcontroller.core.annotations.LogMessageDocs;
-import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState;
+import net.floodlightcontroller.core.internal.OFChannelHandler.RoleRecvStatus;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.util.ListenerDispatcher;
 import net.floodlightcontroller.core.web.CoreWebRoutable;
+import net.floodlightcontroller.debugcounter.IDebugCounter;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
+import net.floodlightcontroller.debugevent.IDebugEventService;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
+import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
+import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
+import net.floodlightcontroller.debugevent.IEventUpdater;
+import net.floodlightcontroller.debugevent.NullDebugEvent;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
-import net.onrc.onos.api.registry.ILocalSwitchMastershipListener;
+import net.floodlightcontroller.util.LoadMonitor;
+import net.onrc.onos.core.drivermanager.DriverManager;
 import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
-import net.onrc.onos.core.main.IOFSwitchPortListener;
 import net.onrc.onos.core.packet.Ethernet;
 import net.onrc.onos.core.registry.IControllerRegistryService;
 import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
@@ -71,123 +79,84 @@
 import net.onrc.onos.core.util.OnosInstanceId;
 
 import org.jboss.netty.bootstrap.ServerBootstrap;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.ChannelStateEvent;
-import org.jboss.netty.channel.ChannelUpstreamHandler;
-import org.jboss.netty.channel.Channels;
-import org.jboss.netty.channel.ExceptionEvent;
-import org.jboss.netty.channel.MessageEvent;
 import org.jboss.netty.channel.group.ChannelGroup;
 import org.jboss.netty.channel.group.DefaultChannelGroup;
 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
-import org.jboss.netty.handler.timeout.IdleStateAwareChannelUpstreamHandler;
-import org.jboss.netty.handler.timeout.IdleStateEvent;
-import org.jboss.netty.handler.timeout.ReadTimeoutException;
-import org.openflow.protocol.OFEchoReply;
-import org.openflow.protocol.OFError;
-import org.openflow.protocol.OFError.OFBadActionCode;
-import org.openflow.protocol.OFError.OFBadRequestCode;
-import org.openflow.protocol.OFError.OFErrorType;
-import org.openflow.protocol.OFError.OFFlowModFailedCode;
-import org.openflow.protocol.OFError.OFHelloFailedCode;
-import org.openflow.protocol.OFError.OFPortModFailedCode;
-import org.openflow.protocol.OFError.OFQueueOpFailedCode;
-import org.openflow.protocol.OFFeaturesReply;
-import org.openflow.protocol.OFGetConfigReply;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
-import org.openflow.protocol.OFPhysicalPort.OFPortState;
-import org.openflow.protocol.OFPortStatus;
-import org.openflow.protocol.OFPortStatus.OFPortReason;
-import org.openflow.protocol.OFSetConfig;
-import org.openflow.protocol.OFStatisticsRequest;
-import org.openflow.protocol.OFSwitchConfig;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.OFVendor;
-import org.openflow.protocol.factory.BasicFactory;
-import org.openflow.protocol.factory.MessageParseException;
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
-import org.openflow.protocol.statistics.OFStatistics;
-import org.openflow.protocol.statistics.OFStatisticsType;
-import org.openflow.protocol.vendor.OFBasicVendorDataType;
-import org.openflow.protocol.vendor.OFBasicVendorId;
-import org.openflow.protocol.vendor.OFVendorId;
-import org.openflow.util.HexString;
-import org.openflow.vendor.nicira.OFNiciraVendorData;
-import org.openflow.vendor.nicira.OFRoleReplyVendorData;
-import org.openflow.vendor.nicira.OFRoleRequestVendorData;
-import org.openflow.vendor.nicira.OFRoleVendorData;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.match.MatchFields;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 
 /**
  * The main controller class.  Handles all setup and network listeners
- * <p/>
- * Extensions made by ONOS are:
- * - Detailed Port event: PORTCHANGED -> {PORTCHANGED, PORTADDED, PORTREMOVED}
- * Available as net.onrc.onos.core.main.IOFSwitchPortListener
- * - Distributed ownership control of switch through RegistryService(IControllerRegistryService)
- * - Register ONOS services. (IControllerRegistryService)
- * - Additional DEBUG logs
- * - Try using hostname as controller ID, when ID was not explicitly given.
+ * - Distributed ownership control of switch through IControllerRegistryService
  */
 public class Controller implements IFloodlightProviderService {
 
     protected final static Logger log = LoggerFactory.getLogger(Controller.class);
-
-    private static final String ERROR_DATABASE =
+    static final String ERROR_DATABASE =
             "The controller could not communicate with the system database.";
+    protected static OFFactory factory13 = OFFactories.getFactory(OFVersion.OF_13);
+    protected static OFFactory factory10 = OFFactories.getFactory(OFVersion.OF_10);
 
-    protected BasicFactory factory;
-    protected ConcurrentMap<OFType,
-            ListenerDispatcher<OFType, IOFMessageListener>>
-            messageListeners;
-    // 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
-    protected ConcurrentHashMap<Long, IOFSwitch> activeSwitches;
-    // connectedSwitches contains all connected switches, including ones where
-    // we're a slave controller. We need to keep track of them so that we can
-    // 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;
+    // connectedSwitches cache contains all connected switch's channelHandlers
+    // including ones where this controller is a master/equal/slave controller
+    // as well as ones that have not been activated yet
+    protected ConcurrentHashMap<Long, OFChannelHandler> connectedSwitches;
+    // These caches contains only those switches that are active
+    protected ConcurrentHashMap<Long, IOFSwitch> activeMasterSwitches;
+    protected ConcurrentHashMap<Long, IOFSwitch> activeEqualSwitches;
+    // lock to synchronize on, when manipulating multiple caches above
+    private Object multiCacheLock;
 
-    // The controllerNodeIPsCache maps Controller IDs to their IP address. 
+    // The controllerNodeIPsCache maps Controller IDs to their IP address.
     // It's only used by handleControllerNodeIPsChanged
     protected HashMap<String, String> controllerNodeIPsCache;
-
-    protected Set<IOFSwitchListener> switchListeners;
     protected BlockingQueue<IUpdate> updates;
 
-    private CopyOnWriteArrayList<ILocalSwitchMastershipListener> localSwitchMastershipListeners =
-        new CopyOnWriteArrayList<>();
+    protected ConcurrentMap<OFType,
+        ListenerDispatcher<OFType, IOFMessageListener>> messageListeners;
+    protected Set<IOFSwitchListener> switchListeners;
 
     // Module dependencies
     protected IRestApiService restApi;
     protected IThreadPoolService threadPool;
     protected IControllerRegistryService registryService;
+    protected IDebugCounterService debugCounters;
+    protected IDebugEventService debugEvents;
 
     protected ILinkDiscoveryService linkDiscovery;
 
     // Configuration options
     protected int openFlowPort = 6633;
     protected int workerThreads = 0;
+
     // The id for this controller node. Should be unique for each controller
     // node in a controller cluster.
     private OnosInstanceId onosInstanceId = new OnosInstanceId("localhost");
 
-    // The current role of the controller.
-    // If the controller isn't configured to support roles, then this is null.
-    protected Role role;
-    // A helper that handles sending and timeout handling for role requests
-    protected RoleChanger roleChanger;
+    // defined counters
+    private Counters counters;
+    // Event IDs for debug events
+    protected IEventUpdater<SwitchEvent> evSwitch;
+
+    // Load monitor for overload protection
+    protected final boolean overload_drop =
+        Boolean.parseBoolean(System.getProperty("overload_drop", "false"));
+    protected final LoadMonitor loadmonitor = new LoadMonitor(log);
 
     // Start time of the controller
     protected long systemStartTime;
@@ -200,12 +169,44 @@
     protected static final int BATCH_MAX_SIZE = 100;
     protected static final boolean ALWAYS_DECODE_ETH = true;
 
+
+
+    // ******************************
+    // Switch Management and Updates
+    // ******************************
+
+    /**
+     * Switch updates are sent to all IOFSwitchListeners. A switch that is connected
+     * to this controller instance, but not activated, is not available for updates.
+     *
+     * In ONOS, each controller instance can simultaneously serve in a MASTER role
+     * for some connected switches, and in a EQUAL role for other connected switches.
+     * The EQUAL role can be treated as a SLAVE role, by ensuring that the
+     * controller instance never sends packets or commands out to the switch.
+     * Activated switches, either with Controller Role MASTER or EQUAL are announced
+     * as updates. We also support announcements of controller role transitions
+     * from MASTER --> EQUAL, and EQUAL --> MASTER, for an individual switch.
+     *
+     * Disconnection of only activated switches are announced. Finally, changes
+     * to switch ports are announced with a portChangeType (see @IOFSwitch)
+     *
+     * @author saurav
+     */
     public enum SwitchUpdateType {
-        ADDED,
-        REMOVED,
+        /** switch activated with this controller's role as MASTER */
+        ACTIVATED_MASTER,
+        /** switch activated with this controller's role as EQUAL.
+         *  listener can treat this controller's role as SLAVE by not
+         *  sending packets or commands to the switch */
+        ACTIVATED_EQUAL,
+        /** this controller's role for this switch changed from Master to Equal */
+        MASTER_TO_EQUAL,
+        /** this controller's role for this switch changed form Equal to Master */
+        EQUAL_TO_MASTER,
+        /** A previously activated switch disconnected */
+        DISCONNECTED,
+        /** Port changed on a previously activated switch */
         PORTCHANGED,
-        PORTADDED,
-        PORTREMOVED
     }
 
     /**
@@ -213,59 +214,269 @@
      * ONOS: This message extended to indicate Port add or removed event.
      */
     protected class SwitchUpdate implements IUpdate {
-        public IOFSwitch sw;
-        public OFPhysicalPort port; // Added by ONOS
-        public SwitchUpdateType switchUpdateType;
-
-        public SwitchUpdate(IOFSwitch sw, SwitchUpdateType switchUpdateType) {
-            this.sw = sw;
-            this.switchUpdateType = switchUpdateType;
+        public long getSwId() {
+            return swId;
         }
 
-        public SwitchUpdate(IOFSwitch sw, OFPhysicalPort port, SwitchUpdateType switchUpdateType) {
-            this.sw = sw;
+        public SwitchUpdateType getSwitchUpdateType() {
+            return switchUpdateType;
+        }
+
+        public PortChangeType getPortChangeType() {
+            return changeType;
+        }
+
+        private final long swId;
+        private final SwitchUpdateType switchUpdateType;
+        private final OFPortDesc port;
+        private final PortChangeType changeType;
+
+        public SwitchUpdate(long swId, SwitchUpdateType switchUpdateType) {
+            this(swId, switchUpdateType, null, null);
+        }
+        public SwitchUpdate(long swId,
+                            SwitchUpdateType switchUpdateType,
+                            OFPortDesc port,
+                            PortChangeType changeType) {
+            if (switchUpdateType == SwitchUpdateType.PORTCHANGED) {
+                if (port == null) {
+                    throw new NullPointerException("Port must not be null " +
+                            "for PORTCHANGED updates");
+                }
+                if (changeType == null) {
+                    throw new NullPointerException("ChangeType must not be " +
+                            "null for PORTCHANGED updates");
+                }
+            } else {
+                if (port != null || changeType != null) {
+                    throw new IllegalArgumentException("port and changeType " +
+                            "must be null for " + switchUpdateType +
+                            " updates");
+                }
+            }
+            this.swId = swId;
+            this.switchUpdateType = switchUpdateType;
             this.port = port;
-            this.switchUpdateType = switchUpdateType;
+            this.changeType = changeType;
         }
 
+        @Override
         public void dispatch() {
             if (log.isTraceEnabled()) {
                 log.trace("Dispatching switch update {} {}",
-                        sw, switchUpdateType);
+                        HexString.toHexString(swId), switchUpdateType);
             }
             if (switchListeners != null) {
                 for (IOFSwitchListener listener : switchListeners) {
-                    switch (switchUpdateType) {
-                        case ADDED:
-                            listener.addedSwitch(sw);
+                    switch(switchUpdateType) {
+                        case ACTIVATED_MASTER:
+                            // don't count here. We have more specific
+                            // counters before the update is created
+                            listener.switchActivatedMaster(swId);
                             break;
-                        case REMOVED:
-                            listener.removedSwitch(sw);
+                        case ACTIVATED_EQUAL:
+                            // don't count here. We have more specific
+                            // counters before the update is created
+                            listener.switchActivatedEqual(swId);
+                            break;
+                        case MASTER_TO_EQUAL:
+                            listener.switchMasterToEqual(swId);
+                            break;
+                        case EQUAL_TO_MASTER:
+                            listener.switchEqualToMaster(swId);
+                            break;
+                        case DISCONNECTED:
+                            // don't count here. We have more specific
+                            // counters before the update is created
+                            listener.switchDisconnected(swId);
                             break;
                         case PORTCHANGED:
-                            listener.switchPortChanged(sw.getId());
-                            break;
-                        case PORTADDED:
-                            if (listener instanceof IOFSwitchPortListener) {
-                                ((IOFSwitchPortListener) listener).switchPortAdded(sw.getId(), port);
-                            }
-                            break;
-                        case PORTREMOVED:
-                            if (listener instanceof IOFSwitchPortListener) {
-                                ((IOFSwitchPortListener) listener).switchPortRemoved(sw.getId(), port);
-                            }
-                            break;
-                        default:
+                            counters.switchPortChanged.updateCounterWithFlush();
+                            listener.switchPortChanged(swId, port, changeType);
                             break;
                     }
                 }
             }
         }
+
+
+    }
+
+    protected boolean addConnectedSwitch(long dpid, OFChannelHandler h) {
+        if (connectedSwitches.get(dpid) != null) {
+            log.error("Trying to add connectedSwitch but found a previous "
+                    + "value for dpid: {}", dpid);
+            return false;
+        } else {
+            connectedSwitches.put(dpid, h);
+            return true;
+        }
+    }
+
+    /**
+     *  Switch Events
+     */
+    @Override
+    public void addSwitchEvent(long dpid, String reason, boolean flushNow) {
+        if (flushNow)
+            evSwitch.updateEventWithFlush(new SwitchEvent(dpid, reason));
+        else
+            evSwitch.updateEventNoFlush(new SwitchEvent(dpid, reason));
+    }
+
+    private boolean validActivation(long dpid) {
+        if (connectedSwitches.get(dpid) == null) {
+            log.error("Trying to activate switch but is not in "
+                    + "connected switches: dpid {}. Aborting ..",
+                    HexString.toHexString(dpid));
+            return false;
+        }
+        if (activeMasterSwitches.get(dpid) != null ||
+                activeEqualSwitches.get(dpid) != null) {
+            log.error("Trying to activate switch but it is already "
+                    + "activated: dpid {}. Found in activeMaster: {} "
+                    + "Found in activeEqual: {}. Aborting ..", new Object[] {
+                            HexString.toHexString(dpid),
+                            (activeMasterSwitches.get(dpid) == null)? 'Y': 'N',
+                            (activeEqualSwitches.get(dpid) == null)? 'Y': 'N'});
+            counters.switchWithSameDpidActivated.updateCounterWithFlush();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Called when a switch is activated, with this controller's role as MASTER
+     */
+    protected boolean addActivatedMasterSwitch(long dpid, IOFSwitch sw) {
+        synchronized(multiCacheLock) {
+            if (!validActivation(dpid)) return false;
+            activeMasterSwitches.put(dpid, sw);
+        }
+        // XXX Workaround to prevent race condition where a link is detected
+        // and attempted to be written to the database before the port is in
+        // the database. We now suppress link discovery on ports until we're
+        // sure they're in the database.
+        for (OFPortDesc port : sw.getPorts()) {
+            linkDiscovery.disableDiscoveryOnPort(sw.getId(),
+                    port.getPortNo().getShortPortNumber());
+        }
+        //update counters and events
+        counters.switchActivated.updateCounterWithFlush();
+        evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "activeMaster"));
+        addUpdateToQueue(new SwitchUpdate(dpid,
+                SwitchUpdateType.ACTIVATED_MASTER));
+        return true;
+    }
+
+    /**
+     * Called when a switch is activated, with this controller's role as EQUAL
+     */
+    protected boolean addActivatedEqualSwitch(long dpid, IOFSwitch sw) {
+        synchronized(multiCacheLock) {
+            if (!validActivation(dpid)) return false;
+            activeEqualSwitches.put(dpid, sw);
+        }
+        //update counters and events
+        counters.switchActivated.updateCounterWithFlush();
+        evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "activeEqual"));
+        addUpdateToQueue(new SwitchUpdate(dpid,
+                SwitchUpdateType.ACTIVATED_EQUAL));
+        return true;
+    }
+
+    /**
+     * Called when this controller's role for a switch transitions from equal
+     * to master. For 1.0 switches, we internally refer to the role 'slave' as
+     * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
+     */
+    protected void transitionToMasterSwitch(long dpid) {
+	synchronized(multiCacheLock) {
+		IOFSwitch sw = activeEqualSwitches.remove(dpid);
+		if (sw == null) {
+			log.error("Transition to master called on sw {}, but switch "
+					+ "was not found in controller-cache", dpid);
+			return;
+		}
+		activeMasterSwitches.put(dpid, sw);
+	}
+	addUpdateToQueue(new SwitchUpdate(dpid,
+                SwitchUpdateType.EQUAL_TO_MASTER));
+    }
+
+
+    /**
+     * Called when this controller's role for a switch transitions to equal.
+     * For 1.0 switches, we internally refer to the role 'slave' as
+     * 'equal'.
+     */
+    protected void transitionToEqualSwitch(long dpid) {
+	synchronized(multiCacheLock) {
+		IOFSwitch sw = activeMasterSwitches.remove(dpid);
+		if (sw == null) {
+			log.error("Transition to equal called on sw {}, but switch "
+					+ "was not found in controller-cache", dpid);
+			return;
+		}
+		activeEqualSwitches.put(dpid, sw);
+	}
+	addUpdateToQueue(new SwitchUpdate(dpid,
+                SwitchUpdateType.MASTER_TO_EQUAL));
+    }
+
+    /**
+     * Clear all state in controller switch maps for a switch that has
+     * disconnected from the local controller. Also release control for
+     * that switch from the global repository. Notify switch listeners.
+     */
+    protected void removeConnectedSwitch(long dpid) {
+        releaseRegistryControl(dpid);
+        connectedSwitches.remove(dpid);
+        IOFSwitch sw = activeMasterSwitches.remove(dpid);
+        if (sw == null) sw = activeEqualSwitches.remove(dpid);
+        if (sw != null) {
+            sw.cancelAllStatisticsReplies();
+            sw.setConnected(false); // do we need this?
+        }
+        evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "disconnected"));
+        counters.switchDisconnected.updateCounterWithFlush();
+        addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.DISCONNECTED));
+    }
+
+    /**
+     * Indicates that ports on the given switch have changed. Enqueue a
+     * switch update.
+     * @param sw
+     */
+    protected void notifyPortChanged(long dpid, OFPortDesc port,
+            PortChangeType changeType) {
+        if (port == null || changeType == null) {
+            String msg = String.format("Switch port or changetType must not "
+                    + "be null in port change notification");
+            throw new NullPointerException(msg);
+        }
+        if (connectedSwitches.get(dpid) == null || getSwitch(dpid) == null) {
+            log.warn("Port change update on switch {} not connected or activated "
+                    + "... Aborting.", HexString.toHexString(dpid));
+            return;
+        }
+
+        if (changeType == PortChangeType.ADD) {
+            // XXX Workaround to prevent race condition where a link is detected
+            // and attempted to be written to the database before the port is in
+            // the database. We now suppress link discovery on ports until we're
+            // sure they're in the database.
+            linkDiscovery.disableDiscoveryOnPort(dpid, port.getPortNo().getShortPortNumber());
+        }
+
+        SwitchUpdate update = new SwitchUpdate(dpid, SwitchUpdateType.PORTCHANGED,
+                port, changeType);
+        addUpdateToQueue(update);
     }
 
     // ***************
     // Getters/Setters
-    // *************** 
+    // ***************
 
     public void setRestApiService(IRestApiService restApi) {
         this.restApi = restApi;
@@ -283,920 +494,120 @@
         this.linkDiscovery = linkDiscovery;
     }
 
-    public void publishUpdate(IUpdate update) {
-        try {
-            this.updates.put(update);
-        } catch (InterruptedException e) {
-            log.error("Failure adding update to queue", e);
-        }
+    public void setDebugCounter(IDebugCounterService debugCounters) {
+        this.debugCounters = debugCounters;
+    }
+
+    public void setDebugEvent(IDebugEventService debugEvents) {
+        this.debugEvents = debugEvents;
+    }
+
+    IDebugCounterService getDebugCounter() {
+        return this.debugCounters;
     }
 
     // **********************
-    // ChannelUpstreamHandler
+    // Role Handling
     // **********************
 
-    /**
-     * Return a new channel handler for processing a switch connections
-     *
-     * @param state The channel state object for the connection
-     * @return the new channel handler
+    /** created by ONOS - works with registry service
      */
-    protected ChannelUpstreamHandler getChannelHandler(OFChannelState state) {
-        return new OFChannelHandler(state);
-    }
-
     protected class RoleChangeCallback implements ControlChangeCallback {
         @Override
         public void controlChanged(long dpidLong, boolean hasControl) {
             Dpid dpid = new Dpid(dpidLong);
             log.info("Role change callback for switch {}, hasControl {}",
-                     dpid, hasControl);
+                    dpid, hasControl);
 
-            synchronized (roleChanger) {
-                Role role = null;
-                /*
-                 * issue #229
-                 * Cannot rely on sw.getRole() as it can be behind due to pending
-                 * role changes in the queue. Just submit it and late the RoleChanger
-                 * handle duplicates.
-                 */
-                if (hasControl) {
-                    role = Role.MASTER;
-                } else {
-                    role = Role.SLAVE;
-                }
-                //
-                // Inform all listeners about the Controller role change.
-                //
-                // NOTE: The role change here is triggered by the mastership
-                // election mechanism, and reflects what the Controller itself
-                // believes its role should be. The role change request hasn't
-                // been accepted by the switch itself.
-                // If the semantics for informing the listeners is changed
-                // (i.e., the listeners should be informed after the switch
-                // has accepted the role change), then the code below should
-                // be moved to method handleRoleReplyMessage() or its
-                // equivalent.
-                // 
-                for (ILocalSwitchMastershipListener listener : localSwitchMastershipListeners) {
-                    listener.controllerRoleChanged(dpid, role);
-                }
-
-                OFSwitchImpl sw = null;
-                for (OFSwitchImpl connectedSw : connectedSwitches) {
-                    if (connectedSw.getId() == dpidLong) {
-                        sw = connectedSw;
-                        break;
-                    }
-                }
-                if (sw == null) {
-                    log.warn("Switch {} not found in connected switches",
-                             dpid);
-                    return;
-                }
-
-                log.debug("Sending role request {} msg to {}", role, sw);
-                Collection<OFSwitchImpl> swList = new ArrayList<OFSwitchImpl>(1);
-                swList.add(sw);
-                roleChanger.submitRequest(swList, role);
-            }
-        }
-    }
-
-    /**
-     * Channel handler deals with the switch connection and dispatches
-     * switch messages to the appropriate locations.
-     *
-     * @author readams
-     */
-    protected class OFChannelHandler
-            extends IdleStateAwareChannelUpstreamHandler {
-        protected OFSwitchImpl sw;
-        protected OFChannelState state;
-
-        public OFChannelHandler(OFChannelState state) {
-            this.state = state;
-        }
-
-        @Override
-        @LogMessageDoc(message = "New switch connection from {ip address}",
-                explanation = "A new switch has connected from the " +
-                        "specified IP address")
-        public void channelConnected(ChannelHandlerContext ctx,
-                                     ChannelStateEvent e) throws Exception {
-            log.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);
-
-        }
-
-        @Override
-        @LogMessageDoc(message = "Disconnected switch {switch information}",
-                explanation = "The specified switch has disconnected.")
-        public void channelDisconnected(ChannelHandlerContext ctx,
-                                        ChannelStateEvent e) throws Exception {
-            if (sw != null && state.hsState == HandshakeState.READY) {
-                if (activeSwitches.containsKey(sw.getId())) {
-                    // It's safe to call removeSwitch even though the map might
-                    // not contain this particular switch but another with the 
-                    // same DPID
-                    removeSwitch(sw);
-                }
-                synchronized (roleChanger) {
-                    if (controlRequested) {
-
-                        //
-                        // Inform all listeners about the switch disconnection
-                        //
-                        Dpid dpid = new Dpid(sw.getId());
-                        for (ILocalSwitchMastershipListener listener :
-                                 localSwitchMastershipListeners) {
-                            listener.switchDisconnected(dpid);
-                        }
-
-                        registryService.releaseControl(sw.getId());
-                    }
-                    connectedSwitches.remove(sw);
-                }
-                sw.setConnected(false);
-            }
-            log.info("Disconnected switch {}", sw);
-        }
-
-        @Override
-        @LogMessageDocs({
-                @LogMessageDoc(level = "ERROR",
-                        message = "Disconnecting switch {switch} due to read timeout",
-                        explanation = "The connected switch has failed to send any " +
-                                "messages or respond to echo requests",
-                        recommendation = LogMessageDoc.CHECK_SWITCH),
-                @LogMessageDoc(level = "ERROR",
-                        message = "Disconnecting switch {switch}: failed to " +
-                                "complete handshake",
-                        explanation = "The switch did not respond correctly " +
-                                "to handshake messages",
-                        recommendation = LogMessageDoc.CHECK_SWITCH),
-                @LogMessageDoc(level = "ERROR",
-                        message = "Disconnecting switch {switch} due to IO Error: {}",
-                        explanation = "There was an error communicating with the switch",
-                        recommendation = LogMessageDoc.CHECK_SWITCH),
-                @LogMessageDoc(level = "ERROR",
-                        message = "Disconnecting switch {switch} due to switch " +
-                                "state error: {error}",
-                        explanation = "The switch sent an unexpected message",
-                        recommendation = LogMessageDoc.CHECK_SWITCH),
-                @LogMessageDoc(level = "ERROR",
-                        message = "Disconnecting switch {switch} due to " +
-                                "message parse failure",
-                        explanation = "Could not parse a message from the switch",
-                        recommendation = LogMessageDoc.CHECK_SWITCH),
-                @LogMessageDoc(level = "ERROR",
-                        message = "Could not process message: queue full",
-                        explanation = "OpenFlow messages are arriving faster than " +
-                                " the controller can process them.",
-                        recommendation = LogMessageDoc.CHECK_CONTROLLER),
-                @LogMessageDoc(level = "ERROR",
-                        message = "Error while processing message " +
-                                "from switch {switch} {cause}",
-                        explanation = "An error occurred processing the switch message",
-                        recommendation = LogMessageDoc.GENERIC_ACTION)
-        })
-        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
-                throws Exception {
-            if (e.getCause() instanceof ReadTimeoutException) {
-                // switch timeout
-                log.error("Disconnecting switch {} due to read timeout", sw);
-                ctx.getChannel().close();
-            } else if (e.getCause() instanceof HandshakeTimeoutException) {
-                log.error("Disconnecting switch {}: failed to complete handshake",
-                        sw);
-                ctx.getChannel().close();
-            } else if (e.getCause() instanceof ClosedChannelException) {
-                //log.warn("Channel for sw {} already closed", sw);
-            } else if (e.getCause() instanceof IOException) {
-                log.error("Disconnecting switch {} due to IO Error: {}",
-                        sw, e.getCause().getMessage());
-                ctx.getChannel().close();
-            } else if (e.getCause() instanceof SwitchStateException) {
-                log.error("Disconnecting switch {} due to switch state error: {}",
-                        sw, e.getCause().getMessage());
-                ctx.getChannel().close();
-            } else if (e.getCause() instanceof MessageParseException) {
-                log.error("Disconnecting switch " + sw +
-                        " due to message parse failure",
-                        e.getCause());
-                ctx.getChannel().close();
-            } else if (e.getCause() instanceof RejectedExecutionException) {
-                log.warn("Could not process message: queue full");
-            } else {
-                log.error("Error while processing message from switch " + sw,
-                        e.getCause());
-                ctx.getChannel().close();
-            }
-        }
-
-        @Override
-        public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
-                throws Exception {
-            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-            msglist.add(factory.getMessage(OFType.ECHO_REQUEST));
-            e.getChannel().write(msglist);
-        }
-
-        @Override
-        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
-                throws Exception {
-            if (e.getMessage() instanceof List) {
-                @SuppressWarnings("unchecked")
-                List<OFMessage> msglist = (List<OFMessage>) e.getMessage();
-
-                for (OFMessage ofm : msglist) {
-                    try {
-                        processOFMessage(ofm);
-                    } catch (Exception ex) {
-                        // We are the last handler in the stream, so run the 
-                        // exception through the channel again by passing in 
-                        // ctx.getChannel().
-                        Channels.fireExceptionCaught(ctx.getChannel(), ex);
-                    }
-                }
-
-                // Flush all flow-mods/packet-out generated from this "train"
-                OFSwitchImpl.flush_all();
-            }
-        }
-
-        /**
-         * Process the request for the switch description
-         */
-        @LogMessageDoc(level = "ERROR",
-                message = "Exception in reading description " +
-                        " during handshake {exception}",
-                explanation = "Could not process the switch description string",
-                recommendation = LogMessageDoc.CHECK_SWITCH)
-        @SuppressWarnings("unchecked")
-        void processSwitchDescReply() {
-            try {
-                // Read description, if it has been updated
-                Future<?> future =
-                        (Future<?>) sw.
-                                getAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE);
-                Future<List<OFStatistics>> desc_future =
-                        (Future<List<OFStatistics>>) 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;
-                }
-
-                sw.removeAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE);
-                state.hasDescription = true;
-                checkSwitchReady();
-            } catch (InterruptedException ex) {
-                // Ignore
-            } catch (TimeoutException ex) {
-                // Ignore
-            } catch (Exception ex) {
-                log.error("Exception in reading description " +
-                        " during handshake", ex);
-            }
-        }
-
-        /**
-         * Send initial switch setup information that we need before adding
-         * the switch
-         *
-         * @throws IOException
-         */
-        void sendHelloConfiguration() throws IOException {
-            // Send initial Features Request
-            log.debug("Sending FEATURES_REQUEST to {}", sw);
-            sw.write(factory.getMessage(OFType.FEATURES_REQUEST), null);
-        }
-
-        /**
-         * Send the configuration requests we can only do after we have
-         * the features reply
-         *
-         * @throws IOException
-         */
-        void sendFeatureReplyConfiguration() throws IOException {
-            log.debug("Sending CONFIG_REQUEST to {}", sw);
-            // Ensure we receive the full packet via PacketIn
-            OFSetConfig config = (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);
-
-            // Get Description to set switch-specific flags
-            OFStatisticsRequest req = new OFStatisticsRequest();
-            req.setStatisticType(OFStatisticsType.DESC);
-            req.setLengthU(req.getLengthU());
-            Future<List<OFStatistics>> dfuture =
-                    sw.getStatistics(req);
-            sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE,
-                    dfuture);
-
-        }
-
-        volatile Boolean controlRequested = Boolean.FALSE;
-
-        protected void checkSwitchReady() {
-            if (state.hsState == HandshakeState.FEATURES_REPLY &&
-                    state.hasDescription && state.hasGetConfigReply) {
-
-                state.hsState = HandshakeState.READY;
-                log.debug("Handshake with {} complete", sw);
-
-                synchronized (roleChanger) {
-                    // We need to keep track of all of the switches that are connected
-                    // to the controller, in any role, so that we can later send the
-                    // role request messages when the controller role changes.
-                    // We need to be synchronized while doing this: we must not
-                    // send a another role request to the connectedSwitches until
-                    // we were able to add this new switch to connectedSwitches
-                    // *and* send the current role to the new switch.
-                    connectedSwitches.add(sw);
-
-                    if (role != null) {
-                        //Put the switch in SLAVE mode until we know we have control
-                        log.debug("Setting new switch {} to SLAVE", sw.getStringId());
-                        Collection<OFSwitchImpl> swList = new ArrayList<OFSwitchImpl>(1);
-                        swList.add(sw);
-                        roleChanger.submitRequest(swList, Role.SLAVE);
-
-                        //Request control of the switch from the global registry
-                        try {
-                            controlRequested = Boolean.TRUE;
-                            registryService.requestControl(sw.getId(),
-                                    new RoleChangeCallback());
-                        } catch (RegistryException e) {
-                            log.debug("Registry error: {}", e.getMessage());
-                            controlRequested = Boolean.FALSE;
-                        }
-
-
-                        // Send a role request if role support is enabled for the controller
-                        // This is a probe that we'll use to determine if the switch
-                        // actually supports the role request message. If it does we'll
-                        // get back a role reply message. If it doesn't we'll get back an
-                        // OFError message.
-                        // If role is MASTER we will promote switch to active
-                        // list when we receive the switch's role reply messages
-                        /*
-                        log.debug("This controller's role is {}, " +
-                                "sending initial role request msg to {}",
-                                role, sw);
-                        Collection<OFSwitchImpl> swList = new ArrayList<OFSwitchImpl>(1);
-                        swList.add(sw);
-                        roleChanger.submitRequest(swList, role);
-                        */
-                    } else {
-                        // Role supported not enabled on controller (for now)
-                        // automatically promote switch to active state.
-                        log.debug("This controller's role is {}, " +
-                                "not sending role request msg to {}",
-                                role, sw);
-                        // Need to clear FlowMods before we add the switch
-                        // and dispatch updates otherwise we have a race condition.
-                        sw.clearAllFlowMods();
-                        addSwitch(sw);
-                        state.firstRoleReplyReceived = true;
-                    }
-                }
-                if (!controlRequested) {
-                    // yield to allow other thread(s) to release control
-                    try {
-                        Thread.sleep(10);
-                    } catch (InterruptedException e) {
-                        // Ignore interruptions
-                    }
-                    // safer to bounce the switch to reconnect here than proceeding further
-                    log.debug("Closing {} because we weren't able to request control " +
-                            "successfully" + sw);
-                    sw.channel.close();
-                }
-            }
-        }
-
-        /* 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
-         * to synchronize addSwitch(), removeSwitch() operations from the same
-         * connection.
-         * FIXME: However, when a switch with the same DPID connects we do
-         * need some synchronization. However, handling switches with same
-         * DPID needs to be revisited anyways (get rid of r/w-lock and synchronous
-         * removedSwitch notification):1
-         *
-         */
-        @LogMessageDoc(level = "ERROR",
-                message = "Invalid role value in role reply message",
-                explanation = "Was unable to set the HA role (master or slave) " +
-                        "for the controller.",
-                recommendation = LogMessageDoc.CHECK_CONTROLLER)
-        protected void handleRoleReplyMessage(OFVendor vendorMessage,
-                                              OFRoleReplyVendorData roleReplyVendorData) {
-            // Map from the role code in the message to our role enum
-            int nxRole = roleReplyVendorData.getRole();
             Role role = null;
-            switch (nxRole) {
-                case OFRoleVendorData.NX_ROLE_OTHER:
-                    role = Role.EQUAL;
-                    break;
-                case OFRoleVendorData.NX_ROLE_MASTER:
-                    role = Role.MASTER;
-                    break;
-                case OFRoleVendorData.NX_ROLE_SLAVE:
-                    role = Role.SLAVE;
-                    break;
-                default:
-                    log.error("Invalid role value in role reply message");
-                    sw.getChannel().close();
-                    return;
-            }
 
-            log.debug("Handling role reply for role {} from {}. " +
-                    "Controller's role is {} ",
-                    new Object[]{role, sw, Controller.this.role}
-            );
+            /*
+             * issue #229
+             * Cannot rely on sw.getRole() as it can be behind due to pending
+             * role changes in the queue. Just submit it and late the
+             * RoleChanger handle duplicates.
+             */
 
-            sw.deliverRoleReply(vendorMessage.getXid(), role);
-
-            boolean isActive = activeSwitches.containsKey(sw.getId());
-            if (!isActive && sw.isActive()) {
-                // Transition from SLAVE to MASTER.
-
-                if (!state.firstRoleReplyReceived ||
-                        getAlwaysClearFlowsOnSwAdd()) {
-                    // This is the first role-reply message we receive from
-                    // this switch or roles were disabled when the switch
-                    // connected:
-                    // Delete all pre-existing flows for new connections to
-                    // the master
-                    //
-                    // FIXME: Need to think more about what the test should
-                    // be for when we flush the flow-table? For example,
-                    // if all the controllers are temporarily in the backup
-                    // role (e.g. right after a failure of the master
-                    // controller) at the point the switch connects, then
-                    // all of the controllers will initially connect as
-                    // backup controllers and not flush the flow-table.
-                    // Then when one of them is promoted to master following
-                    // the master controller election the flow-table
-                    // will still not be flushed because that's treated as
-                    // a failover event where we don't want to flush the
-                    // flow-table. The end result would be that the flow
-                    // table for a newly connected switch is never
-                    // flushed. Not sure how to handle that case though...
-                    sw.clearAllFlowMods();
-                    log.debug("First role reply from master switch {}, " +
-                            "clear FlowTable to active switch list",
-                            HexString.toHexString(sw.getId()));
-                }
-
-                // Some switches don't seem to update us with port
-                // status messages while in slave role.
-                //readSwitchPortStateFromStorage(sw);
-
-                // Only add the switch to the active switch list if
-                // we're not in the slave role. Note that if the role
-                // attribute is null, then that means that the switch
-                // doesn't support the role request messages, so in that
-                // case we're effectively in the EQUAL role and the
-                // switch should be included in the active switch list.
-                addSwitch(sw);
-                log.debug("Added master switch {} to active switch list",
-                        HexString.toHexString(sw.getId()));
-
-            } else if (isActive && !sw.isActive()) {
-                // Transition from MASTER to SLAVE: remove switch
-                // from active switch list.
-                log.debug("Removed slave switch {} from active switch" +
-                        " list", HexString.toHexString(sw.getId()));
-                removeSwitch(sw);
-            }
-
-            // Indicate that we have received a role reply message.
-            state.firstRoleReplyReceived = true;
-        }
-
-        protected boolean handleVendorMessage(OFVendor vendorMessage) {
-            boolean shouldHandleMessage = false;
-            int vendor = vendorMessage.getVendor();
-            switch (vendor) {
-                case OFNiciraVendorData.NX_VENDOR_ID:
-                    OFNiciraVendorData niciraVendorData =
-                            (OFNiciraVendorData) vendorMessage.getVendorData();
-                    int dataType = niciraVendorData.getDataType();
-                    switch (dataType) {
-                        case OFRoleReplyVendorData.NXT_ROLE_REPLY:
-                            OFRoleReplyVendorData roleReplyVendorData =
-                                    (OFRoleReplyVendorData) niciraVendorData;
-                            handleRoleReplyMessage(vendorMessage,
-                                    roleReplyVendorData);
-                            break;
-                        default:
-                            log.warn("Unhandled Nicira VENDOR message; " +
-                                    "data type = {}", dataType);
-                            break;
-                    }
-                    break;
-                default:
-                    log.warn("Unhandled VENDOR message; vendor id = {}", vendor);
-                    break;
-            }
-
-            return shouldHandleMessage;
-        }
-
-        /**
-         * Dispatch an Openflow message from a switch to the appropriate
-         * handler.
-         *
-         * @param m The message to process
-         * @throws IOException
-         * @throws SwitchStateException
-         */
-        @LogMessageDocs({
-                @LogMessageDoc(level = "WARN",
-                        message = "Config Reply from {switch} has " +
-                                "miss length set to {length}",
-                        explanation = "The controller requires that the switch " +
-                                "use a miss length of 0xffff for correct " +
-                                "function",
-                        recommendation = "Use a different switch to ensure " +
-                                "correct function"),
-                @LogMessageDoc(level = "WARN",
-                        message = "Received ERROR from sw {switch} that "
-                                + "indicates roles are not supported "
-                                + "but we have received a valid "
-                                + "role reply earlier",
-                        explanation = "The switch sent a confusing message to the" +
-                                "controller")
-        })
-        protected void processOFMessage(OFMessage m)
-                throws IOException, SwitchStateException {
-            boolean shouldHandleMessage = false;
-
-            switch (m.getType()) {
-                case HELLO:
-                    if (log.isTraceEnabled())
-                        log.trace("HELLO from {}", sw);
-
-                    if (state.hsState.equals(HandshakeState.START)) {
-                        state.hsState = HandshakeState.HELLO;
-                        sendHelloConfiguration();
-                    } else {
-                        throw new SwitchStateException("Unexpected HELLO from "
-                                + sw);
-                    }
-                    break;
-                case ECHO_REQUEST:
-                    OFEchoReply reply =
-                            (OFEchoReply) factory.getMessage(OFType.ECHO_REPLY);
-                    reply.setXid(m.getXid());
-                    sw.write(reply, null);
-                    break;
-                case ECHO_REPLY:
-                    break;
-                case FEATURES_REPLY:
-                    if (log.isTraceEnabled())
-                        log.trace("Features Reply from {}", sw);
-
-                    sw.setFeaturesReply((OFFeaturesReply) m);
-                    if (state.hsState.equals(HandshakeState.HELLO)) {
-                        sendFeatureReplyConfiguration();
-                        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.deliverOFFeaturesReply(m);
-                        // update database */
-                        //updateActiveSwitchInfo(sw);
-                    }
-                    break;
-                case GET_CONFIG_REPLY:
-                    if (log.isTraceEnabled())
-                        log.trace("Get config reply from {}", sw);
-
-                    if (!state.hsState.equals(HandshakeState.FEATURES_REPLY)) {
-                        String em = "Unexpected GET_CONFIG_REPLY from " + sw;
-                        throw new SwitchStateException(em);
-                    }
-                    OFGetConfigReply cr = (OFGetConfigReply) m;
-                    if (cr.getMissSendLength() == (short) 0xffff) {
-                        log.trace("Config Reply from {} confirms " +
-                                "miss length set to 0xffff", sw);
-                    } else {
-                        log.warn("Config Reply from {} has " +
-                                "miss length set to {}",
-                                sw, cr.getMissSendLength() & 0xffff);
-                    }
-                    state.hasGetConfigReply = true;
-                    checkSwitchReady();
-                    break;
-                case VENDOR:
-                    shouldHandleMessage = handleVendorMessage((OFVendor) m);
-                    break;
-                case ERROR:
-                    log.debug("Recieved ERROR message from switch {}: {}", sw, m);
-                    // TODO: we need better error handling. Especially for
-                    // request/reply style message (stats, roles) we should have
-                    // a unified way to lookup the xid in the error message.
-                    // This will probable involve rewriting the way we handle
-                    // request/reply style messages.
-                    OFError error = (OFError) m;
-                    boolean shouldLogError = true;
-                    // TODO: should we check that firstRoleReplyReceived is false,
-                    // i.e., check only whether the first request fails?
-                    if (sw.checkFirstPendingRoleRequestXid(error.getXid())) {
-                        boolean isBadVendorError =
-                                (error.getErrorType() == OFError.OFErrorType.
-                                        OFPET_BAD_REQUEST.getValue());
-                        // We expect to receive a bad vendor error when
-                        // we're connected to a switch that doesn't support
-                        // the Nicira vendor extensions (i.e. not OVS or
-                        // derived from OVS).  By protocol, it should also be
-                        // BAD_VENDOR, but too many switch implementations
-                        // get it wrong and we can already check the xid()
-                        // so we can ignore the type with confidence that this
-                        // is not a spurious error
-                        shouldLogError = !isBadVendorError;
-                        if (isBadVendorError) {
-                            log.debug("Handling bad vendor error for {}", sw);
-                            if (state.firstRoleReplyReceived && (role != null)) {
-                                log.warn("Received ERROR from sw {} that "
-                                        + "indicates roles are not supported "
-                                        + "but we have received a valid "
-                                        + "role reply earlier", sw);
-                            }
-                            state.firstRoleReplyReceived = true;
-                            Role requestedRole =
-                                    sw.deliverRoleRequestNotSupportedEx(error.getXid());
-                            synchronized (roleChanger) {
-                                if (sw.role == null && Controller.this.role == Role.SLAVE) {
-                                    //This will now never happen. The Controller's role
-                                    //is now never SLAVE, always MASTER.
-                                    // 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
-                                    log.warn("Closing {} channel because controller's role " +
-                                            "is SLAVE", sw);
-                                    sw.getChannel().close();
-                                } else if (sw.role == null && requestedRole == Role.MASTER) {
-                                    log.debug("Adding switch {} because we got an error" +
-                                            " returned from a MASTER role request", sw);
-                                    // Controller's role is master: add to
-                                    // active
-                                    // TODO: check if clearing flow table is
-                                    // right choice here.
-                                    // Need to clear FlowMods before we add the switch
-                                    // and dispatch updates otherwise we have a race condition.
-                                    // TODO: switch update is async. Won't we still have a potential
-                                    //       race condition?
-                                    sw.clearAllFlowMods();
-                                    addSwitch(sw);
-                                }
-                            }
-                        } else {
-                            // TODO: Is this the right thing to do if we receive
-                            // some other error besides a bad vendor error?
-                            // Presumably that means the switch did actually
-                            // understand the role request message, but there
-                            // was some other error from processing the message.
-                            // OF 1.2 specifies a OFPET_ROLE_REQUEST_FAILED
-                            // error code, but it doesn't look like the Nicira
-                            // role request has that. Should check OVS source
-                            // code to see if it's possible for any other errors
-                            // to be returned.
-                            // If we received an error the switch is not
-                            // in the correct role, so we need to disconnect it.
-                            // We could also resend the request but then we need to
-                            // check if there are other pending request in which
-                            // case we shouldn't resend. If we do resend we need
-                            // to make sure that the switch eventually accepts one
-                            // of our requests or disconnect the switch. This feels
-                            // cumbersome.
-                            log.debug("Closing {} channel because we recieved an " +
-                                    "error other than BAD_VENDOR", sw);
-                            sw.getChannel().close();
-                        }
-                    }
-                    // Once we support OF 1.2, we'd add code to handle it here.
-                    //if (error.getXid() == state.ofRoleRequestXid) {
-                    //}
-                    if (shouldLogError)
-                        logError(sw, error);
-                    break;
-                case STATS_REPLY:
-                    if (state.hsState.ordinal() <
-                            HandshakeState.FEATURES_REPLY.ordinal()) {
-                        String em = "Unexpected STATS_REPLY from " + sw;
-                        throw new SwitchStateException(em);
-                    }
-                    sw.deliverStatisticsReply(m);
-                    if (sw.hasAttribute(IOFSwitch.SWITCH_DESCRIPTION_FUTURE)) {
-                        processSwitchDescReply();
-                    }
-                    break;
-                case PORT_STATUS:
-                    // We want to update our port state info even if we're in
-                    // the slave role, but we only want to update storage if
-                    // we're the master (or equal).
-                    boolean updateStorage = state.hsState.
-                            equals(HandshakeState.READY) &&
-                            (sw.getRole() != Role.SLAVE);
-                    handlePortStatusMessage(sw, (OFPortStatus) m, updateStorage);
-                    shouldHandleMessage = true;
-                    break;
-
-                default:
-                    shouldHandleMessage = true;
-                    break;
-            }
-
-            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);
-                            }
-                        } else {
-                            handleMessage(sw, m, null);
-                        }
-                    }
-                } finally {
-                    sw.getListenerReadLock().unlock();
-                }
-            }
-        }
-    }
-
-    // ****************
-    // Message handlers
-    // ****************
-
-    protected void handlePortStatusMessage(IOFSwitch sw,
-                                           OFPortStatus m,
-                                           boolean updateStorage) {
-        short portNumber = m.getDesc().getPortNumber();
-        OFPhysicalPort port = m.getDesc();
-        if (m.getReason() == (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
-            boolean portDown = ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0) ||
-                    ((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0);
-            sw.setPort(port);
-            if (!portDown) {
-                SwitchUpdate update = new SwitchUpdate(sw, port, SwitchUpdateType.PORTADDED);
-                try {
-                    this.updates.put(update);
-                } catch (InterruptedException e) {
-                    log.error("Failure adding update to queue", e);
-                }
+            if (hasControl) {
+                role = Role.MASTER;
             } else {
-                SwitchUpdate update = new SwitchUpdate(sw, port, SwitchUpdateType.PORTREMOVED);
-                try {
-                    this.updates.put(update);
-                } catch (InterruptedException e) {
-                    log.error("Failure adding update to queue", e);
-                }
+                role = Role.EQUAL; // treat the same as Role.SLAVE
             }
-            //if (updateStorage)
-            //updatePortInfo(sw, port);
-            log.debug("Port #{} modified for {}", portNumber, sw);
-        } else if (m.getReason() == (byte) OFPortReason.OFPPR_ADD.ordinal()) {
-            // XXX Workaround to prevent race condition where a link is detected
-            // and attempted to be written to the database before the port is in
-            // the database. We now suppress link discovery on ports until we're
-            // sure they're in the database.
-            linkDiscovery.disableDiscoveryOnPort(sw.getId(), port.getPortNumber());
 
-            sw.setPort(port);
-            SwitchUpdate update = new SwitchUpdate(sw, port, SwitchUpdateType.PORTADDED);
-            try {
-                this.updates.put(update);
-            } catch (InterruptedException e) {
-                log.error("Failure adding update to queue", e);
+            OFChannelHandler swCh = connectedSwitches.get(dpid.value());
+            if (swCh == null) {
+                log.warn("Switch {} not found in connected switches", dpid);
+                return;
             }
-            //if (updateStorage)
-            //updatePortInfo(sw, port);
-            log.debug("Port #{} added for {}", portNumber, sw);
-        } else if (m.getReason() ==
-                (byte) OFPortReason.OFPPR_DELETE.ordinal()) {
-            sw.deletePort(portNumber);
-            SwitchUpdate update = new SwitchUpdate(sw, port, SwitchUpdateType.PORTREMOVED);
-            try {
-                this.updates.put(update);
-            } catch (InterruptedException e) {
-                log.error("Failure adding update to queue", e);
-            }
-            //if (updateStorage)
-            //removePortInfo(sw, portNumber);
-            log.debug("Port #{} deleted for {}", portNumber, sw);
+
+            log.debug("Sending role request {} msg to {}", role, dpid);
+            swCh.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
         }
-        SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.PORTCHANGED);
+    }
+
+    public synchronized void submitRegistryRequest(long dpid) {
+        OFChannelHandler h = connectedSwitches.get(dpid);
+        if (h == null) {
+            log.error("Trying to request registry control for switch {} "
+                    + "not in connected switches. Aborting.. ",
+                    HexString.toHexString(dpid));
+            // FIXME shouldn't we immediately return here?
+        }
+        //Request control of the switch from the global registry
         try {
-            this.updates.put(update);
-        } catch (InterruptedException e) {
-            log.error("Failure adding update to queue", e);
+            h.controlRequested = Boolean.TRUE;
+            registryService.requestControl(dpid, new RoleChangeCallback());
+        } catch (RegistryException e) {
+            log.debug("Registry error: {}", e.getMessage());
+            h.controlRequested = Boolean.FALSE;
+        }
+        if (!h.controlRequested) { // XXX what is being attempted here?
+            // yield to allow other thread(s) to release control
+            try {
+                Thread.sleep(10);
+            } catch (InterruptedException e) {
+                // Ignore interruptions
+            }
+            // safer to bounce the switch to reconnect here than proceeding further
+            // XXX S why? can't we just try again a little later?
+            log.debug("Closing sw:{} because we weren't able to request control " +
+                    "successfully" + dpid);
+            connectedSwitches.get(dpid).disconnectSwitch();
         }
     }
 
-    /**
-     * flcontext_cache - Keep a thread local stack of contexts
-     */
-    protected static final ThreadLocal<Stack<FloodlightContext>> flcontext_cache =
-            new ThreadLocal<Stack<FloodlightContext>>() {
-                @Override
-                protected Stack<FloodlightContext> initialValue() {
-                    return new Stack<FloodlightContext>();
-                }
-            };
-
-    /**
-     * flcontext_alloc - pop a context off the stack, if required create a new one
-     *
-     * @return FloodlightContext
-     */
-    protected static FloodlightContext flcontext_alloc() {
-        FloodlightContext flcontext = null;
-
-        if (flcontext_cache.get().empty()) {
-            flcontext = new FloodlightContext();
-        } else {
-            flcontext = flcontext_cache.get().pop();
+    public synchronized void releaseRegistryControl(long dpidLong) {
+        OFChannelHandler h = connectedSwitches.get(dpidLong);
+        if (h == null) {
+            log.error("Trying to release registry control for switch {} "
+                    + "not in connected switches. Aborting.. ",
+                    HexString.toHexString(dpidLong));
+            return;
         }
-
-        return flcontext;
+        if (h.controlRequested) {
+            registryService.releaseControl(dpidLong);
+        }
     }
 
-    /**
-     * flcontext_free - Free the context to the current thread
-     *
-     * @param flcontext
-     */
-    protected void flcontext_free(FloodlightContext flcontext) {
-        flcontext.getStorage().clear();
-        flcontext_cache.get().push(flcontext);
-    }
+
+    // *******************
+    // OF Message Handling
+    // *******************
 
     /**
-     * Handle replies to certain OFMessages, and pass others off to listeners
      *
-     * @param sw       The switch for the message
-     * @param m        The message
-     * @param bContext The floodlight context. If null then floodlight context would
-     *                 be allocated in this function
+     * Handle and dispatch a message to IOFMessageListeners.
+     *
+     * We only dispatch messages to listeners if the controller's role is MASTER.
+     *
+     * @param sw The switch sending the message
+     * @param m The message the switch sent
+     * @param flContext The floodlight context to use for this message. If
+     * null, a new context will be allocated.
      * @throws IOException
+     *
+     * FIXME: this method and the ChannelHandler disagree on which messages
+     * should be dispatched and which shouldn't
      */
     @LogMessageDocs({
             @LogMessageDoc(level = "ERROR",
@@ -1210,41 +621,73 @@
                     explanation = "The switch sent a message not handled by " +
                             "the controller")
     })
-    @SuppressWarnings("fallthrough")
+    @SuppressWarnings({ "fallthrough", "unchecked" })
     protected void handleMessage(IOFSwitch sw, OFMessage m,
                                  FloodlightContext bContext)
             throws IOException {
         Ethernet eth = null;
+        short inport = -1;
 
         switch (m.getType()) {
             case PACKET_IN:
                 OFPacketIn pi = (OFPacketIn) m;
-
-                if (pi.getPacketData().length <= 0) {
+                //log.info("saw packet in from sw {}", sw.getStringId());
+                if (pi.getData().length <= 0) {
                     log.error("Ignoring PacketIn (Xid = " + pi.getXid() +
-                            ") because the data field is empty.");
+                            ") because/*  the data field is empty.");
                     return;
                 }
 
+                // get incoming port to store in floodlight context
+                if (sw.getOFVersion() == OFVersion.OF_10) {
+                    inport = pi.getInPort().getShortPortNumber();
+                } else if (sw.getOFVersion() == OFVersion.OF_13) {
+                    for (MatchField<?> mf : pi.getMatch().getMatchFields()) {
+                        if (mf.id == MatchFields.IN_PORT) {
+                            inport = pi.getMatch().get((MatchField<OFPort>)mf)
+                                        .getShortPortNumber();
+                            break;
+                        }
+                    }
+                    if (inport == -1) {
+                        log.error("Match field for incoming port missing in "
+                                + "packet-in from sw {} .. Ignoring msg",
+                                sw.getStringId());
+                        return;
+                    }
+                } else {
+                    // should have been taken care of earlier in handshake
+                    log.error("OFVersion {} not supported for "
+                            + "packet-in from sw {} .. Ignoring msg",
+                            sw.getOFVersion(), sw.getStringId());
+                    return;
+                }
+
+                // decode enclosed ethernet packet to store in floodlight context
                 if (Controller.ALWAYS_DECODE_ETH) {
                     eth = new Ethernet();
-                    eth.deserialize(pi.getPacketData(), 0,
-                            pi.getPacketData().length);
+                    eth.deserialize(pi.getData(), 0,
+                            pi.getData().length);
                 }
                 // fall through to default case...
 
+                /*log.debug("Sw:{} packet-in: {}", sw.getStringId(),
+				String.format("0x%x", eth.getEtherType()));*/
+                if (eth.getEtherType() != (short)EthType.LLDP.getValue())
+			log.trace("Sw:{} packet-in: {}", sw.getStringId(), pi);
+
             default:
 
                 List<IOFMessageListener> listeners = null;
+
                 if (messageListeners.containsKey(m.getType())) {
                     listeners = messageListeners.get(m.getType()).
                             getOrderedListeners();
                 }
-
                 FloodlightContext bc = null;
                 if (listeners != null) {
-                    // Check if floodlight context is passed from the calling 
-                    // function, if so use that floodlight context, otherwise 
+                    // Check if floodlight context is passed from the calling
+                    // function, if so use that floodlight context, otherwise
                     // allocate one
                     if (bContext == null) {
                         bc = flcontext_alloc();
@@ -1256,12 +699,17 @@
                                 IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
                                 eth);
                     }
+                    if (inport != -1) {
+                        bc.getStorage().put(
+                                IFloodlightProviderService.CONTEXT_PI_INPORT,
+                                inport);
+                    }
 
-                    // Get the starting time (overall and per-component) of 
+                    // Get the starting time (overall and per-component) of
                     // the processing chain for this packet if performance
                     // monitoring is turned on
 
-                    Command cmd;
+                    Command cmd = null;
                     for (IOFMessageListener listener : listeners) {
                         if (listener instanceof IOFSwitchFilter) {
                             if (!((IOFSwitchFilter) listener).isInterested(sw)) {
@@ -1269,10 +717,8 @@
                             }
                         }
 
-
                         cmd = listener.receive(sw, m, bc);
 
-
                         if (Command.STOP.equals(cmd)) {
                             break;
                         }
@@ -1286,194 +732,62 @@
         }
     }
 
-    /**
-     * Log an OpenFlow error message from a switch
-     *
-     * @param sw    The switch that sent the error
-     * @param error The error message
-     */
-    @LogMessageDoc(level = "ERROR",
-            message = "Error {error type} {error code} from {switch}",
-            explanation = "The switch responded with an unexpected error" +
-                    "to an OpenFlow message from the controller",
-            recommendation = "This could indicate improper network operation. " +
-                    "If the problem persists restarting the switch and " +
-                    "controller may help."
-    )
-    protected void logError(IOFSwitch sw, OFError error) {
-        int etint = 0xffff & error.getErrorType();
-        if (etint < 0 || etint >= OFErrorType.values().length) {
-            log.error("Unknown error code {} from sw {}", etint, sw);
-        }
-        OFErrorType et = OFErrorType.values()[etint];
-        switch (et) {
-            case OFPET_HELLO_FAILED:
-                OFHelloFailedCode hfc =
-                        OFHelloFailedCode.values()[0xffff & error.getErrorCode()];
-                log.error("Error {} {} from {}", new Object[]{et, hfc, sw});
-                break;
-            case OFPET_BAD_REQUEST:
-                OFBadRequestCode brc =
-                        OFBadRequestCode.values()[0xffff & error.getErrorCode()];
-                log.error("Error {} {} from {}", new Object[]{et, brc, sw});
-                break;
-            case OFPET_BAD_ACTION:
-                OFBadActionCode bac =
-                        OFBadActionCode.values()[0xffff & error.getErrorCode()];
-                log.error("Error {} {} from {}", new Object[]{et, bac, sw});
-                break;
-            case OFPET_FLOW_MOD_FAILED:
-                OFFlowModFailedCode fmfc =
-                        OFFlowModFailedCode.values()[0xffff & error.getErrorCode()];
-                log.error("Error {} {} from {}", new Object[]{et, fmfc, sw});
-                break;
-            case OFPET_PORT_MOD_FAILED:
-                OFPortModFailedCode pmfc =
-                        OFPortModFailedCode.values()[0xffff & error.getErrorCode()];
-                log.error("Error {} {} from {}", new Object[]{et, pmfc, sw});
-                break;
-            case OFPET_QUEUE_OP_FAILED:
-                OFQueueOpFailedCode qofc =
-                        OFQueueOpFailedCode.values()[0xffff & error.getErrorCode()];
-                log.error("Error {} {} from {}", new Object[]{et, qofc, sw});
-                break;
-            default:
-                break;
-        }
-    }
-
-    /**
-     * Add a switch to the active switch list and call the switch listeners.
-     * This happens either when a switch first connects (and the controller is
-     * not in the slave role) or when the role of the controller changes from
-     * slave to master.
-     *
-     * @param sw the switch that has been added
-     */
-    // TODO: need to rethink locking and the synchronous switch update.
-    //       We can / should also handle duplicate DPIDs in connectedSwitches
-    @LogMessageDoc(level = "ERROR",
-            message = "New switch added {switch} for already-added switch {switch}",
-            explanation = "A switch with the same DPID as another switch " +
-                    "connected to the controller.  This can be caused by " +
-                    "multiple switches configured with the same DPID, or " +
-                    "by a switch reconnected very quickly after " +
-                    "disconnecting.",
-            recommendation = "If this happens repeatedly, it is likely there " +
-                    "are switches with duplicate DPIDs on the network.  " +
-                    "Reconfigure the appropriate switches.  If it happens " +
-                    "very rarely, then it is likely this is a transient " +
-                    "network problem that can be ignored."
-    )
-    protected void addSwitch(IOFSwitch sw) {
-        // XXX Workaround to prevent race condition where a link is detected
-        // and attempted to be written to the database before the port is in
-        // the database. We now suppress link discovery on ports until we're
-        // sure they're in the database.
-        for (OFPhysicalPort port : sw.getPorts()) {
-            linkDiscovery.disableDiscoveryOnPort(sw.getId(), port.getPortNumber());
-        }
-
-        // TODO: is it safe to modify the HashMap without holding 
-        // the old switch's lock?
-        OFSwitchImpl oldSw = (OFSwitchImpl) 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);
-            return;
-        }
-
-        if (oldSw != null) {
-            oldSw.getListenerWriteLock().lock();
-            try {
-                log.error("New switch added {} for already-added switch {}",
-                        sw, oldSw);
-                // Set the connected flag to false to suppress calling
-                // the listeners for this switch in processOFMessage
-                oldSw.setConnected(false);
-
-                oldSw.cancelAllStatisticsReplies();
-
-                //updateInactiveSwitchInfo(oldSw);
-
-                // we need to clean out old switch state definitively 
-                // before adding the new switch
-                // FIXME: It seems not completely kosher to call the
-                // switch listeners here. I thought one of the points of
-                // having the asynchronous switch update mechanism was so
-                // the addedSwitch and removedSwitch were always called
-                // from a single thread to simplify concurrency issues
-                // for the listener.
-                if (switchListeners != null) {
-                    for (IOFSwitchListener listener : switchListeners) {
-                        listener.removedSwitch(oldSw);
-                    }
-                }
-                // will eventually trigger a removeSwitch(), which will cause
-                // a "Not removing Switch ... already removed debug message.
-                // TODO: Figure out a way to handle this that avoids the
-                // spurious debug message.
-                log.debug("Closing {} because a new IOFSwitch got added " +
-                        "for this dpid", oldSw);
-                oldSw.getChannel().close();
-            } finally {
-                oldSw.getListenerWriteLock().unlock();
-            }
-        }
-
-        //updateActiveSwitchInfo(sw);
-        SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.ADDED);
-        try {
-            this.updates.put(update);
-        } catch (InterruptedException e) {
-            log.error("Failure adding update to queue", e);
-        }
-    }
-
-    /**
-     * Remove a switch from the active switch list and call the switch listeners.
-     * This happens either when the switch is disconnected or when the
-     * controller's role for the switch changes from master to slave.
-     *
-     * @param sw the switch that has been removed
-     */
-    protected void removeSwitch(IOFSwitch sw) {
-        // No need to acquire the listener lock, since
-        // this method is only called after netty has processed all
-        // pending messages
-        log.debug("removeSwitch: {}", sw);
-        if (!this.activeSwitches.remove(sw.getId(), sw) || !sw.isConnected()) {
-            log.debug("Not removing switch {}; already removed", sw);
-            return;
-        }
-        // We cancel all outstanding statistics replies if the switch transition
-        // from active. In the future we might allow statistics requests 
-        // from slave controllers. Then we need to move this cancelation
-        // to switch disconnect
-        sw.cancelAllStatisticsReplies();
-
-        // FIXME: I think there's a race condition if we call updateInactiveSwitchInfo
-        // here if role support is enabled. In that case if the switch is being
-        // removed because we've been switched to being in the slave role, then I think
-        // it's possible that the new master may have already been promoted to master
-        // and written out the active switch state to storage. If we now execute
-        // updateInactiveSwitchInfo we may wipe out all of the state that was
-        // written out by the new master. Maybe need to revisit how we handle all
-        // of the switch state that's written to storage.
-
-        //updateInactiveSwitchInfo(sw);
-        SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.REMOVED);
-        try {
-            this.updates.put(update);
-        } catch (InterruptedException e) {
-            log.error("Failure adding update to queue", e);
-        }
-    }
-
     // ***************
-    // IFloodlightProvider
+    // IFloodlightProviderService
     // ***************
 
+    // FIXME: remove this method
+    @Override
+    public Map<Long,IOFSwitch> getSwitches() {
+        return getMasterSwitches();
+    }
+
+    // FIXME: remove this method
+    public Map<Long, IOFSwitch> getMasterSwitches() {
+        return Collections.unmodifiableMap(activeMasterSwitches);
+    }
+
+
+    @Override
+    public Set<Long> getAllSwitchDpids() {
+        Set<Long> dpids = new HashSet<Long>();
+        dpids.addAll(activeMasterSwitches.keySet());
+        dpids.addAll(activeEqualSwitches.keySet());
+        return dpids;
+    }
+
+    @Override
+    public Set<Long> getAllMasterSwitchDpids() {
+        Set<Long> dpids = new HashSet<Long>();
+        dpids.addAll(activeMasterSwitches.keySet());
+        return dpids;
+    }
+
+    @Override
+    public Set<Long> getAllEqualSwitchDpids() {
+        Set<Long> dpids = new HashSet<Long>();
+        dpids.addAll(activeEqualSwitches.keySet());
+        return dpids;
+    }
+
+    @Override
+    public IOFSwitch getSwitch(long dpid) {
+        IOFSwitch sw = null;
+        if ((sw = activeMasterSwitches.get(dpid)) != null) return sw;
+        if ((sw = activeEqualSwitches.get(dpid)) != null) return sw;
+        return sw;
+    }
+
+    @Override
+    public IOFSwitch getMasterSwitch(long dpid) {
+        return  activeMasterSwitches.get(dpid);
+    }
+
+    @Override
+    public IOFSwitch getEqualSwitch(long dpid) {
+        return  activeEqualSwitches.get(dpid);
+    }
+
     @Override
     public synchronized void addOFMessageListener(OFType type,
                                                   IOFMessageListener listener) {
@@ -1496,6 +810,10 @@
         }
     }
 
+    public void removeOFMessageListeners(OFType type) {
+        messageListeners.remove(type);
+    }
+
     private void logListeners() {
         for (Map.Entry<OFType,
                 ListenerDispatcher<OFType,
@@ -1507,7 +825,7 @@
                     entry.getValue();
 
             StringBuffer sb = new StringBuffer();
-            sb.append("OFListeners for ");
+            sb.append("OFMessageListeners for ");
             sb.append(type);
             sb.append(": ");
             for (IOFMessageListener l : ldd.getOrderedListeners()) {
@@ -1516,15 +834,14 @@
             }
             log.debug(sb.toString());
         }
-    }
+        StringBuffer sl = new StringBuffer();
+        sl.append("SwitchUpdate Listeners: ");
+        for (IOFSwitchListener swlistener : switchListeners) {
+            sl.append(swlistener.getName());
+            sl.append(",");
+        }
+        log.debug(sl.toString());
 
-    public void removeOFMessageListeners(OFType type) {
-        messageListeners.remove(type);
-    }
-
-    @Override
-    public Map<Long, IOFSwitch> getSwitches() {
-        return Collections.unmodifiableMap(this.activeSwitches);
     }
 
     @Override
@@ -1548,19 +865,7 @@
         return Collections.unmodifiableMap(lers);
     }
 
-    @Override
-    public void addLocalSwitchMastershipListener(
-                ILocalSwitchMastershipListener listener) {
-        this.localSwitchMastershipListeners.addIfAbsent(listener);
-    }
-
-    @Override
-    public void removeLocalSwitchMastershipListener(
-                ILocalSwitchMastershipListener listener) {
-        this.localSwitchMastershipListeners.remove(listener);
-    }
-
-    @Override
+    /*@Override
     @LogMessageDocs({
             @LogMessageDoc(message = "Failed to inject OFMessage {message} onto " +
                     "a null switch",
@@ -1587,7 +892,7 @@
         // discussions it sounds like the right thing to do here would be to
         // inject the message as a netty upstream channel event so it goes
         // through the normal netty event processing, including being
-        // handled 
+        // handled
         if (!activeSwitches.containsKey(sw.getId())) return false;
 
         try {
@@ -1599,53 +904,79 @@
             return false;
         }
         return true;
+    }*/
+
+
+
+//    @Override
+//    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) {
+//        // call the overloaded version with floodlight context set to null
+//        return injectOfMessage(sw, msg, null);
+//    }
+
+//    @Override
+//    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
+//                                      FloodlightContext bc) {
+//
+//        List<IOFMessageListener> listeners = null;
+//        if (messageListeners.containsKey(m.getType())) {
+//            listeners =
+//                    messageListeners.get(m.getType()).getOrderedListeners();
+//        }
+//
+//        if (listeners != null) {
+//            for (IOFMessageListener listener : listeners) {
+//                if (listener instanceof IOFSwitchFilter) {
+//                    if (!((IOFSwitchFilter) listener).isInterested(sw)) {
+//                        continue;
+//                    }
+//                }
+//                if (Command.STOP.equals(listener.receive(sw, m, bc))) {
+//                    break;
+//                }
+//            }
+//        }
+//    }
+
+    @Override
+    public OFFactory getOFMessageFactory_10() {
+        return factory10;
     }
 
     @Override
-    @LogMessageDoc(message = "Calling System.exit",
-            explanation = "The controller is terminating")
-    public synchronized void terminate() {
-        log.info("Calling System.exit");
-        System.exit(1);
+    public OFFactory getOFMessageFactory_13() {
+        return factory13;
     }
 
     @Override
-    public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) {
-        // call the overloaded version with floodlight context set to null    
-        return injectOfMessage(sw, msg, null);
-    }
-
-    @Override
-    public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
-                                      FloodlightContext bc) {
-        if (log.isTraceEnabled()) {
-            String str = OFMessage.getDataAsString(sw, m, bc);
-            log.trace("{}", str);
-        }
-
-        List<IOFMessageListener> listeners = null;
-        if (messageListeners.containsKey(m.getType())) {
-            listeners =
-                    messageListeners.get(m.getType()).getOrderedListeners();
-        }
-
-        if (listeners != null) {
-            for (IOFMessageListener listener : listeners) {
-                if (listener instanceof IOFSwitchFilter) {
-                    if (!((IOFSwitchFilter) listener).isInterested(sw)) {
-                        continue;
-                    }
-                }
-                if (Command.STOP.equals(listener.receive(sw, m, bc))) {
-                    break;
-                }
-            }
+    public void publishUpdate(IUpdate update) {
+        try {
+            this.updates.put(update);
+        } catch (InterruptedException e) {
+            log.error("Failure adding update to queue", e);
         }
     }
 
     @Override
-    public BasicFactory getOFMessageFactory() {
-        return factory;
+    public Map<String, String> getControllerNodeIPs() {
+        // We return a copy of the mapping so we can guarantee that
+        // the mapping return is the same as one that will be (or was)
+        // dispatched to IHAListeners
+        HashMap<String, String> retval = new HashMap<String, String>();
+        synchronized (controllerNodeIPsCache) {
+            retval.putAll(controllerNodeIPsCache);
+        }
+        return retval;
+    }
+
+    @Override
+    public long getSystemStartTime() {
+        return (this.systemStartTime);
+    }
+
+    @Override
+    public void setAlwaysClearFlowsOnSwAdd(boolean value) {
+        this.alwaysClearFlowsOnSwAdd = value;
     }
 
     @Override
@@ -1653,10 +984,26 @@
         return onosInstanceId;
     }
 
+    /**
+     * FOR TESTING ONLY. Dispatch all updates in the update queue until queue is
+     * empty
+     */
+    void processUpdateQueueForTesting() {
+        while (!updates.isEmpty()) {
+            IUpdate update = updates.poll();
+            if (update != null)
+                update.dispatch();
+        }
+    }
+
+
     // **************
     // Initialization
     // **************
 
+    // XXX S This should probably go away OR it should be edited to handle
+    // controller roles per switch! Then it could be a way to
+    // deterministically configure a switch to a MASTER controller instance
     /**
      * Sets the initial role based on properties in the config params.
      * It looks for two different properties.
@@ -1737,6 +1084,7 @@
      *
      * @throws IOException
      */
+    @Override
     @LogMessageDocs({
             @LogMessageDoc(message = "Listening for switch connections on {address}",
                     explanation = "The controller is ready and listening for new" +
@@ -1781,7 +1129,9 @@
                 IUpdate update = updates.take();
                 update.dispatch();
             } catch (InterruptedException e) {
-                return;
+                log.error("Received interrupted exception in updates loop;" +
+                          "terminating process");
+                terminate();
             } catch (Exception e) {
                 log.error("Exception in controller updates loop", e);
             }
@@ -1829,23 +1179,6 @@
         log.debug("ControllerId set to {}", this.onosInstanceId);
     }
 
-    private void initVendorMessages() {
-        // Configure openflowj to be able to parse the role request/reply
-        // vendor messages.
-        OFBasicVendorId niciraVendorId = new OFBasicVendorId(
-                OFNiciraVendorData.NX_VENDOR_ID, 4);
-        OFVendorId.registerVendorId(niciraVendorId);
-        OFBasicVendorDataType roleRequestVendorData =
-                new OFBasicVendorDataType(
-                        OFRoleRequestVendorData.NXT_ROLE_REQUEST,
-                        OFRoleRequestVendorData.getInstantiable());
-        niciraVendorId.registerVendorDataType(roleRequestVendorData);
-        OFBasicVendorDataType roleReplyVendorData =
-                new OFBasicVendorDataType(
-                        OFRoleReplyVendorData.NXT_ROLE_REPLY,
-                        OFRoleReplyVendorData.getInstantiable());
-        niciraVendorId.registerVendorDataType(roleReplyVendorData);
-    }
 
     /**
      * Initialize internal data structures
@@ -1854,32 +1187,40 @@
         // These data structures are initialized here because other
         // module's startUp() might be called before ours
         this.messageListeners =
-                new ConcurrentHashMap<OFType,
-                        ListenerDispatcher<OFType,
-                                IOFMessageListener>>();
+                new ConcurrentHashMap<OFType, ListenerDispatcher<OFType,
+                                                    IOFMessageListener>>();
         this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
-        this.activeSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
-        this.connectedSwitches = new HashSet<OFSwitchImpl>();
+        this.activeMasterSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
+        this.activeEqualSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
+        this.connectedSwitches = new ConcurrentHashMap<Long, OFChannelHandler>();
         this.controllerNodeIPsCache = new HashMap<String, String>();
         this.updates = new LinkedBlockingQueue<IUpdate>();
-        this.factory = new BasicFactory();
+
         setConfigParams(configParams);
-        //Set the controller's role to MASTER so it always tries to do role requests.
-        this.role = Role.MASTER;
-        this.roleChanger = new RoleChanger();
-        initVendorMessages();
         this.systemStartTime = System.currentTimeMillis();
+        this.counters = new Counters();
+        this.multiCacheLock = new Object();
+
+        String option = configParams.get("flushSwitchesOnReconnect");
+        if (option != null && option.equalsIgnoreCase("true")) {
+            this.setAlwaysClearFlowsOnSwActivate(true);
+            log.info("Flush switches on reconnect -- Enabled.");
+        } else {
+            this.setAlwaysClearFlowsOnSwActivate(false);
+            log.info("Flush switches on reconnect -- Disabled");
+        }
     }
 
     /**
      * Startup all of the controller's components
+     * @throws FloodlightModuleException
      */
     @LogMessageDoc(message = "Waiting for storage source",
             explanation = "The system database is not yet ready",
             recommendation = "If this message persists, this indicates " +
                     "that the system database has failed to start. " +
                     LogMessageDoc.CHECK_CONTROLLER)
-    public void startupComponents() {
+    public void startupComponents() throws FloodlightModuleException {
         try {
             registryService.registerController(onosInstanceId.toString());
         } catch (RegistryException e) {
@@ -1888,31 +1229,626 @@
 
         // Add our REST API
         restApi.addRestletRoutable(new CoreWebRoutable());
-    }
 
-    @Override
-    public Map<String, String> getControllerNodeIPs() {
-        // We return a copy of the mapping so we can guarantee that
-        // the mapping return is the same as one that will be (or was)
-        // dispatched to IHAListeners
-        HashMap<String, String> retval = new HashMap<String, String>();
-        synchronized (controllerNodeIPsCache) {
-            retval.putAll(controllerNodeIPsCache);
+        // Startup load monitoring
+        if (overload_drop) {
+            this.loadmonitor.startMonitoring(
+                this.threadPool.getScheduledExecutor());
         }
-        return retval;
+
+        // register counters and events
+        try {
+            this.counters.createCounters(debugCounters);
+        } catch (CounterException e) {
+            throw new FloodlightModuleException(e.getMessage());
+        }
+        registerControllerDebugEvents();
+    }
+
+    // **************
+    // debugCounter registrations
+    // **************
+
+    public static class Counters {
+        public static final String prefix = "controller";
+        public IDebugCounter setRoleEqual;
+        public IDebugCounter setSameRole;
+        public IDebugCounter setRoleMaster;
+        public IDebugCounter remoteStoreNotification;
+        public IDebugCounter invalidPortsChanged;
+        public IDebugCounter invalidSwitchActivatedWhileSlave;
+        public IDebugCounter invalidStoreEventWhileMaster;
+        public IDebugCounter switchDisconnectedWhileSlave;
+        public IDebugCounter switchActivated;
+        public IDebugCounter errorSameSwitchReactivated; // err
+        public IDebugCounter switchWithSameDpidActivated; // warn
+        public IDebugCounter newSwitchActivated;   // new switch
+        public IDebugCounter syncedSwitchActivated;
+        public IDebugCounter readyForReconcile;
+        public IDebugCounter newSwitchFromStore;
+        public IDebugCounter updatedSwitchFromStore;
+        public IDebugCounter switchDisconnected;
+        public IDebugCounter syncedSwitchRemoved;
+        public IDebugCounter unknownSwitchRemovedFromStore;
+        public IDebugCounter consolidateStoreRunCount;
+        public IDebugCounter consolidateStoreInconsistencies;
+        public IDebugCounter storeSyncError;
+        public IDebugCounter switchesNotReconnectingToNewMaster;
+        public IDebugCounter switchPortChanged;
+        public IDebugCounter switchOtherChange;
+        public IDebugCounter dispatchMessageWhileSlave;
+        public IDebugCounter dispatchMessage;  // does this cnt make sense? more specific?? per type? count stops?
+        public IDebugCounter controllerNodeIpsChanged;
+        public IDebugCounter messageReceived;
+        public IDebugCounter messageInputThrottled;
+        public IDebugCounter switchDisconnectReadTimeout;
+        public IDebugCounter switchDisconnectHandshakeTimeout;
+        public IDebugCounter switchDisconnectIOError;
+        public IDebugCounter switchDisconnectParseError;
+        public IDebugCounter switchDisconnectSwitchStateException;
+        public IDebugCounter rejectedExecutionException;
+        public IDebugCounter switchDisconnectOtherException;
+        public IDebugCounter switchConnected;
+        public IDebugCounter unhandledMessage;
+        public IDebugCounter packetInWhileSwitchIsSlave;
+        public IDebugCounter epermErrorWhileSwitchIsMaster;
+        public IDebugCounter roleNotResentBecauseRolePending;
+        public IDebugCounter roleRequestSent;
+        public IDebugCounter roleReplyTimeout;
+        public IDebugCounter roleReplyReceived; // expected RoleReply received
+        public IDebugCounter roleReplyErrorUnsupported;
+        public IDebugCounter switchCounterRegistrationFailed;
+        public IDebugCounter packetParsingError;
+
+        void createCounters(IDebugCounterService debugCounters) throws CounterException {
+            setRoleEqual =
+                debugCounters.registerCounter(
+                            prefix, "set-role-equal",
+                            "Controller received a role request with role of "+
+                            "EQUAL which is unusual",
+                            CounterType.ALWAYS_COUNT);
+            setSameRole =
+                debugCounters.registerCounter(
+                            prefix, "set-same-role",
+                            "Controller received a role request for the same " +
+                            "role the controller already had",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            setRoleMaster =
+                debugCounters.registerCounter(
+                            prefix, "set-role-master",
+                            "Controller received a role request with role of " +
+                            "MASTER. This counter can be at most 1.",
+                            CounterType.ALWAYS_COUNT);
+
+            remoteStoreNotification =
+                debugCounters.registerCounter(
+                            prefix, "remote-store-notification",
+                            "Received a notification from the sync service " +
+                            "indicating that switch information has changed",
+                            CounterType.ALWAYS_COUNT);
+
+            invalidPortsChanged =
+                debugCounters.registerCounter(
+                            prefix, "invalid-ports-changed",
+                            "Received an unexpected ports changed " +
+                            "notification while the controller was in " +
+                            "SLAVE role.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            invalidSwitchActivatedWhileSlave =
+                debugCounters.registerCounter(
+                            prefix, "invalid-switch-activated-while-slave",
+                            "Received an unexpected switchActivated " +
+                            "notification while the controller was in " +
+                            "SLAVE role.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            invalidStoreEventWhileMaster =
+                debugCounters.registerCounter(
+                            prefix, "invalid-store-event-while-master",
+                            "Received an unexpected notification from " +
+                            "the sync store while the controller was in " +
+                            "MASTER role.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            switchDisconnectedWhileSlave =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnected-while-slave",
+                            "A switch disconnected and the controller was " +
+                            "in SLAVE role.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            switchActivated =
+                debugCounters.registerCounter(
+                            prefix, "switch-activated",
+                            "A switch connected to this controller is now " +
+                            "in MASTER role",
+                            CounterType.ALWAYS_COUNT);
+
+            errorSameSwitchReactivated = // err
+                debugCounters.registerCounter(
+                            prefix, "error-same-switch-reactivated",
+                            "A switch that was already in active state " +
+                            "was activated again. This indicates a " +
+                            "controller defect",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchWithSameDpidActivated = // warn
+                debugCounters.registerCounter(
+                            prefix, "switch-with-same-dpid-activated",
+                            "A switch with the same DPID as another switch " +
+                            "connected to the controller. This can be " +
+                            "caused by multiple switches configured with " +
+                            "the same DPID or by a switch reconnecting very " +
+                            "quickly.",
+                            CounterType.COUNT_ON_DEMAND,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            newSwitchActivated =   // new switch
+                debugCounters.registerCounter(
+                            prefix, "new-switch-activated",
+                            "A new switch has completed the handshake as " +
+                            "MASTER. The switch was not known to any other " +
+                            "controller in the cluster",
+                            CounterType.ALWAYS_COUNT);
+            syncedSwitchActivated =
+                debugCounters.registerCounter(
+                            prefix, "synced-switch-activated",
+                            "A switch has completed the handshake as " +
+                            "MASTER. The switch was known to another " +
+                            "controller in the cluster",
+                            CounterType.ALWAYS_COUNT);
+
+            readyForReconcile =
+                debugCounters.registerCounter(
+                            prefix, "ready-for-reconcile",
+                            "Controller is ready for flow reconciliation " +
+                            "after Slave to Master transition. Either all " +
+                            "previously known switches are now active " +
+                            "or they have timed out and have been removed." +
+                            "This counter will be 0 or 1.",
+                            CounterType.ALWAYS_COUNT);
+
+            newSwitchFromStore =
+                debugCounters.registerCounter(
+                            prefix, "new-switch-from-store",
+                            "A new switch has connected to another " +
+                            "another controller in the cluster. This " +
+                            "controller instance has received a sync store " +
+                            "notification for it.",
+                            CounterType.ALWAYS_COUNT);
+
+            updatedSwitchFromStore =
+                debugCounters.registerCounter(
+                            prefix, "updated-switch-from-store",
+                            "Information about a switch connected to " +
+                            "another controller instance was updated in " +
+                            "the sync store. This controller instance has " +
+                            "received a notification for it",
+                            CounterType.ALWAYS_COUNT);
+
+            switchDisconnected =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnected",
+                            "FIXME: switch has disconnected",
+                            CounterType.ALWAYS_COUNT);
+
+            syncedSwitchRemoved =
+                debugCounters.registerCounter(
+                            prefix, "synced-switch-removed",
+                            "A switch connected to another controller " +
+                            "instance has disconnected from the controller " +
+                            "cluster. This controller instance has " +
+                            "received a notification for it",
+                            CounterType.ALWAYS_COUNT);
+
+            unknownSwitchRemovedFromStore =
+                debugCounters.registerCounter(
+                            prefix, "unknown-switch-removed-from-store",
+                            "This controller instances has received a sync " +
+                            "store notification that a switch has " +
+                            "disconnected but this controller instance " +
+                            "did not have the any information about the " +
+                            "switch", // might be less than warning
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            consolidateStoreRunCount =
+                debugCounters.registerCounter(
+                            prefix, "consolidate-store-run-count",
+                            "This controller has transitioned from SLAVE " +
+                            "to MASTER and waited for switches to reconnect. " +
+                            "The controller has finished waiting and has " +
+                            "reconciled switch entries in the sync store " +
+                            "with live state",
+                            CounterType.ALWAYS_COUNT);
+
+            consolidateStoreInconsistencies =
+                    debugCounters.registerCounter(
+                                prefix, "consolidate-store-inconsistencies",
+                                "During switch sync store consolidation: " +
+                                "Number of switches that were in the store " +
+                                "but not otherwise known plus number of " +
+                                "switches that were in the store previously " +
+                                "but are now missing plus number of "  +
+                                "connected switches that were absent from " +
+                                "the store although this controller has " +
+                                "written them. A non-zero count " +
+                                "indicates a brief split-brain dual MASTER " +
+                                "situation during fail-over",
+                                CounterType.ALWAYS_COUNT);
+
+            storeSyncError =
+                debugCounters.registerCounter(
+                            prefix, "store-sync-error",
+                            "Number of times a sync store operation failed " +
+                            "due to a store sync exception or an entry in " +
+                            "in the store had invalid data.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchesNotReconnectingToNewMaster =
+                debugCounters.registerCounter(
+                            prefix, "switches-not-reconnecting-to-new-master",
+                            "Switches that were connected to another " +
+                            "controller instance in the cluster but that " +
+                            "did not reconnect to this controller after it " +
+                            "transitioned to MASTER", // might be less than warning
+                            CounterType.ALWAYS_COUNT);
+
+            switchPortChanged =
+                debugCounters.registerCounter(
+                            prefix, "switch-port-changed",
+                            "Number of times switch ports have changed",
+                            CounterType.ALWAYS_COUNT);
+            switchOtherChange =
+                debugCounters.registerCounter(
+                            prefix, "switch-other-change",
+                            "Number of times other information of a switch " +
+                            "has changed.",
+                            CounterType.ALWAYS_COUNT);
+
+            dispatchMessageWhileSlave =
+                debugCounters.registerCounter(
+                            prefix, "dispatch-message-while-slave",
+                            "Number of times an OF message was received " +
+                            "and supposed to be dispatched but the " +
+                            "controller was in SLAVE role and the message " +
+                            "was not dispatched",
+                            CounterType.ALWAYS_COUNT);
+
+            dispatchMessage =  // does this cnt make sense? more specific?? per type? count stops?
+                debugCounters.registerCounter(
+                            prefix, "dispatch-message",
+                            "Number of times an OF message was dispatched " +
+                            "to registered modules",
+                            CounterType.ALWAYS_COUNT);
+
+            controllerNodeIpsChanged =
+                debugCounters.registerCounter(
+                            prefix, "controller-nodes-ips-changed",
+                            "IP addresses of controller nodes have changed",
+                            CounterType.ALWAYS_COUNT);
+
+        //------------------------
+        // channel handler counters. Factor them out ??
+            messageReceived =
+                debugCounters.registerCounter(
+                            prefix, "message-received",
+                            "Number of OpenFlow messages received. Some of " +
+                            "these might be throttled",
+                            CounterType.ALWAYS_COUNT);
+            messageInputThrottled =
+                debugCounters.registerCounter(
+                            prefix, "message-input-throttled",
+                            "Number of OpenFlow messages that were " +
+                            "throttled due to high load from the sender",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+        // TODO: more counters in messageReceived ??
+
+            switchDisconnectReadTimeout =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-read-timeout",
+                            "Number of times a switch was disconnected due " +
+                            "due the switch failing to send OpenFlow " +
+                            "messages or responding to OpenFlow ECHOs",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+            switchDisconnectHandshakeTimeout =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-handshake-timeout",
+                            "Number of times a switch was disconnected " +
+                            "because it failed to complete the handshake " +
+                            "in time.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+            switchDisconnectIOError =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-io-error",
+                            "Number of times a switch was disconnected " +
+                            "due to IO errors on the switch connection.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+            switchDisconnectParseError =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-parse-error",
+                           "Number of times a switch was disconnected " +
+                           "because it sent an invalid packet that could " +
+                           "not be parsed",
+                           CounterType.ALWAYS_COUNT,
+                           IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchDisconnectSwitchStateException =
+                debugCounters.registerCounter(
+                            prefix, "switch-disconnect-switch-state-exception",
+                            "Number of times a switch was disconnected " +
+                            "because it sent messages that were invalid " +
+                            "given the switch connection's state.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+            rejectedExecutionException =
+                debugCounters.registerCounter(
+                            prefix, "rejected-execution-exception",
+                            "TODO",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchDisconnectOtherException =
+                debugCounters.registerCounter(
+                            prefix,  "switch-disconnect-other-exception",
+                            "Number of times a switch was disconnected " +
+                            "due to an exceptional situation not covered " +
+                            "by other counters",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_ERROR);
+
+            switchConnected =
+                debugCounters.registerCounter(
+                            prefix, "switch-connected",
+                            "Number of times a new switch connection was " +
+                            "established",
+                            CounterType.ALWAYS_COUNT);
+
+            unhandledMessage =
+                debugCounters.registerCounter(
+                            prefix, "unhandled-message",
+                            "Number of times an OpenFlow message was " +
+                            "received that the controller ignored because " +
+                            "it was inapproriate given the switch " +
+                            "connection's state.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+                            // might be less than warning
+
+            packetInWhileSwitchIsSlave =
+                debugCounters.registerCounter(
+                            prefix, "packet-in-while-switch-is-slave",
+                            "Number of times a packet in was received " +
+                            "from a switch that was in SLAVE role. " +
+                            "Possibly inidicates inconsistent roles.",
+                            CounterType.ALWAYS_COUNT);
+            epermErrorWhileSwitchIsMaster =
+                debugCounters.registerCounter(
+                            prefix, "eperm-error-while-switch-is-master",
+                            "Number of times a permission error was " +
+                            "received while the switch was in MASTER role. " +
+                            "Possibly inidicates inconsistent roles.",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            roleNotResentBecauseRolePending =
+                debugCounters.registerCounter(
+                            prefix, "role-not-resent-because-role-pending",
+                            "The controller tried to reestablish a role " +
+                            "with a switch but did not do so because a " +
+                            "previous role request was still pending",
+                            CounterType.ALWAYS_COUNT);
+            roleRequestSent =
+                debugCounters.registerCounter(
+                            prefix, "role-request-sent",
+                            "Number of times the controller sent a role " +
+                            "request to a switch.",
+                            CounterType.ALWAYS_COUNT);
+            roleReplyTimeout =
+                debugCounters.registerCounter(
+                            prefix, "role-reply-timeout",
+                            "Number of times a role request message did not " +
+                            "receive the expected reply from a switch",
+                            CounterType.ALWAYS_COUNT,
+                            IDebugCounterService.CTR_MDATA_WARN);
+
+            roleReplyReceived = // expected RoleReply received
+                debugCounters.registerCounter(
+                            prefix, "role-reply-received",
+                            "Number of times the controller received the " +
+                            "expected role reply message from a switch",
+                            CounterType.ALWAYS_COUNT);
+
+            roleReplyErrorUnsupported =
+                debugCounters.registerCounter(
+                            prefix, "role-reply-error-unsupported",
+                            "Number of times the controller received an " +
+                            "error from a switch in response to a role " +
+                            "request indicating that the switch does not " +
+                            "support roles.",
+                            CounterType.ALWAYS_COUNT);
+
+            switchCounterRegistrationFailed =
+                    debugCounters.registerCounter(prefix,
+                                "switch-counter-registration-failed",
+                                "Number of times the controller failed to " +
+                                "register per-switch debug counters",
+                                CounterType.ALWAYS_COUNT,
+                                IDebugCounterService.CTR_MDATA_WARN);
+
+            packetParsingError =
+                    debugCounters.registerCounter(prefix,
+                                "packet-parsing-error",
+                                "Number of times the packet parsing " +
+                                "encountered an error",
+                                CounterType.ALWAYS_COUNT,
+                                IDebugCounterService.CTR_MDATA_ERROR);
+        }
     }
 
     @Override
-    public long getSystemStartTime() {
-        return (this.systemStartTime);
+    public Counters getCounters() {
+        return this.counters;
+    }
+
+    // **************
+    // debugEvent registrations
+    // **************
+
+    private void registerControllerDebugEvents() throws FloodlightModuleException {
+        if (debugEvents == null) {
+            debugEvents = new NullDebugEvent();
+        }
+        try {
+            evSwitch = debugEvents.registerEvent(
+                               Counters.prefix, "switchevent",
+                               "Switch connected, disconnected or port changed",
+                               EventType.ALWAYS_LOG, SwitchEvent.class, 100);
+        } catch (MaxEventsRegistered e) {
+            throw new FloodlightModuleException("Max events registered", e);
+        }
+    }
+
+    public class SwitchEvent {
+        @EventColumn(name = "dpid", description = EventFieldType.DPID)
+        long dpid;
+
+        @EventColumn(name = "reason", description = EventFieldType.STRING)
+        String reason;
+
+        public SwitchEvent(long dpid, String reason) {
+            this.dpid = dpid;
+            this.reason = reason;
+        }
+    }
+
+    // **************
+    // Utility methods
+    // **************
+
+    @Override
+    public void setAlwaysClearFlowsOnSwActivate(boolean value) {
+        //this.alwaysClearFlowsOnSwActivate = value;
+        // XXX S need to be a little more careful about this
     }
 
     @Override
-    public void setAlwaysClearFlowsOnSwAdd(boolean value) {
-        this.alwaysClearFlowsOnSwAdd = value;
+    public Map<String, Long> getMemory() {
+        Map<String, Long> m = new HashMap<String, Long>();
+        Runtime runtime = Runtime.getRuntime();
+        m.put("total", runtime.totalMemory());
+        m.put("free", runtime.freeMemory());
+        return m;
     }
 
-    public boolean getAlwaysClearFlowsOnSwAdd() {
-        return this.alwaysClearFlowsOnSwAdd;
+    @Override
+    public Long getUptime() {
+        RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
+        return rb.getUptime();
     }
+
+    /**
+     * Forward to the driver-manager to get an IOFSwitch instance.
+     * @param desc
+     * @return
+     */
+    protected IOFSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
+        return DriverManager.getOFSwitchImpl(desc, ofv);
+    }
+
+    protected IThreadPoolService getThreadPoolService() {
+        return this.threadPool;
+    }
+
+    /**
+     * Part of the controller updates framework (see 'run()' method)
+     * Use this method to add an IUpdate. A thread-pool will serve the update
+     * by dispatching it to all listeners for that update.
+     * @param update
+     */
+    @LogMessageDoc(level="WARN",
+            message="Failure adding update {} to queue",
+            explanation="The controller tried to add an internal notification" +
+                        " to its message queue but the add failed.",
+            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+    private void addUpdateToQueue(IUpdate update) {
+        try {
+            this.updates.put(update);
+        } catch (InterruptedException e) {
+            // This should never happen
+            log.error("Failure adding update {} to queue.", update);
+        }
+    }
+
+    void flushAll() {
+        // Flush all flow-mods/packet-out/stats generated from this "train"
+        OFSwitchImplBase.flush_all();
+        debugCounters.flushCounters();
+        debugEvents.flushEvents();
+    }
+
+    /**
+     * flcontext_free - Free the context to the current thread
+     *
+     * @param flcontext
+     */
+    protected void flcontext_free(FloodlightContext flcontext) {
+        flcontext.getStorage().clear();
+        flcontext_cache.get().push(flcontext);
+    }
+
+    @LogMessageDoc(message = "Calling System.exit",
+            explanation = "The controller is terminating")
+    private synchronized void terminate() {
+        log.info("Calling System.exit");
+        System.exit(1);
+    }
+
+
+    // ***************
+    // Floodlight context related
+    // ***************
+
+    /**
+     * flcontext_cache - Keep a thread local stack of contexts
+     */
+    protected static final ThreadLocal<Stack<FloodlightContext>> flcontext_cache =
+            new ThreadLocal<Stack<FloodlightContext>>() {
+                @Override
+                protected Stack<FloodlightContext> initialValue() {
+                    return new Stack<FloodlightContext>();
+                }
+            };
+
+    /**
+     * flcontext_alloc - pop a context off the stack, if required create a new one
+     *
+     * @return FloodlightContext
+     */
+    protected static FloodlightContext flcontext_alloc() {
+        FloodlightContext flcontext = null;
+
+        if (flcontext_cache.get().empty()) {
+            flcontext = new FloodlightContext();
+        } else {
+            flcontext = flcontext_cache.get().pop();
+        }
+
+        return flcontext;
+    }
+
+
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java b/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
index d5950b4..c9aa3ca 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/HandshakeTimeoutHandler.java
@@ -1,31 +1,28 @@
 /**
- *    Copyright 2011, Big Switch Networks, Inc.
- *    Originally created by David Erickson, Stanford University
- *
- *    Licensed under the Apache License, Version 2.0 (the "License"); you may
- *    not use this file except in compliance with the License. You may obtain
- *    a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- *    License for the specific language governing permissions and limitations
- *    under the License.
- **/
+*    Copyright 2011, Big Switch Networks, Inc.
+*    Originally created by David Erickson, Stanford University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
 
 package net.floodlightcontroller.core.internal;
 
 import java.util.concurrent.TimeUnit;
 
-import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState;
-
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.ChannelStateEvent;
 import org.jboss.netty.channel.Channels;
 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
-import org.jboss.netty.util.ExternalResourceReleasable;
 import org.jboss.netty.util.Timeout;
 import org.jboss.netty.util.Timer;
 import org.jboss.netty.util.TimerTask;
@@ -34,20 +31,20 @@
  * Trigger a timeout if a switch fails to complete handshake soon enough
  */
 public class HandshakeTimeoutHandler
-        extends SimpleChannelUpstreamHandler
-        implements ExternalResourceReleasable {
+    extends SimpleChannelUpstreamHandler {
     static final HandshakeTimeoutException EXCEPTION =
             new HandshakeTimeoutException();
 
-    final OFChannelState state;
+    final OFChannelHandler channelHandler;
     final Timer timer;
     final long timeoutNanos;
     volatile Timeout timeout;
 
-    public HandshakeTimeoutHandler(OFChannelState state, Timer timer,
+    public HandshakeTimeoutHandler(OFChannelHandler channelHandler,
+                                   Timer timer,
                                    long timeoutSeconds) {
         super();
-        this.state = state;
+        this.channelHandler = channelHandler;
         this.timer = timer;
         this.timeoutNanos = TimeUnit.SECONDS.toNanos(timeoutSeconds);
 
@@ -58,7 +55,7 @@
             throws Exception {
         if (timeoutNanos > 0) {
             timeout = timer.newTimeout(new HandshakeTimeoutTask(ctx),
-                    timeoutNanos, TimeUnit.NANOSECONDS);
+                                       timeoutNanos, TimeUnit.NANOSECONDS);
         }
         ctx.sendUpstream(e);
     }
@@ -72,11 +69,6 @@
         }
     }
 
-    @Override
-    public void releaseExternalResources() {
-        timer.stop();
-    }
-
     private final class HandshakeTimeoutTask implements TimerTask {
 
         private final ChannelHandlerContext ctx;
@@ -94,7 +86,7 @@
             if (!ctx.getChannel().isOpen()) {
                 return;
             }
-            if (!state.hsState.equals(HandshakeState.READY))
+            if (!channelHandler.isHandshakeComplete())
                 Channels.fireExceptionCaught(ctx, EXCEPTION);
         }
     }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchFeatures.java b/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchFeatures.java
deleted file mode 100644
index f537868..0000000
--- a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchFeatures.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import net.floodlightcontroller.core.IOFSwitch;
-
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
-
-public interface IOFSwitchFeatures {
-    public void setFromDescription(IOFSwitch sw, OFDescriptionStatistics description);
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
new file mode 100644
index 0000000..a79e7d9
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
@@ -0,0 +1,2251 @@
+package net.floodlightcontroller.core.internal;
+
+import java.io.IOException;
+import java.nio.channels.ClosedChannelException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.RejectedExecutionException;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IOFSwitch.PortChangeEvent;
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
+import net.floodlightcontroller.core.internal.Controller.Counters;
+import net.floodlightcontroller.core.internal.OFChannelHandler.ChannelState.RoleReplyInfo;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
+import net.floodlightcontroller.util.LoadMonitor;
+
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.Channels;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
+import org.jboss.netty.handler.timeout.IdleStateEvent;
+import org.jboss.netty.handler.timeout.ReadTimeoutException;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
+import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
+import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFEchoReply;
+import org.projectfloodlight.openflow.protocol.OFEchoRequest;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFErrorType;
+import org.projectfloodlight.openflow.protocol.OFExperimenter;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFFlowModFailedCode;
+import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
+import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
+import org.projectfloodlight.openflow.protocol.OFGetConfigRequest;
+import org.projectfloodlight.openflow.protocol.OFHello;
+import org.projectfloodlight.openflow.protocol.OFHelloElem;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFPortDescStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
+import org.projectfloodlight.openflow.protocol.OFRoleReply;
+import org.projectfloodlight.openflow.protocol.OFRoleRequest;
+import org.projectfloodlight.openflow.protocol.OFSetConfig;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
+import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
+import org.projectfloodlight.openflow.protocol.errormsg.OFRoleRequestFailedErrorMsg;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Channel handler deals with the switch connection and dispatches
+ * switch messages to the appropriate locations.
+ * @author readams, gregor, saurav
+ */
+class OFChannelHandler extends IdleStateAwareChannelHandler {
+
+    private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
+
+    private static final long DEFAULT_ROLE_TIMEOUT_MS = 10*1000; // 10 sec
+    private final Controller controller;
+    private final Counters counters;
+    private IOFSwitch sw;
+    private long thisdpid; // channelHandler cached value of connected switch id
+    private Channel channel;
+    // State needs to be volatile because the HandshakeTimeoutHandler
+    // needs to check if the handshake is complete
+    private volatile ChannelState state;
+
+
+    // All role messaging is handled by the roleChanger. The channel state machine
+    // coordinates between the roleChanger and the controller-global-registry-service
+    // to determine controller roles per switch.
+    private RoleChanger roleChanger;
+    // Used to coordinate between the controller and the cleanup thread(?)
+    // for access to the global registry on a per switch basis.
+    volatile Boolean controlRequested;
+    // When a switch with a duplicate dpid is found (i.e we already have a
+    // connected switch with the same dpid), the new switch is immediately
+    // disconnected. At that point netty callsback channelDisconnected() which
+    // proceeds to cleaup switch state - we need to ensure that it does not cleanup
+    // switch state for the older (still connected) switch
+    private volatile Boolean duplicateDpidFound;
+
+    // Temporary storage for switch-features and port-description
+    private OFFeaturesReply featuresReply;
+    private OFPortDescStatsReply portDescReply;
+    // a concurrent ArrayList to temporarily store port status messages
+    // before we are ready to deal with them
+    private final CopyOnWriteArrayList<OFPortStatus> pendingPortStatusMsg;
+
+    //Indicates the openflow version used by this switch
+    protected OFVersion ofVersion;
+    protected static OFFactory factory13;
+    protected static OFFactory factory10;
+
+    /** transaction Ids to use during handshake. Since only one thread
+     * calls into an OFChannelHandler instance, we don't need atomic.
+     * We will count down
+     */
+    private int handshakeTransactionIds = -1;
+
+    /**
+     * Create a new unconnected OFChannelHandler.
+     * @param controller
+     */
+    OFChannelHandler(Controller controller) {
+        this.controller = controller;
+        this.counters = controller.getCounters();
+        this.roleChanger = new RoleChanger(DEFAULT_ROLE_TIMEOUT_MS);
+        this.state = ChannelState.INIT;
+        this.pendingPortStatusMsg = new CopyOnWriteArrayList<OFPortStatus>();
+        factory13 = controller.getOFMessageFactory_13();
+        factory10 = controller.getOFMessageFactory_10();
+        controlRequested = Boolean.FALSE;
+        duplicateDpidFound = Boolean.FALSE;
+    }
+
+    //*******************
+    //  Role Handling
+    //*******************
+
+
+    /**
+     * When we remove a pending role request we use this enum to indicate how we
+     * arrived at the decision. When we send a role request to the switch, we
+     * also use  this enum to indicate what we expect back from the switch, so the
+     * role changer can match the reply to our expectation.
+     * @author gregor, saurav
+     */
+    public enum RoleRecvStatus {
+        /** The switch returned an error indicating that roles are not
+         * supported*/
+        UNSUPPORTED,
+        /** The request timed out */
+        NO_REPLY,
+        /** The reply was old, there is a newer request pending */
+        OLD_REPLY,
+        /**
+         *  The reply's role matched the role that this controller set in the
+         *  request message - invoked either initially at startup or to reassert
+         *  current role
+         */
+        MATCHED_CURRENT_ROLE,
+        /**
+         *  The reply's role matched the role that this controller set in the
+         *  request message - this is the result of a callback from the
+         *  global registry, followed by a role request sent to the switch
+         */
+        MATCHED_SET_ROLE,
+        /**
+         * The reply's role was a response to the query made by this controller
+         */
+        REPLY_QUERY,
+        /** We received a role reply message from the switch
+         *  but the expectation was unclear, or there was no expectation
+         */
+        OTHER_EXPECTATION,
+    }
+
+    /**
+     * Forwards to RoleChanger. See there.
+     * @param role
+     */
+    public void sendRoleRequest(Role role, RoleRecvStatus expectation) {
+        try {
+            roleChanger.sendRoleRequest(role, expectation);
+        } catch (IOException e) {
+             log.error("Disconnecting switch {} due to IO Error: {}",
+                              getSwitchInfoString(), e.getMessage());
+             channel.close();
+        }
+    }
+
+    // XXX S consider if necessary
+    public void disconnectSwitch() {
+        sw.disconnectSwitch();
+    }
+
+    /**
+     * A utility class to handle role requests and replies for this channel.
+     * After a role request is submitted the role changer keeps track of the
+     * pending request, collects the reply (if any) and times out the request
+     * if necessary.
+     *
+     * To simplify role handling we only keep track of the /last/ pending
+     * role reply send to the switch. If multiple requests are pending and
+     * we receive replies for earlier requests we ignore them. However, this
+     * way of handling pending requests implies that we could wait forever if
+     * a new request is submitted before the timeout triggers. If necessary
+     * we could work around that though.
+     * @author gregor
+     * @author saurav (added support OF1.3 role messages, and expectations)
+     */
+    private class RoleChanger {
+        // indicates that a request is currently pending
+        // needs to be volatile to allow correct double-check idiom
+        private volatile boolean requestPending;
+        // the transaction Id of the pending request
+        private int pendingXid;
+        // the role that's pending
+        private Role pendingRole;
+        // system time in MS when we send the request
+        private long roleSubmitTime;
+        // the timeout to use
+        private final long roleTimeoutMs;
+        // the expectation set by the caller for the returned role
+        private RoleRecvStatus expectation;
+
+        public RoleChanger(long roleTimeoutMs) {
+            this.requestPending = false;
+            this.roleSubmitTime = 0;
+            this.pendingXid = -1;
+            this.pendingRole = null;
+            this.roleTimeoutMs = roleTimeoutMs;
+            this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
+        }
+
+        /**
+         * Send NX role request message to the switch requesting the specified
+         * role.
+         *
+         * @param sw switch to send the role request message to
+         * @param role role to request
+         */
+        private int sendNxRoleRequest(Role role) throws IOException {
+            // Convert the role enum to the appropriate role to send
+            OFNiciraControllerRole roleToSend = OFNiciraControllerRole.ROLE_OTHER;
+            switch (role) {
+            case MASTER:
+                roleToSend = OFNiciraControllerRole.ROLE_MASTER;
+                break;
+            case SLAVE:
+            case EQUAL:
+            default:
+                // ensuring that the only two roles sent to 1.0 switches with
+                // Nicira role support, are MASTER and SLAVE
+                roleToSend = OFNiciraControllerRole.ROLE_SLAVE;
+                log.warn("Sending Nx Role.SLAVE to switch {}.", sw);
+            }
+            int xid = sw.getNextTransactionId();
+            OFExperimenter roleRequest = factory10
+                    .buildNiciraControllerRoleRequest()
+                    .setXid(xid)
+                    .setRole(roleToSend)
+                    .build();
+            sw.write(Collections.<OFMessage>singletonList(roleRequest),
+                     new FloodlightContext());
+            return xid;
+        }
+
+        private int sendOF13RoleRequest(Role role) throws IOException {
+            // Convert the role enum to the appropriate role to send
+            OFControllerRole roleToSend = OFControllerRole.ROLE_NOCHANGE;
+            switch (role) {
+            case EQUAL:
+                roleToSend = OFControllerRole.ROLE_EQUAL;
+                break;
+            case MASTER:
+                roleToSend = OFControllerRole.ROLE_MASTER;
+                break;
+            case SLAVE:
+                roleToSend = OFControllerRole.ROLE_SLAVE;
+                break;
+            default:
+                log.warn("Sending default role.noChange to switch {}."
+                        + " Should only be used for queries.", sw);
+            }
+
+            int xid = sw.getNextTransactionId();
+            OFRoleRequest rrm = factory13
+                    .buildRoleRequest()
+                    .setRole(roleToSend)
+                    .setXid(xid)
+                    .setGenerationId(sw.getNextGenerationId())
+                    .build();
+            sw.write(rrm, null);
+            return xid;
+        }
+
+        /**
+         * Send a role request with the given role to the switch and update
+         * the pending request and timestamp.
+         * Sends an OFPT_ROLE_REQUEST to an OF1.3 switch, OR
+         * Sends an NX_ROLE_REQUEST to an OF1.0 switch if configured to support it
+         * in the IOFSwitch driver. If not supported, this method sends nothing
+         * and returns 'false'. The caller should take appropriate action.
+         *
+         * One other optimization we do here is that for OF1.0 switches with
+         * Nicira role message support, we force the Role.EQUAL to become
+         * Role.SLAVE, as there is no defined behavior for the Nicira role OTHER.
+         * We cannot expect it to behave like SLAVE. We don't have this problem with
+         * OF1.3 switches, because Role.EQUAL is well defined and we can simulate
+         * SLAVE behavior by using ASYNC messages.
+         *
+         * @param role
+         * @throws IOException
+         * @returns false if and only if the switch does not support role-request
+         * messages, according to the switch driver; true otherwise.
+         */
+        synchronized boolean sendRoleRequest(Role role, RoleRecvStatus expectation)
+                throws IOException {
+            this.expectation = expectation;
+
+            if (ofVersion == OFVersion.OF_10) {
+                Boolean supportsNxRole = (Boolean)
+                        sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
+                if (!supportsNxRole) {
+			log.debug("Switch driver indicates no support for Nicira "
+					+ "role request messages. Not sending ...");
+			state.handleUnsentRoleMessage(OFChannelHandler.this, role,
+					expectation);
+			return false;
+                }
+                // OF1.0 switch with support for NX_ROLE_REQUEST vendor extn.
+                // make Role.EQUAL become Role.SLAVE
+                role = (role == Role.EQUAL) ? Role.SLAVE : role;
+                pendingXid = sendNxRoleRequest(role);
+                pendingRole = role;
+                roleSubmitTime = System.currentTimeMillis();
+                requestPending = true;
+            } else {
+                // OF1.3 switch, use OFPT_ROLE_REQUEST message
+                pendingXid = sendOF13RoleRequest(role);
+                pendingRole = role;
+                roleSubmitTime = System.currentTimeMillis();
+                requestPending = true;
+            }
+            return true;
+        }
+
+        /**
+         * Deliver a received role reply.
+         *
+         * Check if a request is pending and if the received reply matches the
+         * the expected pending reply (we check both role and xid) we set
+         * the role for the switch/channel.
+         *
+         * If a request is pending but doesn't match the reply we ignore it, and
+         * return
+         *
+         * If no request is pending we disconnect with a SwitchStateException
+         *
+         * @param RoleReplyInfo information about role-reply in format that
+         *                      controller can understand.
+         * @throws SwitchStateException if no request is pending
+         */
+        synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
+                throws SwitchStateException {
+            if (!requestPending) {
+                Role currentRole = (sw != null) ? sw.getRole() : null;
+                if (currentRole != null) {
+                    if (currentRole == rri.getRole()) {
+                        // Don't disconnect if the role reply we received is
+                        // for the same role we are already in.
+                        log.debug("Received unexpected RoleReply from "
+                                + "Switch: {} in State: {}. "
+                                + "Role in reply is same as current role of this "
+                                + "controller for this sw. Ignoring ...",
+                                getSwitchInfoString(), state.toString());
+                        return RoleRecvStatus.OTHER_EXPECTATION;
+                    } else {
+                        String msg = String.format("Switch: [%s], State: [%s], "
+                                + "received unexpected RoleReply[%s]. "
+                                + "No roles are pending, and this controller's "
+                                + "current role:[%s] does not match reply. "
+                                + "Disconnecting switch ... ",
+                                OFChannelHandler.this.getSwitchInfoString(),
+                                OFChannelHandler.this.state.toString(),
+                                rri, currentRole);
+                        throw new SwitchStateException(msg);
+                    }
+                }
+                log.debug("Received unexpected RoleReply {} from "
+                        + "Switch: {} in State: {}. "
+                        + "This controller has no current role for this sw. "
+                        + "Ignoring ...", new Object[] {rri,
+                                getSwitchInfoString(), state});
+                return RoleRecvStatus.OTHER_EXPECTATION;
+            }
+
+            int xid = (int) rri.getXid();
+            Role role = rri.getRole();
+            // XXX S should check generation id meaningfully and other cases of expectations
+            // U64 genId = rri.getGenId();
+
+            if (pendingXid != xid) {
+                log.debug("Received older role reply from " +
+                        "switch {} ({}). Ignoring. " +
+                        "Waiting for {}, xid={}",
+                        new Object[] { getSwitchInfoString(), rri,
+                        pendingRole, pendingXid });
+                return RoleRecvStatus.OLD_REPLY;
+            }
+
+            if (pendingRole == role) {
+                log.debug("Received role reply message from {} that matched "
+                        + "expected role-reply {} with expectations {}",
+                        new Object[] {getSwitchInfoString(), role, expectation});
+                counters.roleReplyReceived.updateCounterWithFlush();
+                //setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY); dont want to set state here
+                if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
+                        expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
+                    return expectation;
+                } else {
+                    return RoleRecvStatus.OTHER_EXPECTATION;
+                }
+            }
+
+            // if xids match but role's don't, perhaps its a query (OF1.3)
+            if (expectation == RoleRecvStatus.REPLY_QUERY)
+                return expectation;
+
+            return RoleRecvStatus.OTHER_EXPECTATION;
+        }
+
+        /**
+         * Called if we receive an  error message. If the xid matches the
+         * pending request we handle it otherwise we ignore it.
+         *
+         * Note: since we only keep the last pending request we might get
+         * error messages for earlier role requests that we won't be able
+         * to handle
+         */
+        synchronized RoleRecvStatus deliverError(OFErrorMsg error)
+                throws SwitchStateException {
+            if (!requestPending) {
+                log.debug("Received an error msg from sw {}, but no pending "
+                        + "requests in role-changer; not handling ...",
+                        getSwitchInfoString());
+                return RoleRecvStatus.OTHER_EXPECTATION;
+            }
+            if (pendingXid != error.getXid()) {
+                if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
+                    log.debug("Received an error msg from sw {} for a role request,"
+                            + " but not for pending request in role-changer; "
+                            + " ignoring error {} ...",
+                            getSwitchInfoString(), error);
+                }
+                return RoleRecvStatus.OTHER_EXPECTATION;
+            }
+            // it is an error related to a currently pending role request message
+            if (error.getErrType() == OFErrorType.BAD_REQUEST) {
+                counters.roleReplyErrorUnsupported.updateCounterWithFlush();
+                log.error("Received a error msg {} from sw {} in state {} for "
+                        + "pending role request {}. Switch driver indicates "
+                        + "role-messaging is supported. Possible issues in "
+                        + "switch driver configuration?", new Object[] {
+                                ((OFBadRequestErrorMsg)error).toString(),
+                                getSwitchInfoString(), state, pendingRole
+                        });
+                return RoleRecvStatus.UNSUPPORTED;
+            }
+
+            if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
+                OFRoleRequestFailedErrorMsg rrerr =
+                        (OFRoleRequestFailedErrorMsg) error;
+                switch (rrerr.getCode()) {
+                case BAD_ROLE:
+                    // switch says that current-role-req has bad role?
+                    // for now we disconnect
+                    // fall-thru
+                case STALE:
+                    // switch says that current-role-req has stale gen-id?
+                    // for now we disconnect
+                    // fall-thru
+                case UNSUP:
+                    // switch says that current-role-req has role that
+                    // cannot be supported? for now we disconnect
+                    String msgx = String.format("Switch: [%s], State: [%s], "
+                            + "received Error to for pending role request [%s]. "
+                            + "Error:[%s]. Disconnecting switch ... ",
+                            OFChannelHandler.this.getSwitchInfoString(),
+                            OFChannelHandler.this.state.toString(),
+                            pendingRole, rrerr);
+                    throw new SwitchStateException(msgx);
+                default:
+                    break;
+                }
+            }
+
+            // This error message was for a role request message but we dont know
+            // how to handle errors for nicira role request messages
+            return RoleRecvStatus.OTHER_EXPECTATION;
+        }
+
+        /**
+         * Check if a pending role request has timed out.
+         */
+        void checkTimeout() {
+            if (!requestPending)
+                return;
+            synchronized(this) {
+                if (!requestPending)
+                    return;
+                long now = System.currentTimeMillis();
+                if (now - roleSubmitTime > roleTimeoutMs) {
+                    // timeout triggered.
+                    counters.roleReplyTimeout.updateCounterWithFlush();
+                    //setSwitchRole(pendingRole, RoleRecvStatus.NO_REPLY);
+                    // XXX S come back to this
+                }
+            }
+        }
+
+    }
+
+    //*************************
+    //  Channel State Machine
+    //*************************
+
+    /**
+     * The state machine for handling the switch/channel state. All state
+     * transitions should happen from within the state machine (and not from other
+     * parts of the code)
+     * @author gregor
+     * @author saurav (modified to handle 1.0 & 1.3 switches, EQUAL state, role-handling )
+     */
+    enum ChannelState {
+        /**
+         * Initial state before channel is connected.
+         */
+        INIT(false) {
+            @Override
+            void processOFMessage(OFChannelHandler h, OFMessage m)
+                    throws IOException, SwitchStateException {
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m)
+                    throws IOException {
+                // need to implement since its abstract but it will never
+                // be called
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                unhandledMessageReceived(h, m);
+            }
+        },
+
+        /**
+         * We send a OF 1.3 HELLO to the switch and wait for a Hello from the switch.
+         * Once we receive the reply, we decide on OF 1.3 or 1.0 switch - no other
+         * protocol version is accepted.
+         * We send an OFFeaturesRequest depending on the protocol version selected
+         * Next state is WAIT_FEATURES_REPLY
+         */
+        WAIT_HELLO(false) {
+            @Override
+            void processOFHello(OFChannelHandler h, OFHello m)
+                    throws IOException {
+                // TODO We could check for the optional bitmap, but for now
+                // we are just checking the version number.
+                if (m.getVersion() == OFVersion.OF_13) {
+                    log.info("Received {} Hello from {}", m.getVersion(),
+                            h.channel.getRemoteAddress());
+                    h.ofVersion = OFVersion.OF_13;
+                } else if (m.getVersion() == OFVersion.OF_10) {
+                    log.info("Received {} Hello from {} - switching to OF "
+                            + "version 1.0", m.getVersion(),
+                            h.channel.getRemoteAddress());
+                    h.ofVersion = OFVersion.OF_10;
+                } else {
+                    log.error("Received Hello of version {} from switch at {}. "
+                            + "This controller works with OF1.0 and OF1.3 "
+                            + "switches. Disconnecting switch ...",
+                            m.getVersion(), h.channel.getRemoteAddress());
+                    h.channel.disconnect();
+                    return;
+                }
+                h.sendHandshakeFeaturesRequestMessage();
+                h.setState(WAIT_FEATURES_REPLY);
+            }
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException, SwitchStateException {
+                illegalMessageReceived(h, m);
+            }
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatsReply  m)
+                    throws IOException, SwitchStateException {
+                illegalMessageReceived(h, m);
+            }
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m) {
+                logErrorDisconnect(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                unhandledMessageReceived(h, m);
+            }
+        },
+
+
+        /**
+         * We are waiting for a features reply message. Once we receive it, the
+         * behavior depends on whether this is a 1.0 or 1.3 switch. For 1.0,
+         * we send a SetConfig request, barrier, and GetConfig request and the
+         * next state is WAIT_CONFIG_REPLY. For 1.3, we send a Port description
+         * request and the next state is WAIT_PORT_DESC_REPLY.
+         */
+        WAIT_FEATURES_REPLY(false) {
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException {
+                h.thisdpid = m.getDatapathId().getLong();
+                log.info("Received features reply for switch at {} with dpid {}",
+                        h.getSwitchInfoString(), h.thisdpid);
+                //update the controller about this connected switch
+                boolean success = h.controller.addConnectedSwitch(
+                        h.thisdpid, h);
+                if (!success) {
+                    disconnectDuplicate(h);
+                    return;
+                }
+
+                h.featuresReply = m; //temp store
+                if (h.ofVersion == OFVersion.OF_10) {
+                    h.sendHandshakeSetConfig();
+                    h.setState(WAIT_CONFIG_REPLY);
+                } else {
+                    //version is 1.3, must get switchport information
+                    h.sendHandshakeOFPortDescRequest();
+                    h.setState(WAIT_PORT_DESC_REPLY);
+                }
+            }
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatsReply  m)
+                    throws IOException, SwitchStateException {
+                illegalMessageReceived(h, m);
+            }
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m) {
+                logErrorDisconnect(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                unhandledMessageReceived(h, m);
+            }
+        },
+
+        /**
+         * We are waiting for a description of the 1.3 switch ports.
+         * Once received, we send a SetConfig request
+         * Next State is WAIT_CONFIG_REPLY
+         */
+        WAIT_PORT_DESC_REPLY(false) {
+
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
+                    throws SwitchStateException {
+                // Read port description
+                if (m.getStatsType() != OFStatsType.PORT_DESC) {
+                    log.warn("Expecting port description stats but received stats "
+                            + "type {} from {}. Ignoring ...", m.getStatsType(),
+                            h.channel.getRemoteAddress());
+                    return;
+                }
+                if (m.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
+                    log.warn("Stats reply indicates more stats from sw {} for "
+                            + "port description - not currently handled",
+                            h.getSwitchInfoString());
+                }
+                h.portDescReply = (OFPortDescStatsReply)m; // temp store
+                log.info("Received port desc reply for switch at {}",
+                        h.getSwitchInfoString());
+                try {
+                    h.sendHandshakeSetConfig();
+                } catch (IOException e) {
+                    log.error("Unable to send setConfig after PortDescReply. "
+                            + "Error: {}", e.getMessage());
+                }
+                h.setState(WAIT_CONFIG_REPLY);
+            }
+
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m)
+                    throws IOException, SwitchStateException {
+                logErrorDisconnect(h, m);
+
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException, SwitchStateException {
+                unhandledMessageReceived(h, m);
+
+            }
+        },
+
+        /**
+         * We are waiting for a config reply message. Once we receive it
+         * we send a DescriptionStatsRequest to the switch.
+         * Next state: WAIT_DESCRIPTION_STAT_REPLY
+         */
+        WAIT_CONFIG_REPLY(false) {
+            @Override
+            @LogMessageDocs({
+                @LogMessageDoc(level="WARN",
+                        message="Config Reply from {switch} has " +
+                                "miss length set to {length}",
+                        explanation="The controller requires that the switch " +
+                                "use a miss length of 0xffff for correct " +
+                                "function",
+                        recommendation="Use a different switch to ensure " +
+                                "correct function")
+            })
+            void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
+                    throws IOException {
+                if (m.getMissSendLen() == 0xffff) {
+                    log.trace("Config Reply from switch {} confirms "
+                            + "miss length set to 0xffff",
+                            h.getSwitchInfoString());
+                } else {
+                    // FIXME: we can't really deal with switches that don't send
+                    // full packets. Shouldn't we drop the connection here?
+                    log.warn("Config Reply from switch {} has"
+                            + "miss length set to {}",
+                            h.getSwitchInfoString(),
+                            m.getMissSendLen());
+                }
+                h.sendHandshakeDescriptionStatsRequest();
+                h.setState(WAIT_DESCRIPTION_STAT_REPLY);
+            }
+
+            @Override
+            void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) {
+                // do nothing;
+            }
+
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException, SwitchStateException {
+                illegalMessageReceived(h, m);
+            }
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatsReply  m)
+                    throws IOException, SwitchStateException {
+                log.error("Received multipart(stats) message sub-type {}",
+                        m.getStatsType());
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m) {
+                logErrorDisconnect(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                h.pendingPortStatusMsg.add(m);
+            }
+        },
+
+
+        /**
+         * We are waiting for a OFDescriptionStat message from the switch.
+         * Once we receive any stat message we try to parse it. If it's not
+         * a description stats message we disconnect. If its the expected
+         * description stats message, we:
+         *    - use the switch driver to bind the switch and get an IOFSwitch instance
+         *    - setup the IOFSwitch instance
+         *    - add switch to FloodlightProvider(Controller) and send the initial role
+         *      request to the switch.
+         * Next state: WAIT_INITIAL_ROLE
+         *      In the typical case, where switches support role request messages
+         *      the next state is where we expect the role reply message.
+         *      In the special case that where the switch does not support any kind
+         *      of role request messages, we don't send a role message, but we do
+         *      request mastership from the registry service. This controller
+         *      should become master once we hear back from the registry service.
+         * All following states will have a h.sw instance!
+         */
+        WAIT_DESCRIPTION_STAT_REPLY(false) {
+            @LogMessageDoc(message="Switch {switch info} bound to class " +
+                "{switch driver}, description {switch description}",
+                    explanation="The specified switch has been bound to " +
+                            "a switch driver based on the switch description" +
+                            "received from the switch")
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
+                    throws SwitchStateException {
+                // Read description, if it has been updated
+                if (m.getStatsType() != OFStatsType.DESC) {
+                    log.warn("Expecting Description stats but received stats "
+                            + "type {} from {}. Ignoring ...", m.getStatsType(),
+                            h.channel.getRemoteAddress());
+                    return;
+                }
+                log.info("Received switch description reply from switch at {}",
+                        h.channel.getRemoteAddress());
+                OFDescStatsReply drep = (OFDescStatsReply) m;
+                // Here is where we differentiate between different kinds of switches
+                h.sw = h.controller.getOFSwitchInstance(drep, h.ofVersion);
+                // set switch information
+                h.sw.setOFVersion(h.ofVersion);
+                ((OFSwitchImplBase) h.sw).setFeaturesReply(h.featuresReply);
+                ((OFSwitchImplBase) h.sw).setPortDescReply(h.portDescReply);
+                h.sw.setConnected(true);
+                h.sw.setChannel(h.channel);
+                h.sw.setFloodlightProvider(h.controller);
+                h.sw.setThreadPoolService(h.controller.getThreadPoolService());
+                try {
+                    h.sw.setDebugCounterService(h.controller.getDebugCounter());
+                } catch (CounterException e) {
+                    h.counters.switchCounterRegistrationFailed
+                            .updateCounterNoFlush();
+                    log.warn("Could not register counters for switch {} ",
+                              h.getSwitchInfoString(), e);
+                }
+
+                log.info("Switch {} bound to class {}, description {}",
+                         new Object[] { h.sw, h.sw.getClass(), drep });
+                //Put switch in EQUAL mode until we hear back from the global registry
+                log.debug("Setting new switch {} to EQUAL and sending Role request",
+                        h.sw.getStringId());
+                h.setSwitchRole(Role.EQUAL);
+                try {
+                    boolean supportsRRMsg = h.roleChanger.sendRoleRequest(Role.EQUAL,
+                            RoleRecvStatus.MATCHED_CURRENT_ROLE);
+                    if (!supportsRRMsg) {
+                        log.warn("Switch {} does not support role request messages "
+                                + "of any kind. No role messages were sent. "
+                                + "This controller instance SHOULD become MASTER "
+                                + "from the registry process. ",
+                                h.getSwitchInfoString());
+                    }
+                    h.setState(WAIT_INITIAL_ROLE);
+                    // request control of switch from global registry -
+                    // necessary even if this is the only controller the
+                    // switch is connected to.
+                    h.controller.submitRegistryRequest(h.sw.getId());
+                } catch (IOException e) {
+                    log.error("Exception when sending role request: {} ",
+                            e.getMessage());
+                    // FIXME shouldn't we disconnect?
+                }
+            }
+
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m) {
+                logErrorDisconnect(h, m);
+            }
+
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException, SwitchStateException {
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException {
+                h.pendingPortStatusMsg.add(m);
+            }
+        },
+
+        /**
+         * We are waiting for a role reply message in response to a role request
+         * sent after hearing back from the registry service -- OR -- we are
+         * just waiting to hear back from the registry service in the case that
+         * the switch does not support role messages. If completed successfully,
+         * the controller's role for this switch will be set here.
+         * Before we move to the state corresponding to the role, we allow the
+         * switch specific driver to complete its configuration. This configuration
+         * typically depends on the role the controller is playing for this switch.
+         * And so we set the switch role (for 'this' controller) before we start
+         * the driver-sub-handshake.
+         * Next State: WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
+         */
+        WAIT_INITIAL_ROLE(false) {
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m)
+                    throws SwitchStateException {
+                // role changer will ignore the error if it isn't for it
+                RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
+                if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
+                    logError(h, m);
+                }
+            }
+
+            @Override
+            void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
+                    throws IOException, SwitchStateException {
+                Role role = extractNiciraRoleReply(h, m);
+                // If role == null it means the vendor (experimenter) message
+                // wasn't really a Nicira role reply. We ignore this case.
+                if (role != null) {
+                    RoleReplyInfo rri = new RoleReplyInfo(role, null, m.getXid());
+                    RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+                    if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+                        setRoleAndStartDriverHandshake(h, rri.getRole());
+                    } // else do nothing - wait for the correct expected reply
+                } else {
+                    unhandledMessageReceived(h, m);
+                }
+            }
+
+            @Override
+            void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
+                    throws SwitchStateException, IOException {
+                RoleReplyInfo rri = extractOFRoleReply(h,m);
+                RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+                if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+                    setRoleAndStartDriverHandshake(h, rri.getRole());
+                } // else do nothing - wait for the correct expected reply
+            }
+
+            @Override
+            void handleUnsentRoleMessage(OFChannelHandler h, Role role,
+            		RoleRecvStatus expectation) throws IOException {
+            	// typically this is triggered for a switch where role messages
+            	// are not supported - we confirm that the role being set is
+            	// master and move to the next state
+            	if (expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
+            		if (role == Role.MASTER) {
+            			setRoleAndStartDriverHandshake(h, role);
+            		} else {
+            			log.error("Expected MASTER role from registry for switch "
+            					+ "which has no support for role-messages."
+            					+ "Received {}. It is possible that this switch "
+            					+ "is connected to other controllers, in which "
+            					+ "case it should support role messages - not "
+            					+ "moving forward.", role);
+            		}
+            	} // else do nothing - wait to hear back from registry
+
+            }
+
+            private void setRoleAndStartDriverHandshake(OFChannelHandler h,
+                    Role role) throws IOException {
+                h.setSwitchRole(role);
+                h.sw.startDriverHandshake();
+                if (h.sw.isDriverHandshakeComplete()) {
+                    Role mySwitchRole = h.sw.getRole();
+                    if (mySwitchRole == Role.MASTER) {
+                        log.info("Switch-driver sub-handshake complete. "
+                                + "Activating switch {} with Role: MASTER",
+                                h.getSwitchInfoString());
+                        handlePendingPortStatusMessages(h); //before activation
+                        boolean success = h.controller.addActivatedMasterSwitch(
+                                h.sw.getId(), h.sw);
+                        if (!success) {
+                            disconnectDuplicate(h);
+                            return;
+                        }
+                        h.setState(MASTER);
+                    } else {
+                        log.info("Switch-driver sub-handshake complete. "
+                                + "Activating switch {} with Role: EQUAL",
+                                h.getSwitchInfoString());
+                        handlePendingPortStatusMessages(h); //before activation
+                        boolean success = h.controller.addActivatedEqualSwitch(
+                                h.sw.getId(), h.sw);
+                        if (!success) {
+                            disconnectDuplicate(h);
+                            return;
+                        }
+                        h.setState(EQUAL);
+                    }
+                } else {
+                    h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
+                }
+            }
+
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                    throws IOException, SwitchStateException {
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
+                    throws SwitchStateException {
+                illegalMessageReceived(h, m);
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException, SwitchStateException {
+                h.pendingPortStatusMsg.add(m);
+
+            }
+        },
+
+        /**
+         * We are waiting for the respective switch driver to complete its
+         * configuration. Notice that we do not consider this to be part of the main
+         * switch-controller handshake. But we do consider it as a step that comes
+         * before we declare the switch as available to the controller.
+         * Next State: depends on the role of this controller for this switch - either
+         * MASTER or EQUAL.
+         */
+        WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(true) {
+
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m)
+                    throws IOException {
+                // will never be called. We override processOFMessage
+            }
+
+            @Override
+            void processOFMessage(OFChannelHandler h, OFMessage m)
+                    throws IOException {
+                if (m.getType() == OFType.ECHO_REQUEST)
+                    processOFEchoRequest(h, (OFEchoRequest)m);
+                else {
+                    // FIXME: other message to handle here?
+                    h.sw.processDriverHandshakeMessage(m);
+                    if (h.sw.isDriverHandshakeComplete()) {
+                        // consult the h.sw role and goto that state
+                        Role mySwitchRole = h.sw.getRole();
+                        if (mySwitchRole == Role.MASTER) {
+                            log.info("Switch-driver sub-handshake complete. "
+                                    + "Activating switch {} with Role: MASTER",
+                                    h.getSwitchInfoString());
+                            handlePendingPortStatusMessages(h); //before activation
+                            boolean success = h.controller.addActivatedMasterSwitch(
+                                    h.sw.getId(), h.sw);
+                            if (!success) {
+                                disconnectDuplicate(h);
+                                return;
+                            }
+                            h.setState(MASTER);
+                        } else {
+                            log.info("Switch-driver sub-handshake complete. "
+                                    + "Activating switch {} with Role: EQUAL",
+                                    h.getSwitchInfoString());
+                            handlePendingPortStatusMessages(h); //before activation
+                            boolean success = h.controller.addActivatedEqualSwitch(
+                                    h.sw.getId(), h.sw);
+                            if (!success) {
+                                disconnectDuplicate(h);
+                                return;
+                            }
+                            h.setState(EQUAL);
+                        }
+                    }
+                }
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException, SwitchStateException {
+                h.pendingPortStatusMsg.add(m);
+            }
+        },
+
+
+        /**
+         * This controller is in MASTER role for this switch. We enter this state
+         * after requesting and winning control from the global registry.
+         * The main handshake as well as the switch-driver sub-handshake
+         * is complete at this point.
+         * // XXX S reconsider below
+         * In the (near) future we may deterministically assign controllers to
+         * switches at startup.
+         * We only leave this state if the switch disconnects or
+         * if we send a role request for SLAVE /and/ receive the role reply for
+         * SLAVE.
+         */
+        MASTER(true) {
+            @LogMessageDoc(level="WARN",
+                message="Received permission error from switch {} while" +
+                         "being master. Reasserting master role.",
+                explanation="The switch has denied an operation likely " +
+                         "indicating inconsistent controller roles",
+                recommendation="This situation can occurs transiently during role" +
+                 " changes. If, however, the condition persists or happens" +
+                 " frequently this indicates a role inconsistency. " +
+                 LogMessageDoc.CHECK_CONTROLLER )
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m)
+                    throws IOException, SwitchStateException {
+                // first check if the error msg is in response to a role-request message
+                RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
+                if (rrstatus != RoleRecvStatus.OTHER_EXPECTATION) {
+			// rolechanger has handled the error message - we are done
+                    return;
+                }
+
+                // if we get here, then the error message is for something else
+                if (m.getErrType() == OFErrorType.BAD_REQUEST &&
+                        ((OFBadRequestErrorMsg) m).getCode() ==
+                            OFBadRequestCode.EPERM) {
+                    // We are the master controller and the switch returned
+                    // a permission error. This is a likely indicator that
+                    // the switch thinks we are slave. Reassert our
+                    // role
+                    // FIXME: this could be really bad during role transitions
+                    // if two controllers are master (even if its only for
+                    // a brief period). We might need to see if these errors
+                    // persist before we reassert
+                    h.counters.epermErrorWhileSwitchIsMaster.updateCounterWithFlush();
+                    log.warn("Received permission error from switch {} while" +
+                             "being master. Reasserting master role.",
+                             h.getSwitchInfoString());
+                    //h.controller.reassertRole(h, Role.MASTER);
+                    // XXX S reassert in role changer or reconsider if all this
+                    // stuff is really needed
+                } else if (m.getErrType() == OFErrorType.FLOW_MOD_FAILED &&
+                            ((OFFlowModFailedErrorMsg) m).getCode() ==
+                                OFFlowModFailedCode.ALL_TABLES_FULL) {
+                    h.sw.setTableFull(true);
+                } else {
+                    logError(h, m);
+                }
+                h.dispatchMessage(m);
+            }
+
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatsReply m) {
+                h.sw.deliverStatisticsReply(m);
+            }
+
+            @Override
+            void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
+                    throws IOException, SwitchStateException {
+                Role role = extractNiciraRoleReply(h, m);
+                if (role == null) {
+			// The message wasn't really a Nicira role reply. We just
+			// dispatch it to the OFMessage listeners in this case.
+			h.dispatchMessage(m);
+			return;
+                }
+
+                RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
+				new RoleReplyInfo(role, null, m.getXid()));
+                if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+			checkAndSetRoleTransition(h, role);
+                }
+            }
+
+            @Override
+            void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
+                    throws SwitchStateException, IOException {
+                RoleReplyInfo rri = extractOFRoleReply(h, m);
+                RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+                if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+			checkAndSetRoleTransition(h, rri.getRole());
+                }
+            }
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException, SwitchStateException {
+                handlePortStatusMessage(h, m, true);
+                h.dispatchMessage(m);
+            }
+
+            @Override
+            void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
+                    throws IOException {
+                h.dispatchMessage(m);
+            }
+
+            @Override
+            void processOFFlowRemoved(OFChannelHandler h,
+                                      OFFlowRemoved m) throws IOException {
+                h.dispatchMessage(m);
+            }
+
+            @Override
+            void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
+                    throws IOException {
+		h.dispatchMessage(m);
+            }
+
+        },
+
+        /**
+         * This controller is in EQUAL role for this switch. We enter this state
+         * after some /other/ controller instance wins mastership-role over this
+         * switch. The EQUAL role can be considered the same as the SLAVE role
+         * if this controller does NOT send commands or packets to the switch.
+         * This should always be true for OF1.0 switches. XXX S need to enforce.
+         *
+         * For OF1.3 switches, choosing this state as EQUAL instead of SLAVE,
+         * gives us the flexibility that if an app wants to send commands/packets
+         * to switches, it can, even thought it is running on a controller instance
+         * that is not in a MASTER role for this switch. Of course, it is the job
+         * of the app to ensure that commands/packets sent by this (EQUAL) controller
+         * instance does not clash/conflict with commands/packets sent by the MASTER
+         * controller for this switch. Neither the controller instances, nor the
+         * switch provides any kind of resolution mechanism should conflicts occur.
+         */
+        EQUAL(true) {
+            @Override
+            void processOFError(OFChannelHandler h, OFErrorMsg m)
+                    throws IOException, SwitchStateException {
+                // role changer will ignore the error if it isn't for it
+                RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
+                if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
+                    logError(h, m);
+                    h.dispatchMessage(m);
+                }
+            }
+
+            @Override
+            void processOFStatisticsReply(OFChannelHandler h,
+                                          OFStatsReply m) {
+                h.sw.deliverStatisticsReply(m);
+            }
+
+            @Override
+            void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
+                    throws IOException, SwitchStateException {
+                Role role = extractNiciraRoleReply(h, m);
+                // If role == null it means the message wasn't really a
+                // Nicira role reply. We ignore it in this state.
+                if (role != null) {
+			RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
+                            new RoleReplyInfo(role, null, m.getXid()));
+			if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+			checkAndSetRoleTransition(h, role);
+                    }
+                } else {
+                    unhandledMessageReceived(h, m);
+                }
+            }
+
+            @Override
+            void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
+                    throws SwitchStateException, IOException {
+                RoleReplyInfo rri = extractOFRoleReply(h, m);
+                RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+                if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+			checkAndSetRoleTransition(h, rri.getRole());
+                }
+            }
+
+            // XXX S needs more handlers for 1.3 switches in equal role
+
+            @Override
+            void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                    throws IOException, SwitchStateException {
+                handlePortStatusMessage(h, m, true);
+            }
+
+            @Override
+            @LogMessageDoc(level="WARN",
+                message="Received PacketIn from switch {} while" +
+                         "being slave. Reasserting slave role.",
+                explanation="The switch has receive a PacketIn despite being " +
+                         "in slave role indicating inconsistent controller roles",
+                recommendation="This situation can occurs transiently during role" +
+                         " changes. If, however, the condition persists or happens" +
+                         " frequently this indicates a role inconsistency. " +
+                         LogMessageDoc.CHECK_CONTROLLER )
+            void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
+                // we don't expect packetIn while slave, reassert we are slave
+                h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush();
+                log.warn("Received PacketIn from switch {} while" +
+                         "being slave. Reasserting slave role.", h.sw);
+                //h.controller.reassertRole(h, Role.SLAVE);
+                // XXX reassert in role changer
+            }
+        };
+
+        private final boolean handshakeComplete;
+        ChannelState(boolean handshakeComplete) {
+            this.handshakeComplete = handshakeComplete;
+        }
+
+        /**
+         * Is this a state in which the handshake has completed?
+         * @return true if the handshake is complete
+         */
+        public boolean isHandshakeComplete() {
+            return handshakeComplete;
+        }
+
+        /**
+         * Get a string specifying the switch connection, state, and
+         * message received. To be used as message for SwitchStateException
+         * or log messages
+         * @param h The channel handler (to get switch information_
+         * @param m The OFMessage that has just been received
+         * @param details A string giving more details about the exact nature
+         * of the problem.
+         * @return
+         */
+        // needs to be protected because enum members are actually subclasses
+        protected String getSwitchStateMessage(OFChannelHandler h,
+                                                      OFMessage m,
+                                                      String details) {
+            return String.format("Switch: [%s], State: [%s], received: [%s]"
+                                 + ", details: %s",
+                                 h.getSwitchInfoString(),
+                                 this.toString(),
+                                 m.getType().toString(),
+                                 details);
+        }
+
+        /**
+         * We have an OFMessage we didn't expect given the current state and
+         * we want to treat this as an error.
+         * We currently throw an exception that will terminate the connection
+         * However, we could be more forgiving
+         * @param h the channel handler that received the message
+         * @param m the message
+         * @throws SwitchStateException
+         * @throws SwitchStateExeption we always through the execption
+         */
+        // needs to be protected because enum members are acutally subclasses
+        protected void illegalMessageReceived(OFChannelHandler h, OFMessage m)
+                throws SwitchStateException {
+            String msg = getSwitchStateMessage(h, m,
+                    "Switch should never send this message in the current state");
+            throw new SwitchStateException(msg);
+
+        }
+
+        /**
+         * We have an OFMessage we didn't expect given the current state and
+         * we want to ignore the message
+         * @param h the channel handler the received the message
+         * @param m the message
+         */
+        protected void unhandledMessageReceived(OFChannelHandler h,
+                                                OFMessage m) {
+            h.counters.unhandledMessage.updateCounterNoFlush();
+            if (log.isDebugEnabled()) {
+                String msg = getSwitchStateMessage(h, m,
+                        "Ignoring unexpected message");
+                log.debug(msg);
+            }
+        }
+
+        /**
+         * Log an OpenFlow error message from a switch
+         * @param sw The switch that sent the error
+         * @param error The error message
+         */
+        @LogMessageDoc(level="ERROR",
+                message="Error {error type} {error code} from {switch} " +
+                        "in state {state}",
+                explanation="The switch responded with an unexpected error" +
+                        "to an OpenFlow message from the controller",
+                recommendation="This could indicate improper network operation. " +
+                        "If the problem persists restarting the switch and " +
+                        "controller may help."
+                )
+        protected void logError(OFChannelHandler h, OFErrorMsg error) {
+            log.error("{} from switch {} in state {}",
+                      new Object[] {
+                          error,
+                          h.getSwitchInfoString(),
+                          this.toString()});
+        }
+
+        /**
+         * Log an OpenFlow error message from a switch and disconnect the
+         * channel
+         * @param sw The switch that sent the error
+         * @param error The error message
+         */
+        protected void logErrorDisconnect(OFChannelHandler h, OFErrorMsg error) {
+            logError(h, error);
+            h.channel.disconnect();
+        }
+
+        /**
+         * log an error message for a duplicate dpid and disconnect this channel
+         */
+        protected void disconnectDuplicate(OFChannelHandler h) {
+            log.error("Duplicated dpid or incompleted cleanup - "
+                    + "disconnecting channel {}", h.getSwitchInfoString());
+            h.duplicateDpidFound = Boolean.TRUE;
+            h.channel.disconnect();
+        }
+
+        /**
+         * Extract the role from an OFVendor message.
+         *
+         * Extract the role from an OFVendor message if the message is a
+         * Nicira role reply. Otherwise return null.
+         *
+         * @param h The channel handler receiving the message
+         * @param vendorMessage The vendor message to parse.
+         * @return The role in the message if the message is a Nicira role
+         * reply, null otherwise.
+         * @throws SwitchStateException If the message is a Nicira role reply
+         * but the numeric role value is unknown.
+         */
+        protected Role extractNiciraRoleReply(OFChannelHandler h,
+			OFExperimenter experimenterMsg) throws SwitchStateException {
+		int vendor = (int) experimenterMsg.getExperimenter();
+		if (vendor != 0x2320) // magic number representing nicira
+			return null;
+		OFNiciraControllerRoleReply nrr =
+				(OFNiciraControllerRoleReply) experimenterMsg;
+
+		Role role = null;
+		OFNiciraControllerRole ncr = nrr.getRole();
+		switch(ncr) {
+		case ROLE_MASTER:
+			role = Role.MASTER;
+			break;
+		case ROLE_OTHER:
+			role = Role.EQUAL;
+			break;
+		case ROLE_SLAVE:
+			role = Role.SLAVE;
+			break;
+		default: //handled below
+		}
+
+		if (role == null) {
+			String msg = String.format("Switch: [%s], State: [%s], "
+					+ "received NX_ROLE_REPLY with invalid role "
+					+ "value %d",
+					h.getSwitchInfoString(),
+					this.toString(),
+					nrr.getRole());
+			throw new SwitchStateException(msg);
+		}
+		return role;
+        }
+
+        /**
+         * Helper class returns role reply information in the format understood
+         * by the controller.
+         */
+        protected class RoleReplyInfo {
+            private Role role;
+            private U64 genId;
+            private long xid;
+
+            RoleReplyInfo (Role role, U64 genId, long xid) {
+                this.role = role;
+                this.genId = genId;
+                this.xid = xid;
+            }
+            public Role getRole() { return role; }
+            public U64 getGenId() { return genId; }
+            public long getXid() { return xid; }
+            @Override
+            public String toString() {
+                return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
+            }
+        }
+
+        /**
+         * Extract the role information from an OF1.3 Role Reply Message
+         * @param h
+         * @param rrmsg
+         * @return RoleReplyInfo object
+         * @throws SwitchStateException
+         */
+        protected RoleReplyInfo extractOFRoleReply(OFChannelHandler h,
+                OFRoleReply rrmsg) throws SwitchStateException {
+            OFControllerRole cr = rrmsg.getRole();
+            Role role = null;
+            switch(cr) {
+            case ROLE_EQUAL:
+                role = Role.EQUAL;
+                break;
+            case ROLE_MASTER:
+                role = Role.MASTER;
+                break;
+            case ROLE_SLAVE:
+                role = Role.SLAVE;
+                break;
+            case ROLE_NOCHANGE: // switch should send current role
+            default:
+                String msg = String.format("Unknown controller role {} "
+                        + "received from switch {}", cr, h.sw);
+                throw new SwitchStateException(msg);
+            }
+
+            return new RoleReplyInfo(role, rrmsg.getGenerationId(), rrmsg.getXid());
+        }
+
+        /**
+         * Handles all pending port status messages before a switch is declared
+         * activated in MASTER or EQUAL role. Note that since this handling
+         * precedes the activation (and therefore notification to IOFSwitchListerners)
+         * the changes to ports will already be visible once the switch is
+         * activated. As a result, no notifications are sent out for these
+         * pending portStatus messages.
+         * @param h
+         * @throws SwitchStateException
+         */
+        protected void handlePendingPortStatusMessages(OFChannelHandler h) {
+            try {
+                handlePendingPortStatusMessages(h, 0);
+            } catch (SwitchStateException e) {
+                // do nothing - exception msg printed
+            }
+        }
+
+        private void handlePendingPortStatusMessages(OFChannelHandler h, int index)
+                throws SwitchStateException {
+            if (h.sw == null) {
+                String msg = "State machine error: switch is null. Should never " +
+                        "happen";
+                throw new SwitchStateException(msg);
+            }
+            ArrayList<OFPortStatus> temp  = new ArrayList<OFPortStatus>();
+            for (OFPortStatus ps: h.pendingPortStatusMsg) {
+                temp.add(ps);
+                handlePortStatusMessage(h, ps, false);
+            }
+            temp.clear();
+            // expensive but ok - we don't expect too many port-status messages
+            // note that we cannot use clear(), because of the reasons below
+            h.pendingPortStatusMsg.removeAll(temp);
+            // the iterator above takes a snapshot of the list - so while we were
+            // dealing with the pending port-status messages, we could have received
+            // newer ones. Handle them recursively, but break the recursion after
+            // five steps to avoid an attack.
+            if (!h.pendingPortStatusMsg.isEmpty() && ++index < 5) {
+                handlePendingPortStatusMessages(h, index);
+            }
+        }
+
+        /**
+         * Handle a port status message.
+         *
+         * Handle a port status message by updating the port maps in the
+         * IOFSwitch instance and notifying Controller about the change so
+         * it can dispatch a switch update.
+         *
+         * @param h The OFChannelHhandler that received the message
+         * @param m The PortStatus message we received
+         * @param doNotify if true switch port changed events will be
+         * dispatched
+         * @throws SwitchStateException
+         *
+         */
+        protected void handlePortStatusMessage(OFChannelHandler h, OFPortStatus m,
+                boolean doNotify) throws SwitchStateException {
+            if (h.sw == null) {
+                String msg = getSwitchStateMessage(h, m,
+                        "State machine error: switch is null. Should never " +
+                        "happen");
+                throw new SwitchStateException(msg);
+            }
+
+            Collection<PortChangeEvent> changes = h.sw.processOFPortStatus(m);
+            if (doNotify) {
+                for (PortChangeEvent ev: changes)
+                    h.controller.notifyPortChanged(h.sw.getId(), ev.port, ev.type);
+            }
+        }
+
+        /**
+         * Checks if the role received (from the role-reply msg) is different
+         * from the existing role in the IOFSwitch object for this controller.
+         * If so, it transitions the controller to the new role. Note that
+         * the caller should have already verified that the role-reply msg
+         * received was in response to a role-request msg sent out by this
+         * controller after hearing from the registry service.
+         *
+         * @param h the ChannelHandler that received the message
+         * @param role the role in the recieved role reply message
+         */
+        protected void checkAndSetRoleTransition(OFChannelHandler h, Role role) {
+		// we received a role-reply in response to a role message
+		// sent after hearing from the registry service. It is
+		// possible that the role of this controller instance for
+		// this switch has changed:
+		// for 1.0 switch: from MASTER to SLAVE
+		// for 1.3 switch: from MASTER to EQUAL
+		if ((h.sw.getRole() == Role.MASTER && role == Role.SLAVE) ||
+			(h.sw.getRole() == Role.MASTER && role == Role.EQUAL)) {
+			// the mastership has changed
+			h.sw.setRole(role);
+			h.setState(EQUAL);
+			h.controller.transitionToEqualSwitch(h.sw.getId());
+			return;
+		}
+
+		// or for both 1.0 and 1.3 switches from EQUAL to MASTER.
+		// note that for 1.0, even though we mean SLAVE,
+		// internally we call the role EQUAL.
+		if (h.sw.getRole() == Role.EQUAL && role == Role.MASTER) {
+			// the mastership has changed
+			h.sw.setRole(role);
+			h.setState(MASTER);
+			h.controller.transitionToMasterSwitch(h.sw.getId());
+			return;
+		}
+        }
+
+        /**
+         * Process an OF message received on the channel and
+         * update state accordingly.
+         *
+         * The main "event" of the state machine. Process the received message,
+         * send follow up message if required and update state if required.
+         *
+         * Switches on the message type and calls more specific event handlers
+         * for each individual OF message type. If we receive a message that
+         * is supposed to be sent from a controller to a switch we throw
+         * a SwitchStateExeption.
+         *
+         * The more specific handlers can also throw SwitchStateExceptions
+         *
+         * @param h The OFChannelHandler that received the message
+         * @param m The message we received.
+         * @throws SwitchStateException
+         * @throws IOException
+         */
+        void processOFMessage(OFChannelHandler h, OFMessage m)
+                throws IOException, SwitchStateException {
+            h.roleChanger.checkTimeout();
+            switch(m.getType()) {
+                case HELLO:
+                    processOFHello(h, (OFHello)m);
+                    break;
+                case BARRIER_REPLY:
+                    processOFBarrierReply(h, (OFBarrierReply)m);
+                    break;
+                case ECHO_REPLY:
+                    processOFEchoReply(h, (OFEchoReply)m);
+                    break;
+                case ECHO_REQUEST:
+                    processOFEchoRequest(h, (OFEchoRequest)m);
+                    break;
+                case ERROR:
+                    processOFError(h, (OFErrorMsg)m);
+                    break;
+                case FEATURES_REPLY:
+                    processOFFeaturesReply(h, (OFFeaturesReply)m);
+                    break;
+                case FLOW_REMOVED:
+                    processOFFlowRemoved(h, (OFFlowRemoved)m);
+                    break;
+                case GET_CONFIG_REPLY:
+                    processOFGetConfigReply(h, (OFGetConfigReply)m);
+                    break;
+                case PACKET_IN:
+                    processOFPacketIn(h, (OFPacketIn)m);
+                    break;
+                case PORT_STATUS:
+                    processOFPortStatus(h, (OFPortStatus)m);
+                    break;
+                case QUEUE_GET_CONFIG_REPLY:
+                    processOFQueueGetConfigReply(h, (OFQueueGetConfigReply)m);
+                    break;
+                case STATS_REPLY: // multipart_reply in 1.3
+                    processOFStatisticsReply(h, (OFStatsReply)m);
+                    break;
+                case EXPERIMENTER:
+                    processOFExperimenter(h, (OFExperimenter)m);
+                    break;
+                case ROLE_REPLY:
+                    processOFRoleReply(h, (OFRoleReply)m);
+                    break;
+                case GET_ASYNC_REPLY:
+                    processOFGetAsyncReply(h, (OFAsyncGetReply)m);
+                    break;
+
+                // The following messages are sent to switches. The controller
+                // should never receive them
+                case SET_CONFIG:
+                case GET_CONFIG_REQUEST:
+                case PACKET_OUT:
+                case PORT_MOD:
+                case QUEUE_GET_CONFIG_REQUEST:
+                case BARRIER_REQUEST:
+                case STATS_REQUEST: // multipart request in 1.3
+                case FEATURES_REQUEST:
+                case FLOW_MOD:
+                case GROUP_MOD:
+                case TABLE_MOD:
+                case GET_ASYNC_REQUEST:
+                case SET_ASYNC:
+                case METER_MOD:
+                default:
+                    illegalMessageReceived(h, m);
+                    break;
+            }
+        }
+
+        /*-----------------------------------------------------------------
+         * Default implementation for message handlers in any state.
+         *
+         * Individual states must override these if they want a behavior
+         * that differs from the default.
+         *
+         * In general, these handlers simply ignore the message and do
+         * nothing.
+         *
+         * There are some exceptions though, since some messages really
+         * are handled the same way in every state (e.g., ECHO_REQUST) or
+         * that are only valid in a single state (e.g., HELLO, GET_CONFIG_REPLY
+         -----------------------------------------------------------------*/
+
+        void processOFHello(OFChannelHandler h, OFHello m)
+                throws IOException, SwitchStateException {
+            // we only expect hello in the WAIT_HELLO state
+            illegalMessageReceived(h, m);
+        }
+
+        void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m)
+                throws IOException {
+            // Silently ignore.
+        }
+
+        void processOFEchoRequest(OFChannelHandler h, OFEchoRequest m)
+            throws IOException {
+            if (h.ofVersion == null) {
+                log.error("No OF version set for {}. Not sending Echo REPLY",
+                        h.channel.getRemoteAddress());
+                return;
+            }
+            OFFactory factory = (h.ofVersion == OFVersion.OF_13) ? factory13 : factory10;
+            OFEchoReply reply = factory
+                    .buildEchoReply()
+                    .setXid(m.getXid())
+                    .setData(m.getData())
+                    .build();
+            h.channel.write(Collections.singletonList(reply));
+        }
+
+        void processOFEchoReply(OFChannelHandler h, OFEchoReply m)
+            throws IOException {
+            // Do nothing with EchoReplies !!
+        }
+
+        // no default implementation for OFError
+        // every state must override it
+        abstract void processOFError(OFChannelHandler h, OFErrorMsg m)
+                throws IOException, SwitchStateException;
+
+
+        void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+                throws IOException, SwitchStateException {
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFFlowRemoved(OFChannelHandler h, OFFlowRemoved m)
+            throws IOException {
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFGetConfigReply(OFChannelHandler h, OFGetConfigReply m)
+                throws IOException, SwitchStateException {
+            // we only expect config replies in the WAIT_CONFIG_REPLY state
+            illegalMessageReceived(h, m);
+        }
+
+        void processOFPacketIn(OFChannelHandler h, OFPacketIn m)
+                throws IOException {
+            unhandledMessageReceived(h, m);
+        }
+
+        // no default implementation. Every state needs to handle it.
+        abstract void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+                throws IOException, SwitchStateException;
+
+        void processOFQueueGetConfigReply(OFChannelHandler h,
+                                          OFQueueGetConfigReply m)
+                throws IOException {
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
+                throws IOException, SwitchStateException {
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
+                throws IOException, SwitchStateException {
+            // TODO: it might make sense to parse the vendor message here
+            // into the known vendor messages we support and then call more
+            // specific event handlers
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
+                throws SwitchStateException, IOException {
+            unhandledMessageReceived(h, m);
+        }
+
+        void processOFGetAsyncReply(OFChannelHandler h,
+                OFAsyncGetReply m) {
+            unhandledMessageReceived(h, m);
+        }
+
+        void handleUnsentRoleMessage(OFChannelHandler h, Role role,
+			RoleRecvStatus expectation) throws IOException {
+		// do nothing in most states
+        }
+    }
+
+
+
+    //*************************
+    //  Channel handler methods
+    //*************************
+
+    @Override
+    @LogMessageDoc(message="New switch connection from {ip address}",
+                   explanation="A new switch has connected from the " +
+                            "specified IP address")
+    public void channelConnected(ChannelHandlerContext ctx,
+                                 ChannelStateEvent e) throws Exception {
+        counters.switchConnected.updateCounterWithFlush();
+        channel = e.getChannel();
+        log.info("New switch connection from {}",
+                 channel.getRemoteAddress());
+        sendHandshakeHelloMessage();
+        setState(ChannelState.WAIT_HELLO);
+    }
+
+    @Override
+    @LogMessageDoc(message="Disconnected switch {switch information}",
+                   explanation="The specified switch has disconnected.")
+    public void channelDisconnected(ChannelHandlerContext ctx,
+                                    ChannelStateEvent e) throws Exception {
+        log.info("Switch disconnected callback for sw:{}. Cleaning up ...",
+        		getSwitchInfoString());
+        if (thisdpid != 0) {
+        	if (duplicateDpidFound != Boolean.TRUE) {
+        		// if the disconnected switch (on this ChannelHandler)
+        		// was not one with a duplicate-dpid, it is safe to remove all
+        		// state for it at the controller. Notice that if the disconnected
+        		// switch was a duplicate-dpid, calling the method below would clear
+        		// all state for the original switch (with the same dpid),
+        		// which we obviously don't want.
+        		controller.removeConnectedSwitch(thisdpid);
+        	} else {
+        		// A duplicate was disconnected on this ChannelHandler,
+        		// this is the same switch reconnecting, but the original state was
+        		// not cleaned up - XXX check liveness of original ChannelHandler
+        		duplicateDpidFound = Boolean.FALSE;
+        	}
+        } else {
+        	log.warn("no dpid in channelHandler registered for "
+        			+ "disconnected switch {}", getSwitchInfoString());
+        }
+    }
+
+    @Override
+    @LogMessageDocs({
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch} due to read timeout",
+                explanation="The connected switch has failed to send any " +
+                            "messages or respond to echo requests",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch}: failed to " +
+                        "complete handshake",
+                explanation="The switch did not respond correctly " +
+                            "to handshake messages",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch} due to IO Error: {}",
+                explanation="There was an error communicating with the switch",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch} due to switch " +
+                        "state error: {error}",
+                explanation="The switch sent an unexpected message",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Disconnecting switch {switch} due to " +
+                        "message parse failure",
+                explanation="Could not parse a message from the switch",
+                recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+                message="Terminating controller due to storage exception",
+                explanation=Controller.ERROR_DATABASE,
+                recommendation=LogMessageDoc.CHECK_CONTROLLER),
+        @LogMessageDoc(level="ERROR",
+                message="Could not process message: queue full",
+                explanation="OpenFlow messages are arriving faster than " +
+                            " the controller can process them.",
+                recommendation=LogMessageDoc.CHECK_CONTROLLER),
+        @LogMessageDoc(level="ERROR",
+                message="Error while processing message " +
+                        "from switch {switch} {cause}",
+                explanation="An error occurred processing the switch message",
+                recommendation=LogMessageDoc.GENERIC_ACTION)
+    })
+    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
+            throws Exception {
+        if (e.getCause() instanceof ReadTimeoutException) {
+            // switch timeout
+            log.error("Disconnecting switch {} due to read timeout",
+                                 getSwitchInfoString());
+            counters.switchDisconnectReadTimeout.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof HandshakeTimeoutException) {
+            log.error("Disconnecting switch {}: failed to complete handshake",
+                      getSwitchInfoString());
+            counters.switchDisconnectHandshakeTimeout.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof ClosedChannelException) {
+            log.debug("Channel for sw {} already closed", getSwitchInfoString());
+        } else if (e.getCause() instanceof IOException) {
+            log.error("Disconnecting switch {} due to IO Error: {}",
+                      getSwitchInfoString(), e.getCause().getMessage());
+            if (log.isDebugEnabled()) {
+                // still print stack trace if debug is enabled
+                log.debug("StackTrace for previous Exception: ", e.getCause());
+            }
+            counters.switchDisconnectIOError.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof SwitchStateException) {
+            log.error("Disconnecting switch {} due to switch state error: {}",
+                      getSwitchInfoString(), e.getCause().getMessage());
+            if (log.isDebugEnabled()) {
+                // still print stack trace if debug is enabled
+                log.debug("StackTrace for previous Exception: ", e.getCause());
+            }
+            counters.switchDisconnectSwitchStateException.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof OFParseError) {
+            log.error("Disconnecting switch "
+                                 + getSwitchInfoString() +
+                                 " due to message parse failure",
+                                 e.getCause());
+            counters.switchDisconnectParseError.updateCounterWithFlush();
+            ctx.getChannel().close();
+        } else if (e.getCause() instanceof RejectedExecutionException) {
+            log.warn("Could not process message: queue full");
+            counters.rejectedExecutionException.updateCounterWithFlush();
+        } else {
+            log.error("Error while processing message from switch "
+                                 + getSwitchInfoString()
+                                 + "state " + this.state, e.getCause());
+            counters.switchDisconnectOtherException.updateCounterWithFlush();
+            ctx.getChannel().close();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getSwitchInfoString();
+    }
+
+    @Override
+    public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
+            throws Exception {
+        OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
+        OFMessage m = factory.buildEchoRequest().build();
+        log.info("Sending Echo Request on idle channel: {}",
+                e.getChannel().getPipeline().getLast().toString());
+        e.getChannel().write(Collections.singletonList(m));
+        // XXX S some problems here -- echo request has no transaction id, and
+        // echo reply is not correlated to the echo request.
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
+            throws Exception {
+        if (e.getMessage() instanceof List) {
+            @SuppressWarnings("unchecked")
+            List<OFMessage> msglist = (List<OFMessage>)e.getMessage();
+
+            LoadMonitor.LoadLevel loadlevel;
+            int packets_dropped = 0;
+            int packets_allowed = 0;
+            int lldps_allowed = 0;
+
+            if (this.controller.overload_drop) {
+                loadlevel = this.controller.loadmonitor.getLoadLevel();
+            }
+            else {
+                loadlevel = LoadMonitor.LoadLevel.OK;
+            }
+
+            for (OFMessage ofm : msglist) {
+                counters.messageReceived.updateCounterNoFlush();
+                // Per-switch input throttling - placeholder for future throttling
+                /*if (sw != null && sw.inputThrottled(ofm)) {
+                    counters.messageInputThrottled.updateCounterNoFlush();
+                    continue;
+                }*/
+                try {
+                    if (this.controller.overload_drop &&
+                        !loadlevel.equals(LoadMonitor.LoadLevel.OK)) {
+                        switch (ofm.getType()) {
+                        case PACKET_IN:
+                            switch (loadlevel) {
+                            case VERYHIGH:
+                                // Drop all packet-ins, including LLDP/BDDPs
+                                packets_dropped++;
+                                continue;
+                            case HIGH:
+                                // Drop all packet-ins, except LLDP/BDDPs
+                                byte[] data = ((OFPacketIn)ofm).getData();
+                                if (data.length > 14) {
+                                    if (((data[12] == (byte)0x88) &&
+                                         (data[13] == (byte)0xcc)) ||
+                                        ((data[12] == (byte)0x89) &&
+                                         (data[13] == (byte)0x42))) {
+                                        lldps_allowed++;
+                                        packets_allowed++;
+                                        break;
+                                    }
+                                }
+                                packets_dropped++;
+                                continue;
+                            default:
+                                // Load not high, go ahead and process msg
+                                packets_allowed++;
+                                break;
+                            }
+                            break;
+                        default:
+                            // Process all non-packet-ins
+                            packets_allowed++;
+                            break;
+                        }
+                    }
+
+                    // Do the actual packet processing
+                    state.processOFMessage(this, ofm);
+
+                }
+                catch (Exception ex) {
+                    // We are the last handler in the stream, so run the
+                    // exception through the channel again by passing in
+                    // ctx.getChannel().
+                    Channels.fireExceptionCaught(ctx.getChannel(), ex);
+                }
+            }
+
+            if (loadlevel != LoadMonitor.LoadLevel.OK) {
+                if (log.isDebugEnabled()) {
+                    log.debug(
+                        "Overload: Detected {}, packets dropped={}",
+                        loadlevel.toString(), packets_dropped);
+                    log.debug(
+                        "Overload: Packets allowed={} (LLDP/BDDPs allowed={})",
+                        packets_allowed, lldps_allowed);
+                }
+            }
+        }
+        else {
+            //Channels.fireExceptionCaught(ctx.getChannel(),
+            //      new AssertionError("Message received from Channel is not a list"));
+            //TODO: Pankaj: move the counters using ONOS metrics implementation
+
+            counters.messageReceived.updateCounterNoFlush();
+            state.processOFMessage(this, (OFMessage) e.getMessage());
+        }
+
+        // Flush all thread local queues etc. generated by this train
+        // of messages.
+        this.controller.flushAll();
+    }
+
+
+
+    //*************************
+    //  Channel utility methods
+    //*************************
+
+    /**
+     * Is this a state in which the handshake has completed?
+     * @return true if the handshake is complete
+     */
+    public boolean isHandshakeComplete() {
+        return this.state.isHandshakeComplete();
+    }
+
+    private void dispatchMessage(OFMessage m) throws IOException {
+        // handleMessage will count
+        this.controller.handleMessage(this.sw, m, null);
+    }
+
+    /**
+     * Return a string describing this switch based on the already available
+     * information (DPID and/or remote socket)
+     * @return
+     */
+    private String getSwitchInfoString() {
+        if (sw != null)
+            return sw.toString();
+        String channelString;
+        if (channel == null || channel.getRemoteAddress() == null) {
+            channelString = "?";
+        } else {
+            channelString = channel.getRemoteAddress().toString();
+        }
+        String dpidString;
+        if (featuresReply == null) {
+            dpidString = "?";
+        } else {
+            dpidString = featuresReply.getDatapathId().toString();
+        }
+        return String.format("[%s DPID[%s]]", channelString, dpidString);
+    }
+
+    /**
+     * Update the channels state. Only called from the state machine.
+     * TODO: enforce restricted state transitions
+     * @param state
+     */
+    private void setState(ChannelState state) {
+        this.state = state;
+    }
+
+    /**
+     * Send hello message to the switch using the handshake transactions ids.
+     * @throws IOException
+     */
+    private void sendHandshakeHelloMessage() throws IOException {
+        // The OF protocol requires us to start things off by sending the highest
+        // version of the protocol supported.
+
+        // bitmap represents OF1.0 (ofp_version=0x01) and OF1.3 (ofp_version=0x04)
+        // see Sec. 7.5.1 of the OF1.3.4 spec
+        U32 bitmap = U32.ofRaw(0x00000012);
+        OFHelloElem hem = factory13.buildHelloElemVersionbitmap()
+                .setBitmaps(Collections.singletonList(bitmap))
+                .build();
+        OFMessage.Builder mb = factory13.buildHello()
+                .setXid(this.handshakeTransactionIds--)
+                .setElements(Collections.singletonList(hem));
+        log.info("Sending OF_13 Hello to {}", channel.getRemoteAddress());
+        channel.write(Collections.singletonList(mb.build()));
+    }
+
+    /**
+     * Send featuresRequest msg to the switch using the handshake transactions ids.
+     * @throws IOException
+     */
+    private void sendHandshakeFeaturesRequestMessage() throws IOException {
+        OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
+        OFMessage m = factory.buildFeaturesRequest()
+                .setXid(this.handshakeTransactionIds--)
+                .build();
+        channel.write(Collections.singletonList(m));
+    }
+
+    private void setSwitchRole(Role role) {
+        sw.setRole(role);
+    }
+
+    /**
+     * Send the configuration requests to tell the switch we want full
+     * packets
+     * @throws IOException
+     */
+    private void sendHandshakeSetConfig() throws IOException {
+        OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
+        //log.debug("Sending CONFIG_REQUEST to {}", channel.getRemoteAddress());
+        List<OFMessage> msglist = new ArrayList<OFMessage>(3);
+
+        // Ensure we receive the full packet via PacketIn
+        // FIXME: We don't set the reassembly flags.
+        OFSetConfig sc = factory
+                .buildSetConfig()
+                .setMissSendLen((short) 0xffff)
+                .setXid(this.handshakeTransactionIds--)
+                .build();
+        msglist.add(sc);
+
+        // Barrier
+        OFBarrierRequest br = factory
+                .buildBarrierRequest()
+                .setXid(this.handshakeTransactionIds--)
+                .build();
+        msglist.add(br);
+
+        // Verify (need barrier?)
+        OFGetConfigRequest gcr = factory
+                .buildGetConfigRequest()
+                .setXid(this.handshakeTransactionIds--)
+                .build();
+        msglist.add(gcr);
+        channel.write(msglist);
+    }
+
+    /**
+     * send a description state request
+     * @throws IOException
+     */
+    private void sendHandshakeDescriptionStatsRequest() throws IOException {
+        // Get Description to set switch-specific flags
+        OFFactory factory = (ofVersion == OFVersion.OF_13) ? factory13 : factory10;
+        OFDescStatsRequest dreq = factory
+                .buildDescStatsRequest()
+                .setXid(handshakeTransactionIds--)
+                .build();
+        channel.write(Collections.singletonList(dreq));
+    }
+
+    private void sendHandshakeOFPortDescRequest() throws IOException {
+        // Get port description for 1.3 switch
+        OFPortDescStatsRequest preq = factory13
+                .buildPortDescStatsRequest()
+                .setXid(handshakeTransactionIds--)
+                .build();
+        channel.write(Collections.singletonList(preq));
+    }
+
+    /**
+     * Read switch properties from storage and set switch attributes accordingly
+     */
+    private void readPropertyFromStorage() {
+        // XXX This is a placeholder for switch configuration
+    }
+
+    ChannelState getStateForTesting() {
+        return state;
+    }
+
+    void useRoleChangerWithOtherTimeoutForTesting(long roleTimeoutMs) {
+        roleChanger = new RoleChanger(roleTimeoutMs);
+    }
+
+
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java
deleted file mode 100644
index 8130c0a..0000000
--- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- *    Copyright 2011, Big Switch Networks, Inc.
- *    Originally created by David Erickson, Stanford University
- *
- *    Licensed under the Apache License, Version 2.0 (the "License"); you may
- *    not use this file except in compliance with the License. You may obtain
- *    a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- *    License for the specific language governing permissions and limitations
- *    under the License.
- **/
-
-package net.floodlightcontroller.core.internal;
-
-/**
- * Wrapper class to hold state for the OpenFlow switch connection
- *
- * @author readams
- */
-class OFChannelState {
-
-    /**
-     * State for handling the switch handshake
-     */
-    protected enum HandshakeState {
-        /**
-         * Beginning state
-         */
-        START,
-
-        /**
-         * Received HELLO from switch
-         */
-        HELLO,
-
-        /**
-         * We've received the features reply
-         * Waiting for Config and Description reply
-         */
-        FEATURES_REPLY,
-
-        /**
-         * Switch is ready for processing messages
-         */
-        READY
-
-    }
-
-    protected volatile HandshakeState hsState = HandshakeState.START;
-    protected boolean hasGetConfigReply = false;
-    protected boolean hasDescription = false;
-
-    // The firstRoleReplyRecevied flag indicates if we have received the
-    // first role reply message on this connection (in response to the 
-    // role request sent after the handshake). If role support is disabled
-    // on the controller we also set this flag to true. 
-    // The flag is used to decide if the flow table should be wiped
-    // @see Controller.handleRoleReplyMessage()
-    protected boolean firstRoleReplyReceived = false;
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java b/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java
index 70ab58e..fa9f999 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFFeaturesReplyFuture.java
@@ -18,13 +18,13 @@
 
 import java.util.concurrent.TimeUnit;
 
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
+
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 
-import org.openflow.protocol.OFFeaturesReply;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
-
 /**
  * A concrete implementation that handles asynchronously receiving
  * OFFeaturesReply
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java b/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java
index 54fafd5..43257ca 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageDecoder.java
@@ -23,39 +23,35 @@
 import org.jboss.netty.channel.Channel;
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.handler.codec.frame.FrameDecoder;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.factory.BasicFactory;
-import org.openflow.protocol.factory.OFMessageFactory;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFMessageReader;
 
 /**
- * Decode an openflow message from a Channel, for use in a netty
- * pipeline
- *
- * @author readams
+ * Decode an openflow message from a Channel, for use in a netty pipeline
  */
 public class OFMessageDecoder extends FrameDecoder {
 
-    OFMessageFactory factory = new BasicFactory();
-
     @Override
     protected Object decode(ChannelHandlerContext ctx, Channel channel,
                             ChannelBuffer buffer) throws Exception {
         if (!channel.isConnected()) {
             // In testing, I see decode being called AFTER decode last.
-            // This check avoids that from reading curroupted frames
+            // This check avoids that from reading corrupted frames
             return null;
         }
 
-        List<OFMessage> message = factory.parseMessage(buffer);
-        return message;
-    }
+        // Note that a single call to decode results in reading a single
+        // OFMessage from the channel buffer, which is passed on to, and processed
+        // by, the controller (in OFChannelHandler).
+        // This is different from earlier behavior (with the original openflowj),
+        // where we parsed all the messages in the buffer, before passing on
+        // a list of the parsed messages to the controller.
+        // The performance *may or may not* not be as good as before.
+        OFMessageReader<OFMessage> reader = OFFactories.getGenericReader();
+		OFMessage message = reader.readFrom(buffer);
 
-    @Override
-    protected Object decodeLast(ChannelHandlerContext ctx, Channel channel,
-                                ChannelBuffer buffer) throws Exception {
-        // This is not strictly needed atthis time. It is used to detect
-        // connection reset detection from netty (for debug)
-        return null;
+		return message;
     }
 
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java b/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java
index 29916c8..fdd6686 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageEncoder.java
@@ -24,7 +24,8 @@
 import org.jboss.netty.channel.Channel;
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
-import org.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
 
 /**
  * Encode an openflow message for output into a ChannelBuffer, for use in a
@@ -42,12 +43,13 @@
 
         @SuppressWarnings("unchecked")
         List<OFMessage> msglist = (List<OFMessage>) msg;
+        /* XXX S can't get length of OFMessage in loxigen's openflowj??
         int size = 0;
         for (OFMessage ofm : msglist) {
             size += ofm.getLengthU();
-        }
+        }*/
 
-        ChannelBuffer buf = ChannelBuffers.buffer(size);
+        ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
 
         for (OFMessage ofm : msglist) {
             ofm.writeTo(buf);
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFMessageFuture.java b/src/main/java/net/floodlightcontroller/core/internal/OFMessageFuture.java
index 9e2a7ed..0d8d29f 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFMessageFuture.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFMessageFuture.java
@@ -23,11 +23,13 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
+
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
 
 /**
  * A Future object used to retrieve asynchronous OFMessage replies. Unregisters
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFStatisticsFuture.java b/src/main/java/net/floodlightcontroller/core/internal/OFStatisticsFuture.java
index 4651c74..91b81c1 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFStatisticsFuture.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFStatisticsFuture.java
@@ -24,10 +24,10 @@
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFStatisticsReply;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.statistics.OFStatistics;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
+import org.projectfloodlight.openflow.protocol.OFType;
 
 /**
  * A concrete implementation that handles asynchronously receiving OFStatistics
@@ -35,7 +35,7 @@
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
 public class OFStatisticsFuture extends
-        OFMessageFuture<List<OFStatistics>> {
+        OFMessageFuture<List<OFStatsReply>> {
 
     protected volatile boolean finished;
 
@@ -46,22 +46,23 @@
     }
 
     public OFStatisticsFuture(IThreadPoolService tp,
-                              IOFSwitch sw, int transactionId, long timeout, TimeUnit unit) {
+                              IOFSwitch sw, int transactionId, long timeout,
+                              TimeUnit unit) {
         super(tp, sw, OFType.STATS_REPLY, transactionId, timeout, unit);
         init();
     }
 
     private void init() {
         this.finished = false;
-        this.result = new CopyOnWriteArrayList<OFStatistics>();
+        this.result = new CopyOnWriteArrayList<OFStatsReply>();
     }
 
     @Override
     protected void handleReply(IOFSwitch sw, OFMessage msg) {
-        OFStatisticsReply sr = (OFStatisticsReply) msg;
+        OFStatsReply sr = (OFStatsReply) msg;
         synchronized (this.result) {
-            this.result.addAll(sr.getStatistics());
-            if ((sr.getFlags() & 0x1) == 0) {
+            this.result.add(sr);
+            if ( !(sr.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) ) {
                 this.finished = true;
             }
         }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
deleted file mode 100644
index 0bb9f2f..0000000
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ /dev/null
@@ -1,877 +0,0 @@
-/**
- *    Copyright 2012, Big Switch Networks, Inc.
- *    Originally created by David Erickson, Stanford University
- *
- *    Licensed under the Apache License, Version 2.0 (the "License"); you may
- *    not use this file except in compliance with the License. You may obtain
- *    a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- *    License for the specific language governing permissions and limitations
- *    under the License.
- **/
-
-package net.floodlightcontroller.core.internal;
-
-import java.io.IOException;
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.core.IFloodlightProviderService.Role;
-import net.floodlightcontroller.core.IOFMessageListener;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
-import net.floodlightcontroller.core.annotations.LogMessageDocs;
-import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
-import net.floodlightcontroller.threadpool.IThreadPoolService;
-import net.floodlightcontroller.util.TimedCache;
-
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
-import org.codehaus.jackson.map.ser.std.ToStringSerializer;
-import org.jboss.netty.channel.Channel;
-import org.openflow.protocol.OFFeaturesReply;
-import org.openflow.protocol.OFFeaturesRequest;
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
-import org.openflow.protocol.OFPhysicalPort.OFPortState;
-import org.openflow.protocol.OFPort;
-import org.openflow.protocol.OFStatisticsRequest;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.OFVendor;
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
-import org.openflow.protocol.statistics.OFStatistics;
-import org.openflow.util.HexString;
-import org.openflow.util.U16;
-import org.openflow.vendor.nicira.OFNiciraVendorData;
-import org.openflow.vendor.nicira.OFRoleRequestVendorData;
-import org.openflow.vendor.nicira.OFRoleVendorData;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-/**
- * This is the internal representation of an openflow switch.
- */
-public class OFSwitchImpl implements IOFSwitch {
-    // TODO: should we really do logging in the class or should we throw
-    // exception that can then be handled by callers?
-    protected final static Logger log = LoggerFactory.getLogger(OFSwitchImpl.class);
-
-    private static final String HA_CHECK_SWITCH =
-            "Check the health of the indicated switch.  If the problem " +
-                    "persists or occurs repeatedly, it likely indicates a defect " +
-                    "in the switch HA implementation.";
-
-    protected ConcurrentMap<Object, Object> attributes;
-    protected IFloodlightProviderService floodlightProvider;
-    protected IThreadPoolService threadPool;
-    protected Date connectedSince;
-    protected String stringId;
-    protected Channel channel;
-    protected AtomicInteger transactionIdSource;
-    // Lock to protect modification of the port maps. We only need to
-    // synchronize on modifications. For read operations we are fine since
-    // we rely on ConcurrentMaps which works for our use case.
-    private Object portLock;
-    // Map port numbers to the appropriate OFPhysicalPort
-    protected ConcurrentHashMap<Short, OFPhysicalPort> portsByNumber;
-    // Map port names to the appropriate OFPhyiscalPort
-    // XXX: The OF spec doesn't specify if port names need to be unique but
-    //      according it's always the case in practice.
-    protected ConcurrentHashMap<String, OFPhysicalPort> portsByName;
-    protected Map<Integer, OFStatisticsFuture> statsFutureMap;
-    protected Map<Integer, IOFMessageListener> iofMsgListenersMap;
-    protected Map<Integer, OFFeaturesReplyFuture> featuresFutureMap;
-    protected boolean connected;
-    protected Role role;
-    protected TimedCache<Long> timedCache;
-    protected ReentrantReadWriteLock listenerLock;
-    protected ConcurrentMap<Short, Long> portBroadcastCacheHitMap;
-    /**
-     * When sending a role request message, the role request is added
-     * to this queue. If a role reply is received this queue is checked to
-     * verify that the reply matches the expected reply. We require in order
-     * delivery of replies. That's why we use a Queue.
-     * The RoleChanger uses a timeout to ensure we receive a timely reply.
-     * <p/>
-     * Need to synchronize on this instance if a request is sent, received,
-     * checked.
-     */
-    protected LinkedList<PendingRoleRequestEntry> pendingRoleRequests;
-
-    /* Switch features from initial featuresReply */
-    protected int capabilities;
-    protected int buffers;
-    protected int actions;
-    protected byte tables;
-    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 WeakHashMap<OFSwitchImpl, List<OFMessage>>();
-                }
-            };
-
-    // for managing our map sizes
-    protected static final int MAX_MACS_PER_SWITCH = 1000;
-
-    protected static class PendingRoleRequestEntry {
-        protected int xid;
-        protected Role role;
-        // cookie is used to identify the role "generation". roleChanger uses
-        protected long cookie;
-
-        public PendingRoleRequestEntry(int xid, Role role, long cookie) {
-            this.xid = xid;
-            this.role = role;
-            this.cookie = cookie;
-        }
-    }
-
-    public OFSwitchImpl() {
-        this.stringId = null;
-        this.attributes = new ConcurrentHashMap<Object, Object>();
-        this.connectedSince = new Date();
-        this.transactionIdSource = new AtomicInteger();
-        this.portLock = new Object();
-        this.portsByNumber = new ConcurrentHashMap<Short, OFPhysicalPort>();
-        this.portsByName = new ConcurrentHashMap<String, OFPhysicalPort>();
-        this.connected = true;
-        this.statsFutureMap = new ConcurrentHashMap<Integer, OFStatisticsFuture>();
-        this.featuresFutureMap = new ConcurrentHashMap<Integer, OFFeaturesReplyFuture>();
-        this.iofMsgListenersMap = new ConcurrentHashMap<Integer, IOFMessageListener>();
-        this.role = null;
-        this.timedCache = new TimedCache<Long>(100, 5 * 1000);  // 5 seconds interval
-        this.listenerLock = new ReentrantReadWriteLock();
-        this.portBroadcastCacheHitMap = new ConcurrentHashMap<Short, Long>();
-        this.pendingRoleRequests = new LinkedList<OFSwitchImpl.PendingRoleRequestEntry>();
-
-        // Defaults properties for an ideal switch
-        this.setAttribute(PROP_FASTWILDCARDS, OFMatch.OFPFW_ALL);
-        this.setAttribute(PROP_SUPPORTS_OFPP_FLOOD, new Boolean(true));
-        this.setAttribute(PROP_SUPPORTS_OFPP_TABLE, new Boolean(true));
-    }
-
-
-    @Override
-    public Object getAttribute(String name) {
-        if (this.attributes.containsKey(name)) {
-            return this.attributes.get(name);
-        }
-        return null;
-    }
-
-    @Override
-    public void setAttribute(String name, Object value) {
-        this.attributes.put(name, value);
-        return;
-    }
-
-    @Override
-    public Object removeAttribute(String name) {
-        return this.attributes.remove(name);
-    }
-
-    @Override
-    public boolean hasAttribute(String name) {
-        return this.attributes.containsKey(name);
-    }
-
-    @Override
-    @JsonIgnore
-    public Channel getChannel() {
-        return this.channel;
-    }
-
-    @JsonIgnore
-    public void setChannel(Channel channel) {
-        this.channel = channel;
-    }
-
-    @Override
-    public void write(OFMessage m, FloodlightContext bc) throws IOException {
-        Map<OFSwitchImpl, List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
-        List<OFMessage> msg_buffer = msg_buffer_map.get(this);
-        if (msg_buffer == null) {
-            msg_buffer = new ArrayList<OFMessage>();
-            msg_buffer_map.put(this, msg_buffer);
-        }
-
-        this.floodlightProvider.handleOutgoingMessage(this, m, bc);
-        msg_buffer.add(m);
-
-        if ((msg_buffer.size() >= Controller.BATCH_MAX_SIZE) ||
-                ((m.getType() != OFType.PACKET_OUT) && (m.getType() != OFType.FLOW_MOD))) {
-            this.write(msg_buffer);
-            msg_buffer.clear();
-        }
-    }
-
-    @Override
-    @LogMessageDoc(level = "WARN",
-            message = "Sending OF message that modifies switch " +
-                    "state while in the slave role: {switch}",
-            explanation = "An application has sent a message to a switch " +
-                    "that is not valid when the switch is in a slave role",
-            recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG)
-    public void write(List<OFMessage> msglist,
-                      FloodlightContext bc) throws IOException {
-        for (OFMessage m : msglist) {
-            if (role == Role.SLAVE) {
-                switch (m.getType()) {
-                    case PACKET_OUT:
-                    case FLOW_MOD:
-                    case PORT_MOD:
-                        log.warn("Sending OF message that modifies switch " +
-                                "state while in the slave role: {}",
-                                m.getType().name());
-                        break;
-                    default:
-                        break;
-                }
-            }
-            this.floodlightProvider.handleOutgoingMessage(this, m, bc);
-        }
-        this.write(msglist);
-    }
-
-    public void write(List<OFMessage> msglist) throws IOException {
-        this.channel.write(msglist);
-    }
-
-    @Override
-    public void disconnectOutputStream() {
-        channel.close();
-    }
-
-    @Override
-    @JsonIgnore
-    public void setFeaturesReply(OFFeaturesReply featuresReply) {
-        synchronized (portLock) {
-            if (stringId == null) {
-                /* ports are updated via port status message, so we
-                 * only fill in ports on initial connection.
-                 */
-                for (OFPhysicalPort port : featuresReply.getPorts()) {
-                    setPort(port);
-                }
-            }
-            this.datapathId = featuresReply.getDatapathId();
-            this.capabilities = featuresReply.getCapabilities();
-            this.buffers = featuresReply.getBuffers();
-            this.actions = featuresReply.getActions();
-            this.tables = featuresReply.getTables();
-            this.stringId = HexString.toHexString(this.datapathId);
-        }
-    }
-
-    @Override
-    @JsonIgnore
-    public Collection<OFPhysicalPort> getEnabledPorts() {
-        List<OFPhysicalPort> result = new ArrayList<OFPhysicalPort>();
-        for (OFPhysicalPort port : portsByNumber.values()) {
-            if (portEnabled(port)) {
-                result.add(port);
-            }
-        }
-        return result;
-    }
-
-    @Override
-    @JsonIgnore
-    public Collection<Short> getEnabledPortNumbers() {
-        List<Short> result = new ArrayList<Short>();
-        for (OFPhysicalPort port : portsByNumber.values()) {
-            if (portEnabled(port)) {
-                result.add(port.getPortNumber());
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public OFPhysicalPort getPort(short portNumber) {
-        return portsByNumber.get(portNumber);
-    }
-
-    @Override
-    public OFPhysicalPort getPort(String portName) {
-        return portsByName.get(portName);
-    }
-
-    @Override
-    @JsonIgnore
-    public void setPort(OFPhysicalPort port) {
-        synchronized (portLock) {
-            portsByNumber.put(port.getPortNumber(), port);
-            portsByName.put(port.getName(), port);
-        }
-    }
-
-    @Override
-    @JsonProperty("ports")
-    public Collection<OFPhysicalPort> getPorts() {
-        return Collections.unmodifiableCollection(portsByNumber.values());
-    }
-
-    @Override
-    public void deletePort(short portNumber) {
-        synchronized (portLock) {
-            portsByName.remove(portsByNumber.get(portNumber).getName());
-            portsByNumber.remove(portNumber);
-        }
-    }
-
-    @Override
-    public void deletePort(String portName) {
-        synchronized (portLock) {
-            portsByNumber.remove(portsByName.get(portName).getPortNumber());
-            portsByName.remove(portName);
-        }
-    }
-
-    @Override
-    public boolean portEnabled(short portNumber) {
-        if (portsByNumber.get(portNumber) == null) return false;
-        return portEnabled(portsByNumber.get(portNumber));
-    }
-
-    @Override
-    public boolean portEnabled(String portName) {
-        if (portsByName.get(portName) == null) return false;
-        return portEnabled(portsByName.get(portName));
-    }
-
-    @Override
-    public boolean portEnabled(OFPhysicalPort port) {
-        if (port == null)
-            return false;
-        if ((port.getConfig() & OFPortConfig.OFPPC_PORT_DOWN.getValue()) > 0)
-            return false;
-        if ((port.getState() & OFPortState.OFPPS_LINK_DOWN.getValue()) > 0)
-            return false;
-        // Port STP state doesn't work with multiple VLANs, so ignore it for now
-        //if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue())
-        //    return false;
-        return true;
-    }
-
-    @Override
-    @JsonSerialize(using = DPIDSerializer.class)
-    @JsonProperty("dpid")
-    public long getId() {
-        if (this.stringId == null)
-            throw new RuntimeException("Features reply has not yet been set");
-        return this.datapathId;
-    }
-
-    @JsonIgnore
-    @Override
-    public String getStringId() {
-        return stringId;
-    }
-
-    /* (non-Javadoc)
-     * @see java.lang.Object#toString()
-     */
-    @Override
-    public String toString() {
-        return "OFSwitchImpl [" + ((channel != null) ? channel.getRemoteAddress() : "?") + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
-    }
-
-    @Override
-    public ConcurrentMap<Object, Object> getAttributes() {
-        return this.attributes;
-    }
-
-    @Override
-    public Date getConnectedSince() {
-        return connectedSince;
-    }
-
-    @JsonIgnore
-    @Override
-    public int getNextTransactionId() {
-        return this.transactionIdSource.incrementAndGet();
-    }
-
-    @Override
-    public void sendStatsQuery(OFStatisticsRequest request, int xid,
-                               IOFMessageListener caller) throws IOException {
-        request.setXid(xid);
-        this.iofMsgListenersMap.put(xid, caller);
-        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-        msglist.add(request);
-        this.channel.write(msglist);
-        return;
-    }
-
-    @Override
-    public Future<List<OFStatistics>> getStatistics(OFStatisticsRequest request) throws IOException {
-        request.setXid(getNextTransactionId());
-        OFStatisticsFuture future = new OFStatisticsFuture(threadPool, this, request.getXid());
-        this.statsFutureMap.put(request.getXid(), future);
-        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-        msglist.add(request);
-        this.channel.write(msglist);
-        return future;
-    }
-
-    @Override
-    public void deliverStatisticsReply(OFMessage reply) {
-        OFStatisticsFuture future = this.statsFutureMap.get(reply.getXid());
-        if (future != null) {
-            future.deliverFuture(this, reply);
-            // The future will ultimately unregister itself and call
-            // cancelStatisticsReply
-            return;
-        }
-        /* Transaction id was not found in statsFutureMap.check the other map */
-        IOFMessageListener caller = this.iofMsgListenersMap.get(reply.getXid());
-        if (caller != null) {
-            caller.receive(this, reply, null);
-        }
-    }
-
-    @Override
-    public void cancelStatisticsReply(int transactionId) {
-        if (null == this.statsFutureMap.remove(transactionId)) {
-            this.iofMsgListenersMap.remove(transactionId);
-        }
-    }
-
-    @Override
-    public void cancelAllStatisticsReplies() {
-        /* we don't need to be synchronized here. Even if another thread
-         * modifies the map while we're cleaning up the future will eventuall
-         * timeout */
-        for (OFStatisticsFuture f : statsFutureMap.values()) {
-            f.cancel(true);
-        }
-        statsFutureMap.clear();
-        iofMsgListenersMap.clear();
-    }
-
-
-    /**
-     * @param floodlightProvider the floodlightProvider to set
-     */
-    @JsonIgnore
-    public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) {
-        this.floodlightProvider = floodlightProvider;
-    }
-
-    @JsonIgnore
-    public void setThreadPoolService(IThreadPoolService tp) {
-        this.threadPool = tp;
-    }
-
-    @JsonIgnore
-    @Override
-    public synchronized boolean isConnected() {
-        return connected;
-    }
-
-    @Override
-    @JsonIgnore
-    public synchronized void setConnected(boolean connected) {
-        this.connected = connected;
-    }
-
-    @Override
-    public Role getRole() {
-        return role;
-    }
-
-    @JsonIgnore
-    @Override
-    public boolean isActive() {
-        return (role != Role.SLAVE);
-    }
-
-    @Override
-    @JsonIgnore
-    public void setSwitchProperties(OFDescriptionStatistics description) {
-        if (switchFeatures != null) {
-            switchFeatures.setFromDescription(this, description);
-        }
-    }
-
-    @Override
-    @LogMessageDoc(level = "ERROR",
-            message = "Failed to clear all flows on switch {switch}",
-            explanation = "An I/O error occured while trying to clear " +
-                    "flows on the switch.",
-            recommendation = LogMessageDoc.CHECK_SWITCH)
-    public void clearAllFlowMods() {
-        // Delete all pre-existing flows
-        OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
-        OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory()
-                .getMessage(OFType.FLOW_MOD))
-                .setMatch(match)
-                .setCommand(OFFlowMod.OFPFC_DELETE)
-                .setOutPort(OFPort.OFPP_NONE)
-                .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
-        try {
-            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-            msglist.add(fm);
-            channel.write(msglist);
-        } catch (Exception e) {
-            log.error("Failed to clear all flows on switch " + this, e);
-        }
-    }
-
-    @Override
-    public boolean updateBroadcastCache(Long entry, Short port) {
-        if (timedCache.update(entry)) {
-            Long count = portBroadcastCacheHitMap.putIfAbsent(port, new Long(1));
-            if (count != null) {
-                count++;
-            }
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    @JsonIgnore
-    public Map<Short, Long> getPortBroadcastHits() {
-        return this.portBroadcastCacheHitMap;
-    }
-
-
-    @Override
-    public void flush() {
-        Map<OFSwitchImpl, List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
-        List<OFMessage> msglist = msg_buffer_map.get(this);
-        if ((msglist != null) && (msglist.size() > 0)) {
-            try {
-                this.write(msglist);
-            } catch (IOException e) {
-                log.error("Failed flushing messages", e);
-            }
-            msglist.clear();
-        }
-    }
-
-    public static void flush_all() {
-        Map<OFSwitchImpl, List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
-        for (OFSwitchImpl sw : msg_buffer_map.keySet()) {
-            sw.flush();
-        }
-    }
-
-    /**
-     * Return a read lock that must be held while calling the listeners for
-     * messages from the switch. Holding the read lock prevents the active
-     * switch list from being modified out from under the listeners.
-     *
-     * @return
-     */
-    @JsonIgnore
-    public Lock getListenerReadLock() {
-        return listenerLock.readLock();
-    }
-
-    /**
-     * Return a write lock that must be held when the controllers modifies the
-     * list of active switches. This is to ensure that the active switch list
-     * doesn't change out from under the listeners as they are handling a
-     * message from the switch.
-     *
-     * @return
-     */
-    @JsonIgnore
-    public Lock getListenerWriteLock() {
-        return listenerLock.writeLock();
-    }
-
-    /**
-     * Get the IP Address for the switch
-     *
-     * @return the inet address
-     */
-    @JsonSerialize(using = ToStringSerializer.class)
-    public SocketAddress getInetAddress() {
-        return channel.getRemoteAddress();
-    }
-
-    /**
-     * Send NX role request message to the switch requesting the specified role.
-     * <p/>
-     * This method should ONLY be called by @see RoleChanger.submitRequest().
-     * <p/>
-     * After sending the request add it to the queue of pending request. We
-     * use the queue to later verify that we indeed receive the correct reply.
-     *
-     * @param sw     switch to send the role request message to
-     * @param role   role to request
-     * @param cookie an opaque value that will be stored in the pending queue so
-     *               RoleChanger can check for timeouts.
-     * @return transaction id of the role request message that was sent
-     */
-    protected int sendNxRoleRequest(Role role, long cookie)
-            throws IOException {
-        synchronized (pendingRoleRequests) {
-            // Convert the role enum to the appropriate integer constant used
-            // in the NX role request message
-            int nxRole = 0;
-            switch (role) {
-                case EQUAL:
-                    nxRole = OFRoleVendorData.NX_ROLE_OTHER;
-                    break;
-                case MASTER:
-                    nxRole = OFRoleVendorData.NX_ROLE_MASTER;
-                    break;
-                case SLAVE:
-                    nxRole = OFRoleVendorData.NX_ROLE_SLAVE;
-                    break;
-                default:
-                    log.error("Invalid Role specified for switch {}."
-                            + " Disconnecting.", this);
-                    // TODO: should throw an error
-                    return 0;
-            }
-
-            // Construct the role request message
-            OFVendor roleRequest = (OFVendor) floodlightProvider.
-                    getOFMessageFactory().getMessage(OFType.VENDOR);
-            int xid = this.getNextTransactionId();
-            roleRequest.setXid(xid);
-            roleRequest.setVendor(OFNiciraVendorData.NX_VENDOR_ID);
-            OFRoleRequestVendorData roleRequestData = new OFRoleRequestVendorData();
-            roleRequestData.setRole(nxRole);
-            roleRequest.setVendorData(roleRequestData);
-            roleRequest.setLengthU(OFVendor.MINIMUM_LENGTH +
-                    roleRequestData.getLength());
-
-            // Send it to the switch
-            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-            msglist.add(roleRequest);
-            // FIXME: should this use this.write() in order for messages to
-            // be processed by handleOutgoingMessage()
-            this.channel.write(msglist);
-
-            pendingRoleRequests.add(new PendingRoleRequestEntry(xid, role, cookie));
-            return xid;
-        }
-    }
-
-    /**
-     * Deliver a RoleReply message to this switch. Checks if the reply
-     * message matches the expected reply (head of the pending request queue).
-     * We require in-order delivery of replies. If there's any deviation from
-     * our expectations we disconnect the switch.
-     * <p/>
-     * We must not check the received role against the controller's current
-     * role because there's no synchronization but that's fine @see RoleChanger
-     * <p/>
-     * Will be called by the OFChannelHandler's receive loop
-     *
-     * @param xid  Xid of the reply message
-     * @param role The Role in the the reply message
-     */
-    @LogMessageDocs({
-            @LogMessageDoc(level = "ERROR",
-                    message = "Switch {switch}: received unexpected role reply for " +
-                            "Role {role}" +
-                            " Disconnecting switch",
-                    explanation = "The switch sent an unexpected HA role reply",
-                    recommendation = HA_CHECK_SWITCH),
-            @LogMessageDoc(level = "ERROR",
-                    message = "Switch {switch}: expected role reply with " +
-                            "Xid {xid}, got {xid}. Disconnecting switch",
-                    explanation = "The switch sent an unexpected HA role reply",
-                    recommendation = HA_CHECK_SWITCH),
-            @LogMessageDoc(level = "ERROR",
-                    message = "Switch {switch}: expected role reply with " +
-                            "Role {role}, got {role}. Disconnecting switch",
-                    explanation = "The switch sent an unexpected HA role reply",
-                    recommendation = HA_CHECK_SWITCH)
-    })
-    protected void deliverRoleReply(int xid, Role role) {
-        synchronized (pendingRoleRequests) {
-            PendingRoleRequestEntry head = pendingRoleRequests.poll();
-            if (head == null) {
-                // Maybe don't disconnect if the role reply we received is
-                // for the same role we are already in.
-                log.error("Switch {}: received unexpected role reply for Role {}" +
-                        " Disconnecting switch", this, role);
-                this.channel.close();
-            } else if (head.xid != xid) {
-                // check xid before role!!
-                log.error("Switch {}: expected role reply with " +
-                        "Xid {}, got {}. Disconnecting switch",
-                        new Object[]{this, head.xid, xid});
-                this.channel.close();
-            } else if (head.role != role) {
-                log.error("Switch {}: expected role reply with " +
-                        "Role {}, got {}. Disconnecting switch",
-                        new Object[]{this, head.role, role});
-                this.channel.close();
-            } else {
-                log.debug("Received role reply message from {}, setting role to {}",
-                        this, role);
-                if (this.role == null && getAttribute(SWITCH_SUPPORTS_NX_ROLE) == null) {
-                    // The first role reply we received. Set the attribute
-                    // that the switch supports roles
-                    setAttribute(SWITCH_SUPPORTS_NX_ROLE, true);
-                }
-                this.role = role;
-            }
-        }
-    }
-
-    /**
-     * Checks whether the given xid matches the xid of the first pending
-     * role request.
-     *
-     * @param xid
-     * @return
-     */
-    protected boolean checkFirstPendingRoleRequestXid(int xid) {
-        synchronized (pendingRoleRequests) {
-            PendingRoleRequestEntry head = pendingRoleRequests.peek();
-            if (head == null)
-                return false;
-            else
-                return head.xid == xid;
-        }
-    }
-
-    /**
-     * Checks whether the given request cookie matches the cookie of the first
-     * pending request
-     *
-     * @param cookie
-     * @return
-     */
-    protected boolean checkFirstPendingRoleRequestCookie(long cookie) {
-        synchronized (pendingRoleRequests) {
-            PendingRoleRequestEntry head = pendingRoleRequests.peek();
-            if (head == null)
-                return false;
-            else
-                return head.cookie == cookie;
-        }
-    }
-
-    /**
-     * Called if we receive a vendor error message indicating that roles
-     * are not supported by the switch. If the xid matches the first pending
-     * one, we'll mark the switch as not supporting roles and remove the head.
-     * Otherwise we ignore it.
-     *
-     * @param xid
-     */
-    protected void deliverRoleRequestNotSupported(int xid) {
-        deliverRoleRequestNotSupportedEx(xid);
-    }
-
-    /**
-     * ONOS Extension to deliverRoleRequestNotSupported().
-     * This version return the Roll request made.
-     *
-     * @param xid
-     * @return Role of attempted RoleRequest.
-     * @see deliverRoleRequestNotSupported
-     */
-    protected Role deliverRoleRequestNotSupportedEx(int xid) {
-        synchronized (pendingRoleRequests) {
-            PendingRoleRequestEntry head = pendingRoleRequests.poll();
-            this.role = null;
-            if (head != null && head.xid == xid) {
-                setAttribute(SWITCH_SUPPORTS_NX_ROLE, false);
-                return head.role;
-            } else {
-                log.debug("Closing {} because a role request error didn't match " +
-                        "head of pendingRoleRequests queue", this);
-                this.channel.close();
-                return null;
-            }
-        }
-    }
-
-    @Override
-    public Future<OFFeaturesReply> getFeaturesReplyFromSwitch()
-            throws IOException {
-        OFMessage request = new OFFeaturesRequest();
-        request.setXid(getNextTransactionId());
-        OFFeaturesReplyFuture future =
-                new OFFeaturesReplyFuture(threadPool, this, request.getXid());
-        this.featuresFutureMap.put(request.getXid(), future);
-        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-        msglist.add(request);
-        this.channel.write(msglist);
-        return future;
-    }
-
-    @Override
-    public void deliverOFFeaturesReply(OFMessage reply) {
-        OFFeaturesReplyFuture future = this.featuresFutureMap.get(reply.getXid());
-        if (future != null) {
-            future.deliverFuture(this, reply);
-            // The future will ultimately unregister itself and call
-            // cancelFeaturesReply
-            return;
-        }
-        log.error("Switch {}: received unexpected featureReply", this);
-    }
-
-    @Override
-    public void cancelFeaturesReply(int transactionId) {
-        this.featuresFutureMap.remove(transactionId);
-    }
-
-
-    @Override
-    public int getBuffers() {
-        return buffers;
-    }
-
-
-    @Override
-    public int getActions() {
-        return actions;
-    }
-
-
-    @Override
-    public int getCapabilities() {
-        return capabilities;
-    }
-
-
-    @Override
-    public byte getTables() {
-        return tables;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImplBase.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImplBase.java
new file mode 100644
index 0000000..c3d6e63
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImplBase.java
@@ -0,0 +1,1288 @@
+package net.floodlightcontroller.core.internal;
+
+/**
+ *    Copyright 2012, Big Switch Networks, Inc.
+ *    Originally created by David Erickson, Stanford University
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.IOFMessageListener;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
+import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
+import net.floodlightcontroller.debugcounter.IDebugCounter;
+import net.floodlightcontroller.debugcounter.IDebugCounterService;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
+import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
+import net.floodlightcontroller.debugcounter.NullDebugCounter;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.util.LinkedHashSetWrapper;
+import net.floodlightcontroller.util.OrderedCollection;
+import net.floodlightcontroller.util.TimedCache;
+
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.jboss.netty.channel.Channel;
+import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.projectfloodlight.openflow.protocol.OFCapabilities;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortConfig;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFPortReason;
+import org.projectfloodlight.openflow.protocol.OFPortState;
+import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFAuxId;
+import org.projectfloodlight.openflow.types.OFGroup;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
+import org.projectfloodlight.openflow.types.U64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This is the internal representation of an openflow switch.
+ */
+public class OFSwitchImplBase implements IOFSwitch {
+    // TODO: should we really do logging in the class or should we throw
+    // exception that can then be handled by callers?
+    protected final static Logger log = LoggerFactory.getLogger(OFSwitchImplBase.class);
+
+    private static final String HA_CHECK_SWITCH =
+            "Check the health of the indicated switch.  If the problem " +
+                    "persists or occurs repeatedly, it likely indicates a defect " +
+                    "in the switch HA implementation.";
+
+    protected ConcurrentMap<Object, Object> attributes;
+    protected IFloodlightProviderService floodlightProvider;
+    protected IThreadPoolService threadPool;
+    protected Date connectedSince;
+    protected String stringId;
+    protected Channel channel;
+    // transaction id used for messages sent out to this switch from
+    // this controller instance. This xid has significance only between this
+    // controller<->switch pair.
+    protected AtomicInteger transactionIdSource;
+
+    // generation id used for roleRequest messages sent to switches (see section
+    // 6.3.5 of the OF1.3.4 spec). This generationId has significance between
+    // all the controllers that this switch is connected to; and only for role
+    // request messages with role MASTER or SLAVE. The set of Controllers that
+    // this switch is connected to should coordinate the next generation id,
+    // via transactional semantics.
+    protected long generationIdSource;
+
+    // Lock to protect modification of the port maps. We only need to
+    // synchronize on modifications. For read operations we are fine since
+    // we rely on ConcurrentMaps which works for our use case.
+    //private Object portLock; XXX S remove this
+
+    // Map port numbers to the appropriate OFPortDesc
+    protected ConcurrentHashMap<Integer, OFPortDesc> portsByNumber;
+    // Map port names to the appropriate OFPhyiscalPort
+    // XXX: The OF spec doesn't specify if port names need to be unique but
+    //      according it's always the case in practice.
+    protected ConcurrentHashMap<String, OFPortDesc> portsByName;
+    protected Map<Integer, OFStatisticsFuture> statsFutureMap;
+    protected Map<Integer, IOFMessageListener> iofMsgListenersMap; // XXX S why is this needed?
+    protected Map<Integer, OFFeaturesReplyFuture> featuresFutureMap;
+    protected boolean connected;
+    protected Role role;
+    protected TimedCache<Long> timedCache;
+    protected ReentrantReadWriteLock listenerLock;
+    protected ConcurrentMap<Short, Long> portBroadcastCacheHitMap;
+    /**
+     * When sending a role request message, the role request is added
+     * to this queue. If a role reply is received this queue is checked to
+     * verify that the reply matches the expected reply. We require in order
+     * delivery of replies. That's why we use a Queue.
+     * The RoleChanger uses a timeout to ensure we receive a timely reply.
+     * <p/>
+     * Need to synchronize on this instance if a request is sent, received,
+     * checked.
+     */
+    protected LinkedList<PendingRoleRequestEntry> pendingRoleRequests;
+
+    /** OpenFlow version for this switch */
+    protected OFVersion ofversion;
+    // Description stats reply describing this switch
+    private OFDescStatsReply switchDescription;
+    // Switch features from initial featuresReply
+    protected Set<OFCapabilities> capabilities;
+    protected int buffers;
+    protected Set<OFActionType> actions;
+    protected byte tables;
+    protected DatapathId datapathId;
+	private OFAuxId auxId;
+
+    private IDebugCounterService debugCounters;
+	private boolean debugCountersRegistered;
+	@SuppressWarnings("unused")
+    private IDebugCounter ctrSwitch, ctrSwitchPktin, ctrSwitchWrite,
+    ctrSwitchPktinDrops, ctrSwitchWriteDrops;
+
+	protected boolean startDriverHandshakeCalled = false;
+	private boolean flowTableFull = false;
+
+	private final PortManager portManager;
+
+
+
+    protected static final ThreadLocal<Map<OFSwitchImplBase, List<OFMessage>>> local_msg_buffer =
+		new ThreadLocal<Map<OFSwitchImplBase, List<OFMessage>>>() {
+	@Override
+	protected Map<OFSwitchImplBase, List<OFMessage>> initialValue() {
+		return new WeakHashMap<OFSwitchImplBase, List<OFMessage>>();
+	}
+    };
+
+
+	private static final String BASE = "switchbase";
+
+    protected static class PendingRoleRequestEntry {
+        protected int xid;
+        protected Role role;
+        // cookie is used to identify the role "generation". roleChanger uses
+        protected long cookie;
+
+        public PendingRoleRequestEntry(int xid, Role role, long cookie) {
+            this.xid = xid;
+            this.role = role;
+            this.cookie = cookie;
+        }
+    }
+
+    public OFSwitchImplBase() {
+        this.stringId = null;
+        this.attributes = new ConcurrentHashMap<Object, Object>();
+        this.connectedSince = new Date();
+        this.transactionIdSource = new AtomicInteger();
+        this.generationIdSource = 0; // XXX S this is wrong; should be negotiated
+        // XXX S no need this.portLock = new Object();
+        this.portsByNumber = new ConcurrentHashMap<Integer, OFPortDesc>();
+        this.portsByName = new ConcurrentHashMap<String, OFPortDesc>();
+        this.connected = true;
+        this.statsFutureMap = new ConcurrentHashMap<Integer, OFStatisticsFuture>();
+        this.featuresFutureMap = new ConcurrentHashMap<Integer, OFFeaturesReplyFuture>();
+        this.iofMsgListenersMap = new ConcurrentHashMap<Integer, IOFMessageListener>();
+        this.role = null;
+        this.timedCache = new TimedCache<Long>(100, 5 * 1000);  // 5 seconds interval
+        this.listenerLock = new ReentrantReadWriteLock();
+        this.pendingRoleRequests = new LinkedList<OFSwitchImplBase.PendingRoleRequestEntry>();
+        this.portManager = new PortManager();
+        // by default the base impl declares no support for Nx_role_requests.
+        // OF1.0 switches like OVS that do support these messages should set the
+        // attribute in the associated switch driver.
+        setAttribute(SWITCH_SUPPORTS_NX_ROLE, false);
+
+    }
+
+    //*******************************************
+    //    Setters and Getters
+    //*******************************************
+
+    @Override
+    public Object getAttribute(String name) {
+        if (this.attributes.containsKey(name)) {
+            return this.attributes.get(name);
+        }
+        return null;
+    }
+
+    @Override
+    public ConcurrentMap<Object, Object> getAttributes() {
+        return this.attributes;
+    }
+
+    @Override
+    public void setAttribute(String name, Object value) {
+        this.attributes.put(name, value);
+        return;
+    }
+
+    @Override
+    public Object removeAttribute(String name) {
+        return this.attributes.remove(name);
+    }
+
+    @Override
+    public boolean hasAttribute(String name) {
+        return this.attributes.containsKey(name);
+    }
+
+    @Override
+    @JsonSerialize(using = DPIDSerializer.class)
+    @JsonProperty("dpid")
+    public long getId() {
+        if (this.stringId == null)
+            throw new RuntimeException("Features reply has not yet been set");
+        return this.datapathId.getLong();
+    }
+
+    @JsonIgnore
+    @Override
+    public String getStringId() {
+        return stringId;
+    }
+
+    /** Retrieve the openflow version (eg. OF1.0, OF1.3) for this switch
+     */
+    public OFVersion getOFVersion() {
+	return ofversion;
+    }
+
+    public void setOFVersion(OFVersion ofv) {
+	ofversion = ofv;
+    }
+
+    /**
+     * @param floodlightProvider the floodlightProvider to set
+     */
+    @JsonIgnore
+    @Override
+    public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) {
+        this.floodlightProvider = floodlightProvider;
+    }
+
+    @JsonIgnore
+    @Override
+    public void setThreadPoolService(IThreadPoolService tp) {
+        this.threadPool = tp;
+    }
+
+    @Override
+    @JsonIgnore
+    public void setDebugCounterService(IDebugCounterService debugCounters)
+            throws CounterException {
+        this.debugCounters = debugCounters;
+        registerOverloadCounters();
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "OFSwitchImpl [" + ((channel != null) ? channel.getRemoteAddress() : "?")
+			+ " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
+    }
+
+
+    //*******************************************
+    //    Channel related methods
+    //*******************************************
+
+    @JsonIgnore
+    @Override
+    public void setChannel(Channel channel) {
+        this.channel = channel;
+    }
+
+    @Override
+    public void write(OFMessage m, FloodlightContext bc) throws IOException {
+        Map<OFSwitchImplBase, List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        List<OFMessage> msg_buffer = msg_buffer_map.get(this);
+        if (msg_buffer == null) {
+            msg_buffer = new ArrayList<OFMessage>();
+            msg_buffer_map.put(this, msg_buffer);
+        }
+        // XXX S will change when iFloodlight provider changes
+        //this.floodlightProvider.handleOutgoingMessage(this, m, bc);
+        msg_buffer.add(m);
+
+        if ((msg_buffer.size() >= Controller.BATCH_MAX_SIZE) ||
+                ((m.getType() != OFType.PACKET_OUT) && (m.getType() != OFType.FLOW_MOD))) {
+            this.write(msg_buffer);
+            msg_buffer.clear();
+        }
+    }
+
+    @Override
+    @LogMessageDoc(level = "WARN",
+            message = "Sending OF message that modifies switch " +
+                    "state while in the slave role: {switch}",
+            explanation = "An application has sent a message to a switch " +
+                    "that is not valid when the switch is in a slave role",
+            recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG)
+    public void write(List<OFMessage> msglist,
+                      FloodlightContext bc) throws IOException {
+        for (OFMessage m : msglist) {
+            if (role == Role.SLAVE) {
+                switch (m.getType()) {
+                    case PACKET_OUT:
+                    case FLOW_MOD:
+                    case PORT_MOD:
+                        log.warn("Sending OF message that modifies switch " +
+                                "state while in the slave role: {}",
+                                m.getType().name());
+                        break;
+                    default:
+                        break;
+                }
+            }
+            // XXX S again
+            //this.floodlightProvider.handleOutgoingMessage(this, m, bc);
+        }
+        this.write(msglist);
+    }
+
+    public void write(List<OFMessage> msglist) throws IOException {
+        this.channel.write(msglist);
+    }
+
+    @Override
+    public void disconnectSwitch() {
+        channel.close();
+    }
+
+    @Override
+    public Date getConnectedSince() {
+        return connectedSince;
+    }
+
+    @JsonIgnore
+    @Override
+    public int getNextTransactionId() {
+        return this.transactionIdSource.incrementAndGet();
+    }
+
+    @JsonIgnore
+    @Override
+    public synchronized boolean isConnected() {
+        return connected;
+    }
+
+    @Override
+    @JsonIgnore
+    public synchronized void setConnected(boolean connected) {
+        this.connected = connected;
+    }
+
+
+
+    //*******************************************
+    //    Switch features related methods
+    //*******************************************
+
+    /**
+     * Set the features reply for this switch from the handshake
+     */
+    protected void setFeaturesReply(OFFeaturesReply featuresReply) {
+	if (featuresReply == null) {
+		log.error("Error setting featuresReply for switch: {}", getStringId());
+		return;
+	}
+	this.datapathId = featuresReply.getDatapathId();
+	this.capabilities = featuresReply.getCapabilities();
+	this.buffers = (int) featuresReply.getNBuffers();
+	this.tables = (byte) featuresReply.getNTables();
+	this.stringId = this.datapathId.toString();
+	if (ofversion == OFVersion.OF_13) {
+		auxId = featuresReply.getAuxiliaryId();
+		if (!auxId.equals(OFAuxId.MAIN)) {
+			log.warn("This controller does not handle auxiliary connections. "
+					+ "Aux connection id {} received from switch {}",
+					auxId, getStringId());
+		}
+	}
+
+	if (ofversion == OFVersion.OF_10) {
+		this.actions = featuresReply.getActions();
+		portManager.compareAndUpdatePorts(featuresReply.getPorts(), true);
+	}
+    }
+
+    /**
+     * Set the port descriptions for this switch from the handshake for
+     * an OF1.3 switch.
+     */
+    protected void setPortDescReply(OFPortDescStatsReply pdrep) {
+	if (ofversion != OFVersion.OF_13) return;
+	if (pdrep == null) {
+		log.error("Error setting ports description for switch: {}", getStringId());
+		return;
+	}
+	portManager.updatePorts(pdrep.getEntries());
+    }
+
+    @Override
+    public int getNumBuffers() {
+        return buffers;
+    }
+    @Override
+    public Set<OFActionType> getActions() {
+        return actions;
+    }
+    @Override
+    public  Set<OFCapabilities> getCapabilities() {
+        return capabilities;
+    }
+    @Override
+    public byte getNumTables() {
+        return tables;
+    }
+
+//    public Future<OFFeaturesReply> getFeaturesReplyFromSwitch()
+//            throws IOException {
+//    	// XXX S fix this later
+//    	OFMessage request = floodlightProvider.getOFMessageFactory_13()
+//    			.buildFeaturesRequest()
+//    			.setXid(getNextTransactionId())
+//    			.build();
+//    	OFFeaturesReplyFuture future =
+//                new OFFeaturesReplyFuture(threadPool, this, (int) request.getXid());
+//        this.featuresFutureMap.put((int) request.getXid(), future);
+//        this.channel.write(Collections.singletonList(request));
+//        return future;
+//
+//    }
+//
+//    public void deliverOFFeaturesReply(OFMessage reply) {
+//        OFFeaturesReplyFuture future = this.featuresFutureMap.get(reply.getXid());
+//        if (future != null) {
+//            future.deliverFuture(this, reply);
+//            // The future will ultimately unregister itself and call
+//            // cancelFeaturesReply
+//            return;
+//        }
+//        log.error("Switch {}: received unexpected featureReply", this);
+//    }
+
+    @Override
+    public void cancelFeaturesReply(int transactionId) {
+        this.featuresFutureMap.remove(transactionId);
+    }
+
+    @JsonIgnore
+    public void setSwitchDescription(OFDescStatsReply desc) {
+	switchDescription = desc;
+    }
+
+    @Override
+    @JsonIgnore
+    public OFDescStatsReply getSwitchDescription() {
+	return switchDescription;
+    }
+
+    //*******************************************
+    //    Switch port handling
+    //*******************************************
+
+    @Override
+    @JsonIgnore
+    public Collection<OFPortDesc> getEnabledPorts() {
+        return portManager.getEnabledPorts();
+    }
+
+    @Override
+    @JsonIgnore
+    public Collection<Integer> getEnabledPortNumbers() {
+        return portManager.getEnabledPortNumbers();
+    }
+
+    @Override
+    public OFPortDesc getPort(int portNumber) {
+        return portManager.getPort(portNumber);
+    }
+
+    @Override
+    public OFPortDesc getPort(String portName) {
+        return portManager.getPort(portName);
+    }
+
+    @Override
+    @JsonIgnore
+    public OrderedCollection<PortChangeEvent> processOFPortStatus(OFPortStatus ps) {
+        return portManager.handlePortStatusMessage(ps);
+    }
+
+    @Override
+    @JsonProperty("ports")
+    public Collection<OFPortDesc> getPorts() {
+	return portManager.getPorts();
+    }
+
+    @Override
+    public boolean portEnabled(int portNumber) {
+        return isEnabled(portManager.getPort(portNumber));
+    }
+
+    @Override
+    public boolean portEnabled(String portName) {
+	return isEnabled(portManager.getPort(portName));
+    }
+
+    private boolean isEnabled(OFPortDesc p) {
+	return (p != null &&
+			!p.getState().contains(OFPortState.LINK_DOWN) &&
+			!p.getState().contains(OFPortState.BLOCKED) &&
+                !p.getConfig().contains(OFPortConfig.PORT_DOWN));
+    }
+
+    @Override
+    public OrderedCollection<PortChangeEvent> comparePorts(Collection<OFPortDesc> ports) {
+        return portManager.comparePorts(ports);
+    }
+
+    @Override
+    @JsonIgnore
+    public OrderedCollection<PortChangeEvent> setPorts(Collection<OFPortDesc> ports) {
+        return portManager.updatePorts(ports);
+    }
+
+    /**
+     * Manages the ports of this switch.
+     *
+     * Provides methods to query and update the stored ports. The class ensures
+     * that every port name and port number is unique. When updating ports
+     * the class checks if port number <-> port name mappings have change due
+     * to the update. If a new port P has number and port that are inconsistent
+     * with the previous mapping(s) the class will delete all previous ports
+     * with name or number of the new port and then add the new port.
+     *
+     * Port names are stored as-is but they are compared case-insensitive
+     *
+     * The methods that change the stored ports return a list of
+     * PortChangeEvents that represent the changes that have been applied
+     * to the port list so that IOFSwitchListeners can be notified about the
+     * changes.
+     *
+     * Implementation notes:
+     * - We keep several different representations of the ports to allow for
+     *   fast lookups
+     * - Ports are stored in unchangeable lists. When a port is modified new
+     *   data structures are allocated.
+     * - We use a read-write-lock for synchronization, so multiple readers are
+     *   allowed.
+     * - All port numbers have int representation (no more shorts)
+     */
+    protected class PortManager {
+        private final ReentrantReadWriteLock lock;
+        private List<OFPortDesc> portList;
+        private List<OFPortDesc> enabledPortList;
+        private List<Integer> enabledPortNumbers;
+        private Map<Integer,OFPortDesc> portsByNumber;
+        private Map<String,OFPortDesc> portsByName;
+
+        public PortManager() {
+            this.lock = new ReentrantReadWriteLock();
+            this.portList = Collections.emptyList();
+            this.enabledPortList = Collections.emptyList();
+            this.enabledPortNumbers = Collections.emptyList();
+            this.portsByName = Collections.emptyMap();
+            this.portsByNumber = Collections.emptyMap();
+        }
+
+        /**
+         * Set the internal data structure storing this switch's port
+         * to the ports specified by newPortsByNumber
+         *
+         * CALLER MUST HOLD WRITELOCK
+         *
+         * @param newPortsByNumber
+         * @throws IllegaalStateException if called without holding the
+         * writelock
+         */
+        private void updatePortsWithNewPortsByNumber(
+                Map<Integer,OFPortDesc> newPortsByNumber) {
+            if (!lock.writeLock().isHeldByCurrentThread()) {
+                throw new IllegalStateException("Method called without " +
+                                                "holding writeLock");
+            }
+            Map<String,OFPortDesc> newPortsByName =
+                    new HashMap<String, OFPortDesc>();
+            List<OFPortDesc> newPortList =
+                    new ArrayList<OFPortDesc>();
+            List<OFPortDesc> newEnabledPortList =
+                    new ArrayList<OFPortDesc>();
+            List<Integer> newEnabledPortNumbers = new ArrayList<Integer>();
+
+            for(OFPortDesc p: newPortsByNumber.values()) {
+                newPortList.add(p);
+                newPortsByName.put(p.getName().toLowerCase(), p);
+                if (isEnabled(p)) {
+                    newEnabledPortList.add(p);
+                    newEnabledPortNumbers.add(p.getPortNo().getPortNumber());
+                }
+            }
+            portsByName = Collections.unmodifiableMap(newPortsByName);
+            portsByNumber =
+                    Collections.unmodifiableMap(newPortsByNumber);
+            enabledPortList =
+                    Collections.unmodifiableList(newEnabledPortList);
+            enabledPortNumbers =
+                    Collections.unmodifiableList(newEnabledPortNumbers);
+            portList = Collections.unmodifiableList(newPortList);
+        }
+
+        /**
+         * Handle a OFPortStatus delete message for the given port.
+         * Updates the internal port maps/lists of this switch and returns
+         * the PortChangeEvents caused by the delete. If the given port
+         * exists as it, it will be deleted. If the name<->number for the
+         * given port is inconsistent with the ports stored by this switch
+         * the method will delete all ports with the number or name of the
+         * given port.
+         *
+         * This method will increment error/warn counters and log
+         *
+         * @param delPort the port from the port status message that should
+         * be deleted.
+         * @return ordered collection of port changes applied to this switch
+         */
+        private OrderedCollection<PortChangeEvent> handlePortStatusDelete(
+				OFPortDesc delPort) {
+            lock.writeLock().lock();
+            OrderedCollection<PortChangeEvent> events =
+                    new LinkedHashSetWrapper<PortChangeEvent>();
+            try {
+                Map<Integer,OFPortDesc> newPortByNumber =
+                        new HashMap<Integer, OFPortDesc>(portsByNumber);
+                OFPortDesc prevPort =
+                        portsByNumber.get(delPort.getPortNo().getPortNumber());
+                if (prevPort == null) {
+                    // so such port. Do we have a port with the name?
+                    prevPort = portsByName.get(delPort.getName());
+                    if (prevPort != null) {
+                        newPortByNumber.remove(prevPort.getPortNo().getPortNumber());
+                        events.add(new PortChangeEvent(prevPort,
+                                                       PortChangeType.DELETE));
+                    }
+                } else if (prevPort.getName().equals(delPort.getName())) {
+                    // port exists with consistent name-number mapping
+                    newPortByNumber.remove(delPort.getPortNo().getPortNumber());
+                    events.add(new PortChangeEvent(delPort,
+                                                   PortChangeType.DELETE));
+                } else {
+                    // port with same number exists but its name differs. This
+                    // is weird. The best we can do is to delete the existing
+                    // port(s) that have delPort's name and number.
+                    newPortByNumber.remove(delPort.getPortNo().getPortNumber());
+                    events.add(new PortChangeEvent(prevPort,
+                                                   PortChangeType.DELETE));
+                    // is there another port that has delPort's name?
+                    prevPort = portsByName.get(delPort.getName().toLowerCase());
+                    if (prevPort != null) {
+                        newPortByNumber.remove(prevPort.getPortNo().getPortNumber());
+                        events.add(new PortChangeEvent(prevPort,
+                                                       PortChangeType.DELETE));
+                    }
+                }
+                updatePortsWithNewPortsByNumber(newPortByNumber);
+                return events;
+            } finally {
+                lock.writeLock().unlock();
+            }
+        }
+
+        /**
+         * Handle a OFPortStatus message, update the internal data structures
+         * that store ports and return the list of OFChangeEvents.
+         *
+         * This method will increment error/warn counters and log
+         *
+         * @param ps
+         * @return
+         */
+        public OrderedCollection<PortChangeEvent> handlePortStatusMessage(OFPortStatus ps) {
+            if (ps == null) {
+                throw new NullPointerException("OFPortStatus message must " +
+                                               "not be null");
+            }
+            lock.writeLock().lock();
+            try {
+                OFPortReason reason = ps.getReason();
+                if (reason == null) {
+                    throw new IllegalArgumentException("Unknown PortStatus " +
+                            "reason code " + ps.getReason());
+                }
+
+                if (log.isDebugEnabled()) {
+                    log.debug("Handling OFPortStatus: {} for {}",
+                              reason, ps);
+                }
+
+                if (reason == OFPortReason.DELETE)
+                        return handlePortStatusDelete(ps.getDesc());
+
+                // We handle ADD and MODIFY the same way. Since OpenFlow
+                // doesn't specify what uniquely identifies a port the
+                // notion of ADD vs. MODIFY can also be hazy. So we just
+                // compare the new port to the existing ones.
+                Map<Integer,OFPortDesc> newPortByNumber =
+                    new HashMap<Integer, OFPortDesc>(portsByNumber);
+                OrderedCollection<PortChangeEvent> events =
+				getSinglePortChanges(ps.getDesc());
+                for (PortChangeEvent e: events) {
+                    switch(e.type) {
+                        case DELETE:
+                            newPortByNumber.remove(e.port.getPortNo().getPortNumber());
+                            break;
+                        case ADD:
+                            if (reason != OFPortReason.ADD) {
+                                // weird case
+                            }
+                            newPortByNumber.put(e.port.getPortNo().getPortNumber(),
+                                    e.port);
+                            break;
+                        case DOWN:
+                            newPortByNumber.put(e.port.getPortNo().getPortNumber(),
+                                    e.port);
+                            break;
+                        case OTHER_UPDATE:
+                            newPortByNumber.put(e.port.getPortNo().getPortNumber(),
+                                    e.port);
+                            break;
+                        case UP:
+                            newPortByNumber.put(e.port.getPortNo().getPortNumber(),
+					e.port);
+                            break;
+                    }
+                }
+                updatePortsWithNewPortsByNumber(newPortByNumber);
+                return events;
+            } finally {
+                lock.writeLock().unlock();
+            }
+
+        }
+
+        /**
+         * Given a new or modified port newPort, returns the list of
+         * PortChangeEvents to "transform" the current ports stored by
+         * this switch to include / represent the new port. The ports stored
+         * by this switch are <b>NOT</b> updated.
+         *
+         * This method acquires the readlock and is thread-safe by itself.
+         * Most callers will need to acquire the write lock before calling
+         * this method though (if the caller wants to update the ports stored
+         * by this switch)
+         *
+         * @param newPort the new or modified port.
+         * @return the list of changes
+         */
+        public OrderedCollection<PortChangeEvent> getSinglePortChanges(
+			OFPortDesc newPort) {
+            lock.readLock().lock();
+            try {
+                OrderedCollection<PortChangeEvent> events =
+                        new LinkedHashSetWrapper<PortChangeEvent>();
+                // Check if we have a port by the same number in our
+                // old map.
+                OFPortDesc prevPort =
+                        portsByNumber.get(newPort.getPortNo().getPortNumber());
+                if (newPort.equals(prevPort)) {
+                    // nothing has changed
+                    return events;
+                }
+
+                if (prevPort != null &&
+                        prevPort.getName().equals(newPort.getName())) {
+                    // A simple modify of a existing port
+                    // A previous port with this number exists and it's name
+                    // also matches the new port. Find the differences
+                    if (isEnabled(prevPort) && !isEnabled(newPort)) {
+                        events.add(new PortChangeEvent(newPort,
+                                                       PortChangeType.DOWN));
+                    } else if (!isEnabled(prevPort) && isEnabled(newPort)) {
+                        events.add(new PortChangeEvent(newPort,
+                                                       PortChangeType.UP));
+                    } else {
+                        events.add(new PortChangeEvent(newPort,
+                                   PortChangeType.OTHER_UPDATE));
+                    }
+                    return events;
+                }
+
+                if (prevPort != null) {
+                    // There exists a previous port with the same port
+                    // number but the port name is different (otherwise we would
+                    // never have gotten here)
+                    // Remove the port. Name-number mapping(s) have changed
+                    events.add(new PortChangeEvent(prevPort,
+                                                   PortChangeType.DELETE));
+                }
+
+                // We now need to check if there exists a previous port sharing
+                // the same name as the new/updated port.
+                prevPort = portsByName.get(newPort.getName().toLowerCase());
+                if (prevPort != null) {
+                    // There exists a previous port with the same port
+                    // name but the port number is different (otherwise we
+                    // never have gotten here).
+                    // Remove the port. Name-number mapping(s) have changed
+                    events.add(new PortChangeEvent(prevPort,
+                                                   PortChangeType.DELETE));
+                }
+
+                // We always need to add the new port. Either no previous port
+                // existed or we just deleted previous ports with inconsistent
+                // name-number mappings
+                events.add(new PortChangeEvent(newPort, PortChangeType.ADD));
+                return events;
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        /**
+         * Compare the current ports of this switch to the newPorts list and
+         * return the changes that would be applied to transfort the current
+         * ports to the new ports. No internal data structures are updated
+         * see {@link #compareAndUpdatePorts(List, boolean)}
+         *
+         * @param newPorts the list of new ports
+         * @return The list of differences between the current ports and
+         * newPortList
+         */
+        public OrderedCollection<PortChangeEvent> comparePorts(
+			Collection<OFPortDesc> newPorts) {
+            return compareAndUpdatePorts(newPorts, false);
+        }
+
+        /**
+         * Compare the current ports of this switch to the newPorts list and
+         * return the changes that would be applied to transform the current
+         * ports to the new ports. No internal data structures are updated
+         * see {@link #compareAndUpdatePorts(List, boolean)}
+         *
+         * @param newPorts the list of new ports
+         * @return The list of differences between the current ports and
+         * newPortList
+         */
+        public OrderedCollection<PortChangeEvent> updatePorts(
+			Collection<OFPortDesc> newPorts) {
+            return compareAndUpdatePorts(newPorts, true);
+        }
+
+        /**
+         * Compare the current ports stored in this switch instance with the
+         * new port list given and return the differences in the form of
+         * PortChangeEvents. If the doUpdate flag is true, newPortList will
+         * replace the current list of this switch (and update the port maps)
+         *
+         * Implementation note:
+         * Since this method can optionally modify the current ports and
+         * since it's not possible to upgrade a read-lock to a write-lock
+         * we need to hold the write-lock for the entire operation. If this
+         * becomes a problem and if compares() are common we can consider
+         * splitting in two methods but this requires lots of code duplication
+         *
+         * @param newPorts the list of new ports.
+         * @param doUpdate If true the newPortList will replace the current
+         * port list for this switch. If false this switch will not be changed.
+         * @return The list of differences between the current ports and
+         * newPorts
+         * @throws NullPointerException if newPortsList is null
+         * @throws IllegalArgumentException if either port names or port numbers
+         * are duplicated in the newPortsList.
+         */
+        private OrderedCollection<PortChangeEvent> compareAndUpdatePorts(
+                Collection<OFPortDesc> newPorts, boolean doUpdate) {
+            if (newPorts == null) {
+                throw new NullPointerException("newPortsList must not be null");
+            }
+            lock.writeLock().lock();
+            try {
+                OrderedCollection<PortChangeEvent> events =
+                        new LinkedHashSetWrapper<PortChangeEvent>();
+
+                Map<Integer,OFPortDesc> newPortsByNumber =
+                        new HashMap<Integer, OFPortDesc>();
+                Map<String,OFPortDesc> newPortsByName =
+                        new HashMap<String, OFPortDesc>();
+                List<OFPortDesc> newEnabledPortList =
+                        new ArrayList<OFPortDesc>();
+                List<Integer> newEnabledPortNumbers =
+                        new ArrayList<Integer>();
+                List<OFPortDesc> newPortsList =
+                        new ArrayList<OFPortDesc>(newPorts);
+
+                for (OFPortDesc p: newPortsList) {
+                    if (p == null) {
+                        throw new NullPointerException("portList must not " +
+                                "contain null values");
+                    }
+
+                    // Add the port to the new maps and lists and check
+                    // that every port is unique
+                    OFPortDesc duplicatePort;
+                    duplicatePort = newPortsByNumber.put(
+				p.getPortNo().getPortNumber(), p);
+                    if (duplicatePort != null) {
+                        String msg = String.format("Cannot have two ports " +
+                                "with the same number: %s <-> %s",
+                                p, duplicatePort);
+                        throw new IllegalArgumentException(msg);
+                    }
+                    duplicatePort =
+                            newPortsByName.put(p.getName().toLowerCase(), p);
+                    if (duplicatePort != null) {
+                        String msg = String.format("Cannot have two ports " +
+                                "with the same name: %s <-> %s",
+                                p.toString().substring(0,80),
+                                duplicatePort.toString().substring(0, 80));
+                        throw new IllegalArgumentException(msg);
+                    }
+                    if (isEnabled(p)) {
+                        newEnabledPortList.add(p);
+                        newEnabledPortNumbers.add(p.getPortNo().getPortNumber());
+                    }
+
+                    // get changes
+                    events.addAll(getSinglePortChanges(p));
+                }
+                // find deleted ports
+                // We need to do this after looping through all the new ports
+                // to we can handle changed name<->number mappings correctly
+                // We could pull it into the loop of we address this but
+                // it's probably not worth it
+                for (OFPortDesc oldPort: this.portList) {
+                    if (!newPortsByNumber.containsKey(oldPort.getPortNo().getPortNumber())) {
+                        PortChangeEvent ev =
+                                new PortChangeEvent(oldPort,
+                                                    PortChangeType.DELETE);
+                        events.add(ev);
+                    }
+                }
+
+
+                if (doUpdate) {
+                    portsByName = Collections.unmodifiableMap(newPortsByName);
+                    portsByNumber =
+                            Collections.unmodifiableMap(newPortsByNumber);
+                    enabledPortList =
+                            Collections.unmodifiableList(newEnabledPortList);
+                    enabledPortNumbers =
+                            Collections.unmodifiableList(newEnabledPortNumbers);
+                    portList = Collections.unmodifiableList(newPortsList);
+                }
+                return events;
+            } finally {
+                lock.writeLock().unlock();
+            }
+        }
+
+        public OFPortDesc getPort(String name) {
+            if (name == null) {
+                throw new NullPointerException("Port name must not be null");
+            }
+            lock.readLock().lock();
+            try {
+                return portsByName.get(name.toLowerCase());
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        public OFPortDesc getPort(int portNumber) {
+            lock.readLock().lock();
+            try {
+                return portsByNumber.get(portNumber);
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        public List<OFPortDesc> getPorts() {
+            lock.readLock().lock();
+            try {
+                return portList;
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        public List<OFPortDesc> getEnabledPorts() {
+            lock.readLock().lock();
+            try {
+                return enabledPortList;
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+
+        public List<Integer> getEnabledPortNumbers() {
+            lock.readLock().lock();
+            try {
+                return enabledPortNumbers;
+            } finally {
+                lock.readLock().unlock();
+            }
+        }
+    }
+
+
+	//*******************************************
+    //    Switch stats handling
+    //*******************************************
+
+    @Override
+    public Future<List<OFStatsReply>> getStatistics(OFStatsRequest<?> request)
+		throws IOException {
+        OFStatisticsFuture future = new OFStatisticsFuture(threadPool, this,
+			(int)request.getXid());
+        log.info("description STAT REQUEST XID {}", request.getXid());
+        this.statsFutureMap.put((int)request.getXid(), future);
+
+        this.channel.write(Collections.singletonList(request));
+        return future;
+    }
+
+    @Override
+    public void deliverStatisticsReply(OFMessage reply) {
+        OFStatisticsFuture future = this.statsFutureMap.get((int)reply.getXid());
+        if (future != null) {
+            future.deliverFuture(this, reply);
+            // The future will ultimately unregister itself and call
+            // cancelStatisticsReply
+            return;
+        }
+        // Transaction id was not found in statsFutureMap.check the other map
+        IOFMessageListener caller = this.iofMsgListenersMap.get(reply.getXid());
+        if (caller != null) {
+		caller.receive(this, reply, null);
+        }
+    }
+
+    @Override
+    public void cancelStatisticsReply(int transactionId) {
+        if (null == this.statsFutureMap.remove(transactionId)) {
+            this.iofMsgListenersMap.remove(transactionId);
+        }
+    }
+
+    @Override
+    public void cancelAllStatisticsReplies() {
+        /* we don't need to be synchronized here. Even if another thread
+         * modifies the map while we're cleaning up the future will eventuall
+         * timeout */
+        for (OFStatisticsFuture f : statsFutureMap.values()) {
+            f.cancel(true);
+        }
+        statsFutureMap.clear();
+        iofMsgListenersMap.clear();
+    }
+
+
+    //*******************************************
+    //    Switch role handling
+    //*******************************************
+
+    // XXX S this is completely wrong. The generation id should be obtained
+    // after coordinating with all controllers connected to this switch.
+    // ie. should be part of registry service (account for 1.3 vs 1.0)
+    // For now we are just generating this locally and keeping it constant.
+    public U64 getNextGenerationId() {
+        //TODO: Pankaj, fix nextGenerationId as part of Registry interface
+	return U64.of(generationIdSource);
+    }
+
+    @Override
+    public Role getRole() {
+        return role;
+    }
+
+    @JsonIgnore
+    @Override
+    public void setRole(Role role) {
+        this.role = role;
+    }
+
+
+    //*******************************************
+    //    Switch utility methods
+    //*******************************************
+
+    private void registerOverloadCounters() throws CounterException {
+        if (debugCountersRegistered) {
+            return;
+        }
+        if (debugCounters == null) {
+            log.error("Debug Counter Service not found");
+            debugCounters = new NullDebugCounter();
+            debugCountersRegistered = true;
+        }
+        // every level of the hierarchical counter has to be registered
+        // even if they are not used
+        ctrSwitch = debugCounters.registerCounter(
+                                   BASE , stringId,
+                                   "Counter for this switch",
+                                   CounterType.ALWAYS_COUNT);
+        ctrSwitchPktin = debugCounters.registerCounter(
+                                   BASE, stringId + "/pktin",
+                                   "Packet in counter for this switch",
+                                   CounterType.ALWAYS_COUNT);
+        ctrSwitchWrite = debugCounters.registerCounter(
+                                   BASE, stringId + "/write",
+                                   "Write counter for this switch",
+                                   CounterType.ALWAYS_COUNT);
+        ctrSwitchPktinDrops = debugCounters.registerCounter(
+                                   BASE, stringId + "/pktin/drops",
+                                   "Packet in throttle drop count",
+                                   CounterType.ALWAYS_COUNT,
+                                   IDebugCounterService.CTR_MDATA_WARN);
+        ctrSwitchWriteDrops = debugCounters.registerCounter(
+                                   BASE, stringId + "/write/drops",
+                                   "Switch write throttle drop count",
+                                   CounterType.ALWAYS_COUNT,
+                                   IDebugCounterService.CTR_MDATA_WARN);
+    }
+
+    @Override
+    public void startDriverHandshake() throws IOException {
+	log.debug("Starting driver handshake for sw {}", getStringId());
+        if (startDriverHandshakeCalled)
+            throw new SwitchDriverSubHandshakeAlreadyStarted();
+        startDriverHandshakeCalled = true;
+    }
+
+    @Override
+    public boolean isDriverHandshakeComplete() {
+        if (!startDriverHandshakeCalled)
+            throw new SwitchDriverSubHandshakeNotStarted();
+        return true;
+    }
+
+    @Override
+    public void processDriverHandshakeMessage(OFMessage m) {
+        if (startDriverHandshakeCalled)
+            throw new SwitchDriverSubHandshakeCompleted(m);
+        else
+            throw new SwitchDriverSubHandshakeNotStarted();
+    }
+
+    @Override
+    @JsonIgnore
+    @LogMessageDoc(level="WARN",
+        message="Switch {switch} flow table is full",
+        explanation="The controller received flow table full " +
+                "message from the switch, could be caused by increased " +
+                "traffic pattern",
+                recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+    public void setTableFull(boolean isFull) {
+        if (isFull && !flowTableFull) {
+            floodlightProvider.addSwitchEvent(this.datapathId.getLong(),
+                    "SWITCH_FLOW_TABLE_FULL " +
+                    "Table full error from switch", false);
+            log.warn("Switch {} flow table is full", stringId);
+        }
+        flowTableFull  = isFull;
+    }
+
+    @Override
+    @LogMessageDoc(level = "ERROR",
+            message = "Failed to clear all flows on switch {switch}",
+            explanation = "An I/O error occured while trying to clear " +
+                    "flows on the switch.",
+            recommendation = LogMessageDoc.CHECK_SWITCH)
+    public void clearAllFlowMods() {
+        // Delete all pre-existing flows
+
+	// by default if match is not specified, then an empty list of matches
+	// is sent, resulting in a wildcard-all flows
+	// XXX fix this later
+	OFMessage fm = floodlightProvider.getOFMessageFactory_13()
+						.buildFlowDelete()
+						.setOutPort(OFPort.ANY)
+						.setOutGroup(OFGroup.ANY)
+						.setTableId(TableId.ALL)
+						.build();
+
+        try {
+            channel.write(Collections.singletonList(fm));
+        } catch (Exception e) {
+            log.error("Failed to clear all flows on switch " + this, e);
+        }
+    }
+
+    @Override
+    public void flush() {
+        Map<OFSwitchImplBase, List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        List<OFMessage> msglist = msg_buffer_map.get(this);
+        if ((msglist != null) && (msglist.size() > 0)) {
+            try {
+                this.write(msglist);
+            } catch (IOException e) {
+		log.error("Failed flushing messages", e);
+            }
+            msglist.clear();
+        }
+    }
+
+    public static void flush_all() {
+        Map<OFSwitchImplBase, List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        for (OFSwitchImplBase sw : msg_buffer_map.keySet()) {
+            sw.flush();
+        }
+    }
+
+    /**
+     * Return a read lock that must be held while calling the listeners for
+     * messages from the switch. Holding the read lock prevents the active
+     * switch list from being modified out from under the listeners.
+     *
+     * @return listener read lock
+     */
+    @JsonIgnore
+    public Lock getListenerReadLock() {
+        return listenerLock.readLock();
+    }
+
+    /**
+     * Return a write lock that must be held when the controllers modifies the
+     * list of active switches. This is to ensure that the active switch list
+     * doesn't change out from under the listeners as they are handling a
+     * message from the switch.
+     *
+     * @return listener write lock
+     */
+    @JsonIgnore
+    public Lock getListenerWriteLock() {
+        return listenerLock.writeLock();
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java b/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java
index e87989d..62938fe 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OpenflowPipelineFactory.java
@@ -1,19 +1,19 @@
 /**
- *    Copyright 2011, Big Switch Networks, Inc.
- *    Originally created by David Erickson, Stanford University
- *
- *    Licensed under the Apache License, Version 2.0 (the "License"); you may
- *    not use this file except in compliance with the License. You may obtain
- *    a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- *    License for the specific language governing permissions and limitations
- *    under the License.
- **/
+*    Copyright 2011, Big Switch Networks, Inc.
+*    Originally created by David Erickson, Stanford University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
 
 package net.floodlightcontroller.core.internal;
 
@@ -25,15 +25,16 @@
 import org.jboss.netty.handler.execution.ExecutionHandler;
 import org.jboss.netty.handler.timeout.IdleStateHandler;
 import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
+import org.jboss.netty.util.ExternalResourceReleasable;
 import org.jboss.netty.util.HashedWheelTimer;
 import org.jboss.netty.util.Timer;
 
 /**
  * Creates a ChannelPipeline for a server-side openflow channel
- *
  * @author readams
  */
-public class OpenflowPipelineFactory implements ChannelPipelineFactory {
+public class OpenflowPipelineFactory
+    implements ChannelPipelineFactory, ExternalResourceReleasable {
 
     protected Controller controller;
     protected ThreadPoolExecutor pipelineExecutor;
@@ -53,20 +54,25 @@
 
     @Override
     public ChannelPipeline getPipeline() throws Exception {
-        OFChannelState state = new OFChannelState();
+        OFChannelHandler handler = new OFChannelHandler(controller);
 
         ChannelPipeline pipeline = Channels.pipeline();
         pipeline.addLast("ofmessagedecoder", new OFMessageDecoder());
         pipeline.addLast("ofmessageencoder", new OFMessageEncoder());
         pipeline.addLast("idle", idleHandler);
         pipeline.addLast("timeout", readTimeoutHandler);
+        // XXX S ONOS: was 15 increased it to fix Issue #296
         pipeline.addLast("handshaketimeout",
-                new HandshakeTimeoutHandler(state, timer, 60)); // ONOS: was 15 increased it to fix Issue #296
+                         new HandshakeTimeoutHandler(handler, timer, 60));
         if (pipelineExecutor != null)
             pipeline.addLast("pipelineExecutor",
-                    new ExecutionHandler(pipelineExecutor));
-        pipeline.addLast("handler", controller.getChannelHandler(state));
+                             new ExecutionHandler(pipelineExecutor));
+        pipeline.addLast("handler", handler);
         return pipeline;
     }
 
+    @Override
+    public void releaseExternalResources() {
+        timer.stop();
+    }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
deleted file mode 100644
index 6252a72..0000000
--- a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
+++ /dev/null
@@ -1,342 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.concurrent.DelayQueue;
-import java.util.concurrent.Delayed;
-import java.util.concurrent.TimeUnit;
-
-import net.floodlightcontroller.core.IFloodlightProviderService.Role;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This class handles sending of RoleRequest messages to all connected switches.
- * <p/>
- * Handling Role Requests is tricky. Roles are hard state on the switch and
- * we can't query it so we need to make sure that we have consistent states
- * on the switches. Whenever we send a role request to the set of connected
- * switches we need to make sure that we've sent the request to all of them
- * before we process the next change request. If a new switch connects, we
- * need to send it the current role and need to make sure that the current
- * role doesn't change while we are doing it. We achieve this by synchronizing
- * all these actions on Controller.roleChanger
- * On the receive side: we need to make sure that we receive a reply for each
- * request we send and that the reply is consistent with the request we sent.
- * We'd also like to send the role request to the switch asynchronously in a
- * separate thread so we don't block the REST API or other callers.
- * <p/>
- * There are potential ways to relax these synchronization requirements:
- * - "Generation ID" for each role request. However, this would be most useful
- * if it were global for the whole cluster
- * - Regularly resend the controller's current role. Don't know whether this
- * might have adverse effects on the switch.
- * <p/>
- * Caveats:
- * - No way to know if another controller (not in our controller cluster)
- * sends MASTER requests to connected switches. Then we would drop to
- * slave role without knowing it. Could regularly resend the current role.
- * Ideally the switch would notify us if it demoted us. What happens if
- * the other controller also regularly resends the same role request?
- * Or if the health check determines that
- * a controller is dead but the controller is still talking to switches (maybe
- * just its health check failed) and resending the master role request....
- * We could try to detect if a switch demoted us to slave even if we think
- * we are master (error messages on packet outs, e.g., when sending LLDPs)
- * <p/>
- * <p/>
- * The general model of Role Request handling is as follows:
- * <p/>
- * - All role request messages are handled by this class. Class Controller
- * submits a role change request and the request gets queued. submitRequest
- * takes a Collection of switches to which to send the request. We make a copy
- * of this list.
- * - A thread takes these change requests from the queue and sends them to
- * all the switches (using our copy of the switch list).
- * - The OFSwitchImpl sends the request over the wire and puts the request
- * into a queue of pending request (storing xid and role). We start a timeout
- * to make sure we eventually receive a reply from the switch. We use a single
- * timeout for each request submitted using submitRequest()
- * - After the timeout triggers we go over the list of switches again and
- * check that a response has been received (by checking the head of the
- * OFSwitchImpl's queue of pending requests)
- * - We handle requests and timeouts in the same thread. We use a priority queue
- * to schedule them so we are guaranteed that they are processed in
- * the same order as they are submitted. If a request times out we drop
- * the connection to this switch.
- * - Since we decouple submission of role change requests and actually sending
- * them we cannot check a received role reply against the controller's current
- * role because the controller's current role could have changed again.
- * - Receiving Role Reply messages is handled by OFChannelHandler and
- * OFSwitchImpl directly. The OFSwitchImpl checks if the received request
- * is as expected (xid and role match the head of the pending queue in
- * OFSwitchImpl). If so
- * the switch updates its role. Otherwise the connection is dropped. If this
- * is the first reply, the SWITCH_SUPPORTS_NX_ROLE attribute is set.
- * Next, we call addSwitch(), removeSwitch() to update the list of active
- * switches if appropriate.
- * - If we receive an Error indicating that roles are not supported by the
- * switch, we set the SWITCH_SUPPORTS_NX_ROLE to false. We keep the
- * switch connection alive while in MASTER and EQUAL role.
- * (TODO: is this the right behavior for EQUAL??). If the role changes to
- * SLAVE the switch connection is dropped (remember: only if the switch
- * doesn't support role requests)
- * The expected behavior is that the switch will probably try to reconnect
- * repeatedly (with some sort of exponential backoff), but after a  while
- * will give-up and move on to the next controller-IP configured on the
- * switch. This is the serial failover mechanism from OpenFlow spec v1.0.
- * <p/>
- * New switch connection:
- * - Switch handshake is done without sending any role request messages.
- * - After handshake completes, switch is added to the list of connected switches
- * and we send the first role request message if role
- * requests are enabled. If roles are disabled automatically promote switch to
- * active switch list and clear FlowTable.
- * - When we receive the first reply we proceed as above. In addition, if
- * the role request is for MASTER we wipe the flow table. We do not wipe
- * the flow table if the switch connected while role supported was disabled
- * on the controller.
- */
-public class RoleChanger {
-    // FIXME: Upon closer inspection DelayQueue seems to be somewhat broken. 
-    // We are required to implement a compareTo based on getDelay() and 
-    // getDelay() must return the remaining delay, thus it needs to use the 
-    // current time. So x1.compareTo(x1) can never return 0 as some time
-    // will have passed between evaluating both getDelays(). This is even worse
-    // if the thread happens to be preempted between calling the getDelay()
-    // For the time being we enforce a small delay between subsequent
-    // role request messages and hope that's long enough to not screw up
-    // ordering. In the long run we might want to use two threads and two queues
-    // (one for requests, one for timeouts)
-    // Sigh. 
-    protected DelayQueue<RoleChangeTask> pendingTasks;
-    protected long lastSubmitTime;
-    protected Thread workerThread;
-    protected long timeout;
-    protected final static long DEFAULT_TIMEOUT = 15L * 1000 * 1000 * 1000L; // 15s
-    protected final static Logger log = LoggerFactory.getLogger(RoleChanger.class);
-
-    /**
-     * A queued task to be handled by the Role changer thread.
-     */
-    protected static class RoleChangeTask implements Delayed {
-        protected enum Type {
-            /**
-             * This is a request. Dispatch the role update to switches
-             */
-            REQUEST,
-            /**
-             * This is a timeout task. Check if all switches have
-             * correctly replied to the previously dispatched role request
-             */
-            TIMEOUT
-        }
-
-        // The set of switches to work on
-        public Collection<OFSwitchImpl> 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) {
-            this.switches = switches;
-            this.role = role;
-            this.type = Type.REQUEST;
-            this.deadline = deadline;
-        }
-
-        @Override
-        public int compareTo(Delayed o) {
-            Long timeRemaining = getDelay(TimeUnit.NANOSECONDS);
-            return timeRemaining.compareTo(o.getDelay(TimeUnit.NANOSECONDS));
-        }
-
-        @Override
-        public long getDelay(TimeUnit tu) {
-            long timeRemaining = deadline - System.nanoTime();
-            return tu.convert(timeRemaining, TimeUnit.NANOSECONDS);
-        }
-    }
-
-    @LogMessageDoc(level = "ERROR",
-            message = "RoleRequestWorker task had an uncaught exception.",
-            explanation = "An unknown occured while processing an HA " +
-                    "role change event.",
-            recommendation = LogMessageDoc.GENERIC_ACTION)
-    protected class RoleRequestWorker extends Thread {
-        @Override
-        public void run() {
-            RoleChangeTask t;
-            boolean interrupted = false;
-            log.trace("RoleRequestWorker thread started");
-            try {
-                while (true) {
-                    try {
-                        t = pendingTasks.take();
-                    } catch (InterruptedException e) {
-                        // see http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html
-                        interrupted = true;
-                        continue;
-                    }
-                    if (t.type == RoleChangeTask.Type.REQUEST) {
-                        sendRoleRequest(t.switches, t.role, t.deadline);
-                        // Queue the timeout
-                        t.type = RoleChangeTask.Type.TIMEOUT;
-                        t.deadline += timeout;
-                        pendingTasks.put(t);
-                    } else {
-                        verifyRoleReplyReceived(t.switches, t.deadline);
-                    }
-                }
-            } catch (Exception e) {
-                // Should never get here
-                log.error("RoleRequestWorker task had an uncaught exception. ",
-                        e);
-            } finally {
-                // Be nice in case we earlier caught InterruptedExecution
-                if (interrupted)
-                    Thread.currentThread().interrupt();
-            }
-        } // end loop
-    }
-
-    public RoleChanger() {
-        this.pendingTasks = new DelayQueue<RoleChangeTask>();
-        this.workerThread = new Thread(new RoleRequestWorker());
-        this.timeout = DEFAULT_TIMEOUT;
-        this.workerThread.start();
-    }
-
-
-    public synchronized void submitRequest(Collection<OFSwitchImpl> 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);
-        RoleChangeTask req = new RoleChangeTask(switches_copy, role, deadline);
-        pendingTasks.put(req);
-        lastSubmitTime = deadline;
-    }
-
-    /**
-     * Send a role request message to switches. This checks the capabilities
-     * of the switch for understanding role request messaging. Currently we only
-     * support the OVS-style role request message, but once the controller
-     * supports OF 1.2, this function will also handle sending out the
-     * OF 1.2-style role request message.
-     *
-     * @param switches the collection of switches to send the request too
-     * @param role     the role to request
-     */
-    @LogMessageDoc(level = "WARN",
-            message = "Failed to send role request message " +
-                    "to switch {switch}: {message}. Disconnecting",
-            explanation = "An I/O error occurred while attempting to change " +
-                    "the switch HA role.",
-            recommendation = LogMessageDoc.CHECK_SWITCH)
-    protected void sendRoleRequest(Collection<OFSwitchImpl> switches,
-                                   Role role, long cookie) {
-        // There are three cases to consider:
-        //
-        // 1) If the controller role at the point the switch connected was
-        //    null/disabled, then we never sent the role request probe to the
-        //    switch and therefore never set the SWITCH_SUPPORTS_NX_ROLE
-        //    attribute for the switch, so supportsNxRole is null. In that
-        //    case since we're now enabling role support for the controller
-        //    we should send out the role request probe/update to the switch.
-        //
-        // 2) If supportsNxRole == Boolean.TRUE then that means we've already
-        //    sent the role request probe to the switch and it replied with
-        //    a role reply message, so we know it supports role request
-        //    messages. Now we're changing the role and we want to send
-        //    it another role request message to inform it of the new role
-        //    for the controller.
-        //
-        // 3) If supportsNxRole == Boolean.FALSE, then that means we sent the
-        //    role request probe to the switch but it responded with an error
-        //    indicating that it didn't understand the role request message.
-        //    In that case we don't want to send it another role request that
-        //    it (still) doesn't understand. But if the new role of the
-        //    controller is SLAVE, then we don't want the switch to remain
-        //    connected to this controller. It might support the older serial
-        //    failover model for HA support, so we want to terminate the
-        //    connection and get it to initiate a connection with another
-        //    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();
-        while (iter.hasNext()) {
-            OFSwitchImpl sw = iter.next();
-            try {
-                Boolean supportsNxRole = (Boolean)
-                        sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
-                if ((supportsNxRole == null) || supportsNxRole) {
-                    // Handle cases #1 and #2
-                    log.debug("Sending NxRoleRequest to {}", sw);
-                    sw.sendNxRoleRequest(role, cookie);
-                } else {
-                    if (role == Role.MASTER) {
-                        // ONOS extension:
-                        log.debug("Switch {} doesn't support NxRoleRequests, but sending " +
-                                "{} request anyway", sw, role);
-                        //Send the role request anyway, even though we know the switch
-                        //doesn't support it. The switch will give an error and in our
-                        //error handling code we will add the switch.
-                        //NOTE we *could* just add the switch right away rather than
-                        //going through the overhead of sending a role request - however
-                        //we then have to deal with concurrency issues resulting from
-                        //calling addSwitch outside of a netty handler.
-                        sw.sendNxRoleRequest(role, cookie);
-                    }
-                    // Handle case #3
-                    else if (role == Role.SLAVE) {
-                        log.debug("Disconnecting switch {} that doesn't support " +
-                                "role request messages from a controller that went to SLAVE mode");
-                        // Closing the channel should result in a call to
-                        // channelDisconnect which updates all state 
-                        sw.getChannel().close();
-                        iter.remove();
-                    }
-                }
-            } catch (IOException e) {
-                log.warn("Failed to send role request message " +
-                        "to switch {}: {}. Disconnecting",
-                        sw, e);
-                sw.getChannel().close();
-                iter.remove();
-            }
-        }
-    }
-
-    /**
-     * Verify that switches have received a role reply message we sent earlier
-     *
-     * @param switches the collection of switches to send the request too
-     * @param cookie   the cookie of the request
-     */
-    @LogMessageDoc(level = "WARN",
-            message = "Timeout while waiting for role reply from switch {switch}."
-                    + " Disconnecting",
-            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,
-                                           long cookie) {
-        for (OFSwitchImpl sw : switches) {
-            if (sw.checkFirstPendingRoleRequestCookie(cookie)) {
-                sw.getChannel().close();
-                log.warn("Timeout while waiting for role reply from switch {}."
-                        + " Disconnecting", sw);
-            }
-        }
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/SwitchStateException.java b/src/main/java/net/floodlightcontroller/core/internal/SwitchStateException.java
index 8e49799..164346b 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/SwitchStateException.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/SwitchStateException.java
@@ -18,6 +18,13 @@
 package net.floodlightcontroller.core.internal;
 
 /**
+ * This exception indicates an error or unexpected message during
+ * message handling. E.g., if an OFMessage is received that is illegal or
+ * unexpected given the current handshake state.
+ *
+ * We don't allow wrapping other exception in a switch state exception. We
+ * only log the SwitchStateExceptions message so the causing exceptions
+ * stack trace is generally not available.
  *
  */
 public class SwitchStateException extends Exception {
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
index 6913b1c..35ccc08 100644
--- a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
@@ -442,8 +442,10 @@
      * Call each loaded module's startup method
      *
      * @param moduleSet the module set to start up
+     * @throws FloodlightModuleException
      */
-    protected void startupModules(Collection<IFloodlightModule> moduleSet) {
+    protected void startupModules(Collection<IFloodlightModule> moduleSet)
+		throws FloodlightModuleException {
         for (IFloodlightModule m : moduleSet) {
             if (logger.isDebugEnabled()) {
                 logger.debug("Starting " + m.getClass().getCanonicalName());
diff --git a/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java b/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java
index a0ee845..ec08db1 100644
--- a/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java
+++ b/src/main/java/net/floodlightcontroller/core/module/IFloodlightModule.java
@@ -73,5 +73,5 @@
      * @param context
      */
 
-    void startUp(FloodlightModuleContext context);
+    void startUp(FloodlightModuleContext context)throws FloodlightModuleException;
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
index 47f6175..d5b534d 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
@@ -117,12 +117,13 @@
                 // pass - nothing todo besides set the type above
             }
             req.setLengthU(requestLength);
-            try {
+            // XXX S fix when we fix stats
+            /*try {
                 future = sw.getStatistics(req);
                 values = future.get(10, TimeUnit.SECONDS);
             } catch (Exception e) {
                 log.error("Failure retrieving statistics from switch " + sw, e);
-            }
+            }*/
         }
         return values;
     }
@@ -140,12 +141,13 @@
         Future<OFFeaturesReply> future;
         OFFeaturesReply featuresReply = null;
         if (sw != null) {
-            try {
+		// XXX S fix when we fix stats
+            /*try {
                 future = sw.getFeaturesReplyFromSwitch();
                 featuresReply = future.get(10, TimeUnit.SECONDS);
             } catch (Exception e) {
                 log.error("Failure getting features reply from switch" + sw, e);
-            }
+            }*/
         }
 
         return featuresReply;