Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitch.java b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitch.java
index f3568c1..798440a 100644
--- a/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitch.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/OpenFlowSwitch.java
@@ -1,23 +1,78 @@
 package org.onlab.onos.of.controller;
 
+import java.util.List;
+
+import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
 
 /**
- * Abstract model of an OpenFlow Switch.
- *
+ * Represents to provider facing side of a switch.
  */
 public interface OpenFlowSwitch {
 
     /**
-     * Writes the message to this switch.
+     * Writes the message to the driver.
      *
      * @param msg the message to write
      */
     public void sendMsg(OFMessage msg);
 
     /**
+     * Writes to the OFMessage list to the driver.
+     *
+     * @param msgs the messages to be written
+     */
+    public void sendMsg(List<OFMessage> msgs);
+
+    /**
      * Handle a message from the switch.
      * @param fromSwitch the message to handle
      */
     public void handleMessage(OFMessage fromSwitch);
+
+    /**
+     * Sets the role for this switch.
+     * @param role the role to set.
+     */
+    public void setRole(RoleState role);
+
+    /**
+     * Fetch the role for this switch.
+     * @return the role.
+     */
+    public RoleState getRole();
+
+    /**
+     * Fetches the ports of this switch.
+     * @return unmodifiable list of the ports.
+     */
+    public List<OFPortDesc> getPorts();
+
+    /**
+     * Provides the factory for this OF version.
+     * @return OF version specific factory.
+     */
+    public OFFactory factory();
+
+    /**
+     * Gets a string version of the ID for this switch.
+     *
+     * @return string version of the ID
+     */
+    public String getStringId();
+
+    /**
+     * Gets the datapathId of the switch.
+     *
+     * @return the switch dpid in long format
+     */
+    public long getId();
+
+    /**
+     * Disconnects the switch by closing the TCP connection. Results in a call
+     * to the channel handler's channelDisconnected method for cleanup
+     */
+    public void disconnectSwitch();
+
 }
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/RoleState.java b/of/api/src/main/java/org/onlab/onos/of/controller/RoleState.java
index 527a91c..db8efd1 100644
--- a/of/api/src/main/java/org/onlab/onos/of/controller/RoleState.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/RoleState.java
@@ -21,3 +21,5 @@
 
 }
 
+
+
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/AbstractOpenFlowSwitch.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/AbstractOpenFlowSwitch.java
similarity index 64%
rename from of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/AbstractOpenFlowSwitch.java
rename to of/api/src/main/java/org/onlab/onos/of/controller/driver/AbstractOpenFlowSwitch.java
index 534daa0..ce6365a 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/AbstractOpenFlowSwitch.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/AbstractOpenFlowSwitch.java
@@ -15,7 +15,7 @@
  *    under the License.
  **/
 
-package org.onlab.onos.of.controller.impl.internal;
+package org.onlab.onos.of.controller.driver;
 
 import java.io.IOException;
 import java.util.Collections;
@@ -24,11 +24,7 @@
 
 import org.jboss.netty.channel.Channel;
 import org.onlab.onos.of.controller.Dpid;
-import org.onlab.onos.of.controller.OpenFlowSwitch;
 import org.onlab.onos.of.controller.RoleState;
-import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent;
-import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleRecvStatus;
-import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleReplyInfo;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
 import org.projectfloodlight.openflow.protocol.OFExperimenter;
@@ -43,19 +39,22 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
-public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
+/**
+ * An abstract representation of an OpenFlow switch. Can be extended by others
+ * to serve as a base for their vendor specific representation of a switch.
+ */
+public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
 
     private static Logger log =
             LoggerFactory.getLogger(AbstractOpenFlowSwitch.class);
 
     protected Channel channel;
-    protected boolean startDriverHandshakeCalled = false;
 
     private boolean connected;
-    private Dpid dpid;
-    private OpenFlowSwitchAgent agent;
-    private AtomicInteger xidCounter = new AtomicInteger(0);
+    protected boolean startDriverHandshakeCalled = false;
+    private final Dpid dpid;
+    private OpenFlowAgent agent;
+    private final AtomicInteger xidCounter = new AtomicInteger(0);
 
     private OFVersion ofVersion;
 
@@ -63,12 +62,17 @@
 
     protected boolean tableFull;
 
-    private final RoleManager roleMan = new RoleManager(this);
+    private RoleHandler roleMan;
 
     protected RoleState role;
 
     protected OFFeaturesReply features;
+    protected OFDescStatsReply desc;
 
+    /**
+     * Given a dpid build this switch.
+     * @param dp the dpid
+     */
     protected AbstractOpenFlowSwitch(Dpid dp) {
         this.dpid = dp;
     }
@@ -77,59 +81,38 @@
     // 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
-     */
+    @Override
     public final void disconnectSwitch() {
         this.channel.close();
     }
 
-    /**
-     * Writes to the OFMessage to the output stream.
-     *
-     * @param m the message to be written
-     */
-    public abstract void sendMsg(OFMessage m);
-
-    /**
-     * Writes to the OFMessage list to the output stream.
-     *
-     * @param msgs the messages to be written
-     */
-    public void write(List<OFMessage> msgs) {
-        this.channel.write(msgs);
+    @Override
+    public final void sendMsg(OFMessage m) {
+        this.write(m);
     }
 
+    @Override
+    public final void sendMsg(List<OFMessage> msgs) {
+        this.write(msgs);
+    }
 
-    /**
-     * Checks if the switch is still connected.
-     * Only call while holding processMessageLock
-     *
-     * @return whether the switch is still disconnected
-     */
+    @Override
+    public abstract void write(OFMessage msg);
+
+    @Override
+    public abstract void write(List<OFMessage> msgs);
+
+    @Override
     public final boolean isConnected() {
         return this.connected;
     }
 
-    /**
-     * Sets whether the switch is connected.
-     * Only call while holding modifySwitchLock
-     *
-     * @param connected whether the switch is connected
-     */
-    final void setConnected(boolean connected) {
+    @Override
+    public final void setConnected(boolean connected) {
         this.connected = connected;
     };
 
-    /**
-     * Sets the Netty Channel this switch instance is associated with.
-     * <p>
-     * Called immediately after instantiation
-     *
-     * @param channel the channel
-     */
+    @Override
     public final void setChannel(Channel channel) {
         this.channel = channel;
     };
@@ -138,41 +121,32 @@
     // Switch features related
     //************************
 
-    /**
-     * Gets the datapathId of the switch.
-     *
-     * @return the switch buffers
-     */
+    @Override
     public final long getId() {
         return this.dpid.value();
     };
 
-    /**
-     * Gets a string version of the ID for this switch.
-     *
-     * @return string version of the ID
-     */
+    @Override
     public final String getStringId() {
         return this.dpid.toString();
     }
 
+    @Override
     public final void setOFVersion(OFVersion ofV) {
         this.ofVersion = ofV;
     }
 
-    void setTableFull(boolean full) {
+    @Override
+    public void setTableFull(boolean full) {
         this.tableFull = full;
     }
 
+    @Override
     public void setFeaturesReply(OFFeaturesReply featuresReply) {
         this.features = featuresReply;
     }
 
-    /**
-     * Let peoeple know if you support Nicira style role requests.
-     *
-     * @return support Nicira roles or not.
-     */
+    @Override
     public abstract Boolean supportNxRole();
 
     //************************
@@ -183,65 +157,80 @@
      *
      * @param m the actual message
      */
+    @Override
     public final void handleMessage(OFMessage m) {
         this.agent.processMessage(m);
     }
 
+    @Override
     public RoleState getRole() {
         return role;
     };
 
-    final boolean addConnectedSwitch() {
-        return this.agent.addConnectedSwitch(this.getId(), this);
+    @Override
+    public final boolean connectSwitch() {
+        return this.agent.addConnectedSwitch(dpid, this);
     }
 
-    final boolean addActivatedMasterSwitch() {
-        return this.agent.addActivatedMasterSwitch(this.getId(), this);
+    @Override
+    public final boolean activateMasterSwitch() {
+        return this.agent.addActivatedMasterSwitch(dpid, this);
     }
 
-    final boolean addActivatedEqualSwitch() {
-        return this.agent.addActivatedEqualSwitch(this.getId(), this);
+    @Override
+    public final boolean activateEqualSwitch() {
+        return this.agent.addActivatedEqualSwitch(dpid, this);
     }
 
-    final void transitionToEqualSwitch() {
-        this.agent.transitionToEqualSwitch(this.getId());
+    @Override
+    public final void transitionToEqualSwitch() {
+        this.agent.transitionToEqualSwitch(dpid);
     }
 
-    final void transitionToMasterSwitch() {
-        this.agent.transitionToMasterSwitch(this.getId());
+    @Override
+    public final void transitionToMasterSwitch() {
+        this.agent.transitionToMasterSwitch(dpid);
     }
 
-    final void removeConnectedSwitch() {
-        this.agent.removeConnectedSwitch(this.getId());
+    @Override
+    public final void removeConnectedSwitch() {
+        this.agent.removeConnectedSwitch(dpid);
     }
 
-    protected OFFactory factory() {
+    @Override
+    public OFFactory factory() {
         return OFFactories.getFactory(ofVersion);
     }
 
+    @Override
     public void setPortDescReply(OFPortDescStatsReply portDescReply) {
         this.ports = portDescReply;
     }
 
+    @Override
     public abstract void startDriverHandshake();
 
+    @Override
     public abstract boolean isDriverHandshakeComplete();
 
+    @Override
     public abstract void processDriverHandshakeMessage(OFMessage m);
 
+    @Override
     public void setRole(RoleState role) {
         try {
             if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
                 this.role = role;
             }
         } catch (IOException e) {
-           log.error("Unable to write to switch {}.", this.dpid);
+            log.error("Unable to write to switch {}.", this.dpid);
         }
     }
 
     // Role Handling
 
-    void handleRole(OFMessage m) throws SwitchStateException {
+    @Override
+    public void handleRole(OFMessage m) throws SwitchStateException {
         RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
         RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
         if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
@@ -254,7 +243,8 @@
         }
     }
 
-    void handleNiciraRole(OFMessage m) throws SwitchStateException {
+    @Override
+    public void handleNiciraRole(OFMessage m) throws SwitchStateException {
         RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
         if (r == null) {
             // The message wasn't really a Nicira role reply. We just
@@ -274,7 +264,8 @@
         }
     }
 
-    boolean handleRoleError(OFErrorMsg error) {
+    @Override
+    public boolean handleRoleError(OFErrorMsg error) {
         try {
             return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
         } catch (SwitchStateException e) {
@@ -283,25 +274,39 @@
         return true;
     }
 
-    void reassertRole() {
+    @Override
+    public void reassertRole() {
         if (this.getRole() == RoleState.MASTER) {
             this.setRole(RoleState.MASTER);
         }
     }
 
-    void setAgent(OpenFlowSwitchAgent ag) {
-        this.agent = ag;
+    @Override
+    public final void setAgent(OpenFlowAgent ag) {
+        if (this.agent == null) {
+            this.agent = ag;
+        }
     }
 
-    public void setSwitchDescription(OFDescStatsReply desc) {
-        // TODO Auto-generated method stub
+    @Override
+    public final void setRoleHandler(RoleHandler roleHandler) {
+        if (this.roleMan == null) {
+            this.roleMan = roleHandler;
+        }
     }
 
-    protected int getNextTransactionId() {
+    @Override
+    public void setSwitchDescription(OFDescStatsReply d) {
+        this.desc = d;
+    }
+
+    @Override
+    public int getNextTransactionId() {
         return this.xidCounter.getAndIncrement();
     }
 
-    protected List<OFPortDesc> getPorts() {
+    @Override
+    public List<OFPortDesc> getPorts() {
         return Collections.unmodifiableList(ports.getEntries());
     }
 
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/driver/OpenFlowAgent.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/OpenFlowAgent.java
new file mode 100644
index 0000000..a0f64e2
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/OpenFlowAgent.java
@@ -0,0 +1,75 @@
+package org.onlab.onos.of.controller.driver;
+
+import org.onlab.onos.of.controller.Dpid;
+import org.onlab.onos.of.controller.OpenFlowSwitch;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
+/**
+ * Responsible for keeping track of the current set of switches
+ * connected to the system. As well as whether they are in Master
+ * role or not.
+ *
+ */
+public interface OpenFlowAgent {
+
+    /**
+     * Add a switch that has just connected to the system.
+     * @param dpid the dpid to add
+     * @param sw the actual switch object.
+     * @return true if added, false otherwise.
+     */
+    public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw);
+
+    /**
+     * Checks if the activation for this switch is valid.
+     * @param dpid the dpid to check
+     * @return true if valid, false otherwise
+     */
+    public boolean validActivation(Dpid dpid);
+
+    /**
+     * Called when a switch is activated, with this controller's role as MASTER.
+     * @param dpid the dpid to add.
+     * @param sw the actual switch
+     * @return true if added, false otherwise.
+     */
+    public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw);
+
+    /**
+     * Called when a switch is activated, with this controller's role as EQUAL.
+     * @param dpid the dpid to add.
+     * @param sw the actual switch
+     * @return true if added, false otherwise.
+     */
+    public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw);
+
+    /**
+     * 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'.
+     * @param dpid the dpid to transistion.
+     */
+    public void transitionToMasterSwitch(Dpid dpid);
+
+    /**
+     * 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'.
+     * @param dpid the dpid to transistion.
+     */
+    public void transitionToEqualSwitch(Dpid dpid);
+
+    /**
+     * 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.
+     * @param dpid the dpid to remove.
+     */
+    public void removeConnectedSwitch(Dpid dpid);
+
+    /**
+     * Process a message coming from a switch.
+     * @param m the message to process
+     */
+    public void processMessage(OFMessage m);
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/driver/OpenFlowSwitchDriver.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/OpenFlowSwitchDriver.java
new file mode 100644
index 0000000..be99973
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/OpenFlowSwitchDriver.java
@@ -0,0 +1,197 @@
+package org.onlab.onos.of.controller.driver;
+
+import java.util.List;
+
+import org.jboss.netty.channel.Channel;
+import org.onlab.onos.of.controller.OpenFlowSwitch;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+/**
+ * Represents the driver side of an OpenFlow switch.
+ * This interface should never be exposed to consumers.
+ *
+ */
+public interface OpenFlowSwitchDriver extends OpenFlowSwitch {
+
+    /**
+     * Sets the OpenFlow agent to be used. This method
+     * can only be called once.
+     * @param agent the agent to set.
+     */
+    public void setAgent(OpenFlowAgent agent);
+
+    /**
+     * Sets the Role handler object.
+     * This method can only be called once.
+     * @param roleHandler the roleHandler class
+     */
+    public void setRoleHandler(RoleHandler roleHandler);
+
+    /**
+     * Reasserts this controllers role to the switch.
+     * Useful in cases where the switch no longer agrees
+     * that this controller has the role it claims.
+     */
+    public void reassertRole();
+
+    /**
+     * Handle the situation where the role request triggers an error.
+     * @param error the error to handle.
+     * @return true if handled, false if not.
+     */
+    public boolean handleRoleError(OFErrorMsg error);
+
+    /**
+     * If this driver know of Nicira style role messages, these should
+     * be handled here.
+     * @param m the role message to handle.
+     * @throws SwitchStateException if the message received was
+     *  not a nicira role or was malformed.
+     */
+    public void handleNiciraRole(OFMessage m) throws SwitchStateException;
+
+    /**
+     * Handle OF 1.x (where x > 0) role messages.
+     * @param m the role message to handle
+     * @throws SwitchStateException if the message received was
+     *  not a nicira role or was malformed.
+     */
+    public void handleRole(OFMessage m) throws SwitchStateException;
+
+    /**
+     * Starts the driver specific handshake process.
+     */
+    public void startDriverHandshake();
+
+    /**
+     * Checks whether the driver specific handshake is complete.
+     * @return true is finished, false if not.
+     */
+    public boolean isDriverHandshakeComplete();
+
+    /**
+     * Process a message during the driver specific handshake.
+     * @param m the message to process.
+     */
+    public void processDriverHandshakeMessage(OFMessage m);
+
+    /**
+     * Announce to the OpenFlow agent that this switch has connected.
+     * @return true if successful, false if duplicate switch.
+     */
+    public boolean connectSwitch();
+
+    /**
+     * Activate this MASTER switch-controller relationship in the OF agent.
+     * @return true is successful, false is switch has not
+     * connected or is unknown to the system.
+     */
+    public boolean activateMasterSwitch();
+
+    /**
+     * Activate this EQUAL switch-controller relationship in the OF agent.
+     * @return true is successful, false is switch has not
+     * connected or is unknown to the system.
+     */
+    public boolean activateEqualSwitch();
+
+    /**
+     * Transition this switch-controller relationship to an EQUAL state.
+     */
+    public void transitionToEqualSwitch();
+
+    /**
+     * Transition this switch-controller relationship to an Master state.
+     */
+    public void transitionToMasterSwitch();
+
+    /**
+     * Remove this switch from the openflow agent.
+     */
+    public void removeConnectedSwitch();
+
+    /**
+     * Sets the ports on this switch.
+     * @param portDescReply the port set and descriptions
+     */
+    public void setPortDescReply(OFPortDescStatsReply portDescReply);
+
+    /**
+     * Sets the features reply for this switch.
+     * @param featuresReply the features to set.
+     */
+    public void setFeaturesReply(OFFeaturesReply featuresReply);
+
+    /**
+     * Sets the switch description.
+     * @param desc the descriptions
+     */
+    public void setSwitchDescription(OFDescStatsReply desc);
+
+    /**
+     * Gets the next transaction id to use.
+     * @return the xid
+     */
+    public int getNextTransactionId();
+
+
+    /**
+     * Does this switch support Nicira Role messages.
+     * @return true if supports, false otherwise.
+     */
+    public Boolean supportNxRole();
+
+    /**
+     * Sets the OF version for this switch.
+     * @param ofV the version to set.
+     */
+    public void setOFVersion(OFVersion ofV);
+
+    /**
+     * Sets this switch has having a full flowtable.
+     * @param full true if full, false otherswise.
+     */
+    public void setTableFull(boolean full);
+
+    /**
+     * Sets the associated Netty channel for this switch.
+     * @param channel the Netty channel
+     */
+    public void setChannel(Channel channel);
+
+    /**
+     * Sets whether the switch is connected.
+     *
+     * @param connected whether the switch is connected
+     */
+    public void setConnected(boolean connected);
+
+    /**
+     * Checks if the switch is still connected.
+     *
+     * @return whether the switch is still connected
+     */
+    public boolean isConnected();
+
+    /**
+     * Writes the message to the output stream
+     * in a driver specific manner.
+     *
+     * @param msg the message to write
+     */
+    public void write(OFMessage msg);
+
+    /**
+     * Writes to the OFMessage list to the output stream
+     * in a driver specific manner.
+     *
+     * @param msgs the messages to be written
+     */
+    public void write(List<OFMessage> msgs);
+
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/driver/OpenFlowSwitchDriverFactory.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/OpenFlowSwitchDriverFactory.java
new file mode 100644
index 0000000..4e84d28
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/OpenFlowSwitchDriverFactory.java
@@ -0,0 +1,24 @@
+package org.onlab.onos.of.controller.driver;
+
+import org.onlab.onos.of.controller.Dpid;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+/**
+ * Switch factory which returns concrete switch objects for the
+ * physical openflow switch in use.
+ *
+ */
+public interface OpenFlowSwitchDriverFactory {
+
+
+    /**
+     * Constructs the real openflow switch representation.
+     * @param dpid the dpid for this switch.
+     * @param desc its description.
+     * @param ofv the OF version in use
+     * @return the openflow switch representation.
+     */
+    public OpenFlowSwitchDriver getOFSwitchImpl(Dpid dpid,
+            OFDescStatsReply desc, OFVersion ofv);
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/driver/RoleHandler.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/RoleHandler.java
new file mode 100644
index 0000000..ac1e1ab
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/RoleHandler.java
@@ -0,0 +1,95 @@
+package org.onlab.onos.of.controller.driver;
+
+import java.io.IOException;
+
+import org.onlab.onos.of.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFExperimenter;
+import org.projectfloodlight.openflow.protocol.OFRoleReply;
+
+/**
+ * Role handling.
+ *
+ */
+public interface RoleHandler {
+
+    /**
+     * 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 experimenterMsg 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.
+     */
+    public RoleState extractNiciraRoleReply(OFExperimenter experimenterMsg)
+            throws SwitchStateException;
+
+    /**
+     * 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.
+     */
+    public boolean sendRoleRequest(RoleState role, RoleRecvStatus exp)
+            throws IOException;
+
+    /**
+     * Extract the role information from an OF1.3 Role Reply Message.
+     * @param h
+     * @param rrmsg
+     * @return RoleReplyInfo object
+     * @throws SwitchStateException
+     */
+    public RoleReplyInfo extractOFRoleReply(OFRoleReply rrmsg)
+            throws SwitchStateException;
+
+    /**
+     * 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 rri information about role-reply in format that
+     *                      controller can understand.
+     * @throws SwitchStateException if no request is pending
+     */
+    public RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
+            throws SwitchStateException;
+
+
+    /**
+     * 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
+     */
+    public RoleRecvStatus deliverError(OFErrorMsg error)
+            throws SwitchStateException;
+
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/driver/RoleRecvStatus.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/RoleRecvStatus.java
new file mode 100644
index 0000000..0a10978
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/RoleRecvStatus.java
@@ -0,0 +1,37 @@
+package org.onlab.onos.of.controller.driver;
+
+/**
+ * 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.
+ */
+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,
+}
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/driver/RoleReplyInfo.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/RoleReplyInfo.java
new file mode 100644
index 0000000..cc3c483
--- /dev/null
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/RoleReplyInfo.java
@@ -0,0 +1,27 @@
+package org.onlab.onos.of.controller.driver;
+
+import org.onlab.onos.of.controller.RoleState;
+import org.projectfloodlight.openflow.types.U64;
+
+/**
+ * Helper class returns role reply information in the format understood
+ * by the controller.
+ */
+public class RoleReplyInfo {
+    private final RoleState role;
+    private final U64 genId;
+    private final long xid;
+
+    public RoleReplyInfo(RoleState role, U64 genId, long xid) {
+        this.role = role;
+        this.genId = genId;
+        this.xid = xid;
+    }
+    public RoleState getRole() { return role; }
+    public U64 getGenId() { return genId; }
+    public long getXid() { return xid; }
+    @Override
+    public String toString() {
+        return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
+    }
+}
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeAlreadyStarted.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeAlreadyStarted.java
similarity index 86%
rename from of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeAlreadyStarted.java
rename to of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeAlreadyStarted.java
index 53227aa..16ed93a 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeAlreadyStarted.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeAlreadyStarted.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.of.controller.impl.internal;
+package org.onlab.onos.of.controller.driver;
 
 /**
  * Thrown when IOFSwitch.startDriverHandshake() is called more than once.
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeCompleted.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeCompleted.java
similarity index 91%
rename from of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeCompleted.java
rename to of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeCompleted.java
index ba792e5..1c6dac9 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeCompleted.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeCompleted.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.of.controller.impl.internal;
+package org.onlab.onos.of.controller.driver;
 
 import org.projectfloodlight.openflow.protocol.OFMessage;
 
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeException.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeException.java
similarity index 91%
rename from of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeException.java
rename to of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeException.java
index 49fdead..1c9a710 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeException.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeException.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.of.controller.impl.internal;
+package org.onlab.onos.of.controller.driver;
 
 /**
  * Base class for exception thrown by switch driver sub-handshake processing.
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeNotStarted.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeNotStarted.java
similarity index 87%
rename from of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeNotStarted.java
rename to of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeNotStarted.java
index 72b17dc..0f34b0e 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeNotStarted.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeNotStarted.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.of.controller.impl.internal;
+package org.onlab.onos.of.controller.driver;
 
 /**
  * Thrown when a switch driver's sub-handshake has not been started but an
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeStateException.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeStateException.java
similarity index 88%
rename from of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeStateException.java
rename to of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeStateException.java
index 191d1bb..09e737e 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchDriverSubHandshakeStateException.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchDriverSubHandshakeStateException.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.of.controller.impl.internal;
+package org.onlab.onos.of.controller.driver;
 
 /**
  * Thrown when a switch driver's sub-handshake state-machine receives an
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchStateException.java b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchStateException.java
similarity index 96%
rename from of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchStateException.java
rename to of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchStateException.java
index d82e917..55b12de 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/SwitchStateException.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/driver/SwitchStateException.java
@@ -15,7 +15,7 @@
  *    under the License.
  **/
 
-package org.onlab.onos.of.controller.impl.internal;
+package org.onlab.onos.of.controller.driver;
 
 /**
  * This exception indicates an error or unexpected message during
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java
index b88a9ec..ab9315f 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/Controller.java
@@ -30,9 +30,10 @@
 import org.jboss.netty.channel.group.DefaultChannelGroup;
 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
 import org.onlab.onos.of.controller.Dpid;
+import org.onlab.onos.of.controller.driver.OpenFlowAgent;
+import org.onlab.onos.of.controller.driver.OpenFlowSwitchDriver;
 import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
 import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
-import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent;
 import org.onlab.onos.of.drivers.DriverManager;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFFactories;
@@ -74,7 +75,7 @@
 
     // Flag to always flush flow table on switch reconnect (HA or otherwise)
     protected boolean alwaysClearFlowsOnSwAdd = false;
-    private OpenFlowSwitchAgent agent;
+    private OpenFlowAgent agent;
 
     // Perf. related configuration
     protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
@@ -120,17 +121,17 @@
      * Tell controller that we're ready to accept switches loop.
      */
     @LogMessageDocs({
-            @LogMessageDoc(message = "Listening for switch connections on {address}",
-                    explanation = "The controller is ready and listening for new" +
-                            " switch connections"),
-            @LogMessageDoc(message = "Storage exception in controller " +
-                    "updates loop; terminating process",
-                    explanation = ERROR_DATABASE,
-                    recommendation = LogMessageDoc.CHECK_CONTROLLER),
-            @LogMessageDoc(level = "ERROR",
-                    message = "Exception in controller updates loop",
-                    explanation = "Failed to dispatch controller event",
-                    recommendation = LogMessageDoc.GENERIC_ACTION)
+        @LogMessageDoc(message = "Listening for switch connections on {address}",
+                explanation = "The controller is ready and listening for new" +
+                " switch connections"),
+                @LogMessageDoc(message = "Storage exception in controller " +
+                        "updates loop; terminating process",
+                        explanation = ERROR_DATABASE,
+                        recommendation = LogMessageDoc.CHECK_CONTROLLER),
+                        @LogMessageDoc(level = "ERROR",
+                        message = "Exception in controller updates loop",
+                        explanation = "Failed to dispatch controller event",
+                        recommendation = LogMessageDoc.GENERIC_ACTION)
     })
     public void run() {
 
@@ -221,15 +222,16 @@
      * @param desc
      * @return switch instance
      */
-    protected AbstractOpenFlowSwitch getOFSwitchInstance(long dpid,
+    protected OpenFlowSwitchDriver getOFSwitchInstance(long dpid,
             OFDescStatsReply desc, OFVersion ofv) {
-        AbstractOpenFlowSwitch sw = DriverManager.getOFSwitchImpl(new Dpid(dpid),
+        OpenFlowSwitchDriver sw = DriverManager.getSwitch(new Dpid(dpid),
                 desc, ofv);
         sw.setAgent(agent);
+        sw.setRoleHandler(new RoleManager(sw));
         return sw;
     }
 
-    public void start(OpenFlowSwitchAgent ag) {
+    public void start(OpenFlowAgent ag) {
         log.info("Initialising OpenFlow Lib and IO");
         this.agent = ag;
         this.init(new HashMap<String, String>());
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/IOFSwitchManager.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/IOFSwitchManager.java
index 4b2f7c3..035c4ca 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/IOFSwitchManager.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/IOFSwitchManager.java
@@ -1,5 +1,6 @@
 package org.onlab.onos.of.controller.impl.internal;
 
+import org.onlab.onos.of.controller.driver.AbstractOpenFlowSwitch;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 
 
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java
index 23bc994..768362f 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OFChannelHandler.java
@@ -18,6 +18,8 @@
 import org.jboss.netty.handler.timeout.IdleStateEvent;
 import org.jboss.netty.handler.timeout.ReadTimeoutException;
 import org.onlab.onos.of.controller.RoleState;
+import org.onlab.onos.of.controller.driver.OpenFlowSwitchDriver;
+import org.onlab.onos.of.controller.driver.SwitchStateException;
 import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
 import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
@@ -66,7 +68,7 @@
 class OFChannelHandler extends IdleStateAwareChannelHandler {
     private static final Logger log = LoggerFactory.getLogger(OFChannelHandler.class);
     private final Controller controller;
-    private AbstractOpenFlowSwitch sw;
+    private OpenFlowSwitchDriver sw;
     private long thisdpid; // channelHandler cached value of connected switch id
     private Channel channel;
     // State needs to be volatile because the HandshakeTimeoutHandler
@@ -413,7 +415,7 @@
                 OFDescStatsReply drep = (OFDescStatsReply) m;
                 // Here is where we differentiate between different kinds of switches
                 h.sw = h.controller.getOFSwitchInstance(h.thisdpid, drep, h.ofVersion);
-                boolean success = h.sw.addConnectedSwitch();
+                boolean success = h.sw.connectSwitch();
                 if (!success) {
                     disconnectDuplicate(h);
                     return;
@@ -431,7 +433,7 @@
                 //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.sw.addActivatedEqualSwitch();
+                h.sw.activateEqualSwitch();
                 //h.setSwitchRole(RoleState.EQUAL);
                 h.setSwitchRole(RoleState.MASTER);
                 h.sw.startDriverHandshake();
@@ -489,8 +491,8 @@
                         }
                     }
                 } else {
-                    if (m.getType() == OFType.EXPERIMENTER && 
-                            ((OFExperimenter) m).getExperimenter() == 
+                    if (m.getType() == OFType.EXPERIMENTER &&
+                            ((OFExperimenter) m).getExperimenter() ==
                             RoleManager.NICIRA_EXPERIMENTER) {
                         h.sw.handleNiciraRole(m);
                     } else {
@@ -848,8 +850,8 @@
                 processOFQueueGetConfigReply(h, (OFQueueGetConfigReply) m);
                 break;
             case STATS_REPLY: // multipart_reply in 1.3
-            processOFStatisticsReply(h, (OFStatsReply) m);
-            break;
+                processOFStatisticsReply(h, (OFStatsReply) m);
+                break;
             case EXPERIMENTER:
                 processOFExperimenter(h, (OFExperimenter) m);
                 break;
@@ -916,12 +918,12 @@
             }
             OFFactory factory = (h.ofVersion == OFVersion.OF_13) ?
                     h.controller.getOFMessageFactory13() : h.controller.getOFMessageFactory10();
-            OFEchoReply reply = factory
-                    .buildEchoReply()
-                    .setXid(m.getXid())
-                    .setData(m.getData())
-                    .build();
-            h.channel.write(Collections.singletonList(reply));
+                    OFEchoReply reply = factory
+                            .buildEchoReply()
+                            .setXid(m.getXid())
+                            .setData(m.getData())
+                            .build();
+                    h.channel.write(Collections.singletonList(reply));
         }
 
         void processOFEchoReply(OFChannelHandler h, OFEchoReply m)
@@ -1044,41 +1046,41 @@
                 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),
+                        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)
+                        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 {
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java
index f846e65..b7ba4c7 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/OpenFlowControllerImpl.java
@@ -15,8 +15,9 @@
 import org.onlab.onos.of.controller.OpenFlowSwitchListener;
 import org.onlab.onos.of.controller.PacketListener;
 import org.onlab.onos.of.controller.RoleState;
+import org.onlab.onos.of.controller.driver.AbstractOpenFlowSwitch;
+import org.onlab.onos.of.controller.driver.OpenFlowAgent;
 import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -27,12 +28,12 @@
     private static final Logger log =
             LoggerFactory.getLogger(OpenFlowControllerImpl.class);
 
-    protected ConcurrentHashMap<Long, OpenFlowSwitch> connectedSwitches =
-            new ConcurrentHashMap<Long, OpenFlowSwitch>();
-    protected ConcurrentHashMap<Long, OpenFlowSwitch> activeMasterSwitches =
-            new ConcurrentHashMap<Long, OpenFlowSwitch>();
-    protected ConcurrentHashMap<Long, OpenFlowSwitch> activeEqualSwitches =
-            new ConcurrentHashMap<Long, OpenFlowSwitch>();
+    protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
+            new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
+    protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
+            new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
+    protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
+            new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
 
     protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
     protected ArrayList<OpenFlowSwitchListener> ofEventListener =
@@ -118,12 +119,13 @@
         ((AbstractOpenFlowSwitch) getSwitch(dpid)).setRole(role);
     }
 
-    public class OpenFlowSwitchAgent {
+    public class OpenFlowSwitchAgent implements OpenFlowAgent {
 
         private final Logger log = LoggerFactory.getLogger(OpenFlowSwitchAgent.class);
-        private Lock switchLock = new ReentrantLock();
+        private final Lock switchLock = new ReentrantLock();
 
-        public boolean addConnectedSwitch(long dpid, AbstractOpenFlowSwitch sw) {
+        @Override
+        public boolean addConnectedSwitch(Dpid dpid, OpenFlowSwitch sw) {
             if (connectedSwitches.get(dpid) != null) {
                 log.error("Trying to add connectedSwitch but found a previous "
                         + "value for dpid: {}", dpid);
@@ -132,17 +134,18 @@
                 log.error("Added switch {}", dpid);
                 connectedSwitches.put(dpid, sw);
                 for (OpenFlowSwitchListener l : ofEventListener) {
-                    l.switchAdded(new Dpid(dpid));
+                    l.switchAdded(dpid);
                 }
                 return true;
             }
         }
 
-        private boolean validActivation(long dpid) {
+        @Override
+        public boolean validActivation(Dpid dpid) {
             if (connectedSwitches.get(dpid) == null) {
                 log.error("Trying to activate switch but is not in "
                         + "connected switches: dpid {}. Aborting ..",
-                        HexString.toHexString(dpid));
+                        dpid);
                 return false;
             }
             if (activeMasterSwitches.get(dpid) != null ||
@@ -150,18 +153,17 @@
                 log.error("Trying to activate switch but it is already "
                         + "activated: dpid {}. Found in activeMaster: {} "
                         + "Found in activeEqual: {}. Aborting ..", new Object[] {
-                                HexString.toHexString(dpid),
+                                dpid,
                                 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
-                                (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
+                                        (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
                 return false;
             }
             return true;
         }
 
-        /**
-         * Called when a switch is activated, with this controller's role as MASTER.
-         */
-        protected boolean addActivatedMasterSwitch(long dpid, AbstractOpenFlowSwitch sw) {
+
+        @Override
+        public boolean addActivatedMasterSwitch(Dpid dpid, OpenFlowSwitch sw) {
             switchLock.lock();
             try {
                 if (!validActivation(dpid)) {
@@ -172,31 +174,25 @@
             } finally {
                 switchLock.unlock();
             }
-    }
+        }
 
-        /**
-         * Called when a switch is activated, with this controller's role as EQUAL.
-         */
-        protected boolean addActivatedEqualSwitch(long dpid, AbstractOpenFlowSwitch sw) {
+        @Override
+        public boolean addActivatedEqualSwitch(Dpid dpid, OpenFlowSwitch sw) {
             switchLock.lock();
             try {
-                    if (!validActivation(dpid)) {
-                        return false;
-                    }
-                    activeEqualSwitches.put(dpid, sw);
-                    log.info("Added Activated EQUAL Switch {}", dpid);
-                    return true;
+                if (!validActivation(dpid)) {
+                    return false;
+                }
+                activeEqualSwitches.put(dpid, sw);
+                log.info("Added Activated EQUAL Switch {}", dpid);
+                return true;
             } finally {
                 switchLock.unlock();
             }
         }
 
-        /**
-         * 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) {
+        @Override
+        public void transitionToMasterSwitch(Dpid dpid) {
             switchLock.lock();
             try {
                 if (activeMasterSwitches.containsKey(dpid)) {
@@ -215,12 +211,8 @@
         }
 
 
-        /**
-         * 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) {
+        @Override
+        public void transitionToEqualSwitch(Dpid dpid) {
             switchLock.lock();
             try {
                 if (activeEqualSwitches.containsKey(dpid)) {
@@ -239,22 +231,19 @@
 
         }
 
-        /**
-         * 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.
-         */
-        public void removeConnectedSwitch(long dpid) {
+        @Override
+        public void removeConnectedSwitch(Dpid dpid) {
             connectedSwitches.remove(dpid);
             OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
             if (sw == null) {
                 sw = activeEqualSwitches.remove(dpid);
             }
             for (OpenFlowSwitchListener l : ofEventListener) {
-                l.switchRemoved(new Dpid(dpid));
+                l.switchRemoved(dpid);
             }
         }
 
+        @Override
         public void processMessage(OFMessage m) {
             processPacket(m);
         }
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java
index 99e9173..235eb61 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java
@@ -4,6 +4,11 @@
 import java.util.Collections;
 
 import org.onlab.onos.of.controller.RoleState;
+import org.onlab.onos.of.controller.driver.OpenFlowSwitchDriver;
+import org.onlab.onos.of.controller.driver.RoleHandler;
+import org.onlab.onos.of.controller.driver.RoleRecvStatus;
+import org.onlab.onos.of.controller.driver.RoleReplyInfo;
+import org.onlab.onos.of.controller.driver.SwitchStateException;
 import org.projectfloodlight.openflow.protocol.OFControllerRole;
 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
 import org.projectfloodlight.openflow.protocol.OFErrorType;
@@ -35,7 +40,7 @@
  * a new request is submitted before the timeout triggers. If necessary
  * we could work around that though.
  */
-class RoleManager {
+class RoleManager implements RoleHandler {
     protected static final long NICIRA_EXPERIMENTER = 0x2320;
 
     private static Logger log = LoggerFactory.getLogger(RoleManager.class);
@@ -49,10 +54,10 @@
 
     // the expectation set by the caller for the returned role
     private RoleRecvStatus expectation;
-    private AbstractOpenFlowSwitch sw;
+    private final OpenFlowSwitchDriver sw;
 
 
-    public RoleManager(AbstractOpenFlowSwitch sw) {
+    public RoleManager(OpenFlowSwitchDriver sw) {
         this.requestPending = false;
         this.pendingXid = -1;
         this.pendingRole = null;
@@ -122,33 +127,13 @@
         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(RoleState role, RoleRecvStatus exp)
+    @Override
+    public synchronized boolean sendRoleRequest(RoleState role, RoleRecvStatus exp)
             throws IOException {
         this.expectation = exp;
 
         if (sw.factory().getVersion() == OFVersion.OF_10) {
-            Boolean supportsNxRole = (Boolean)
-                    sw.supportNxRole();
+            Boolean supportsNxRole = sw.supportNxRole();
             if (!supportsNxRole) {
                 log.debug("Switch driver indicates no support for Nicira "
                         + "role request messages. Not sending ...");
@@ -189,23 +174,9 @@
 
     }
 
-    /**
-     * 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)
+
+    @Override
+    public synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
             throws SwitchStateException {
         if (!requestPending) {
             RoleState currentRole = (sw != null) ? sw.getRole() : null;
@@ -280,12 +251,13 @@
      * error messages for earlier role requests that we won't be able
      * to handle
      */
-    synchronized RoleRecvStatus deliverError(OFErrorMsg error)
+    @Override
+    public 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 ...",
-                   sw.getStringId());
+                    sw.getStringId());
             return RoleRecvStatus.OTHER_EXPECTATION;
         }
         if (pendingXid != error.getXid()) {
@@ -353,7 +325,8 @@
      * @throws SwitchStateException If the message is a Nicira role reply
      * but the numeric role value is unknown.
      */
-    protected RoleState extractNiciraRoleReply(OFExperimenter experimenterMsg)
+    @Override
+    public RoleState extractNiciraRoleReply(OFExperimenter experimenterMsg)
             throws SwitchStateException {
         int vendor = (int) experimenterMsg.getExperimenter();
         if (vendor != 0x2320) {
@@ -389,72 +362,14 @@
     }
 
     /**
-     * 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.
-     */
-    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,
-    }
-
-    /**
-     * Helper class returns role reply information in the format understood
-     * by the controller.
-     */
-    protected static class RoleReplyInfo {
-        private RoleState role;
-        private U64 genId;
-        private long xid;
-
-        RoleReplyInfo(RoleState role, U64 genId, long xid) {
-            this.role = role;
-            this.genId = genId;
-            this.xid = xid;
-        }
-        public RoleState 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
+     * @param rrmsg the role message
      * @return RoleReplyInfo object
-     * @throws SwitchStateException
+     * @throws SwitchStateException if the role information could not be extracted.
      */
-    protected RoleReplyInfo extractOFRoleReply(OFRoleReply rrmsg)
+    @Override
+    public RoleReplyInfo extractOFRoleReply(OFRoleReply rrmsg)
             throws SwitchStateException {
         OFControllerRole cr = rrmsg.getRole();
         RoleState role = null;
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/drivers/DriverManager.java b/of/ctl/src/main/java/org/onlab/onos/of/drivers/DriverManager.java
index b475c91..97f94d3 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/drivers/DriverManager.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/drivers/DriverManager.java
@@ -3,11 +3,9 @@
 
 
 import org.onlab.onos.of.controller.Dpid;
-import org.onlab.onos.of.controller.RoleState;
-import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
+import org.onlab.onos.of.controller.driver.OpenFlowSwitchDriver;
+import org.onlab.onos.of.controller.driver.OpenFlowSwitchDriverFactory;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
-import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -16,7 +14,7 @@
  * A simple implementation of a driver manager that differentiates between
  * connected switches using the OF Description Statistics Reply message.
  */
-public final class DriverManager {
+public final class DriverManager implements OpenFlowSwitchDriverFactory {
 
     private static final Logger log = LoggerFactory.getLogger(DriverManager.class);
 
@@ -32,7 +30,8 @@
      * @return A IOFSwitch instance if the driver found an implementation for
      *         the given description. Otherwise it returns OFSwitchImplBase
      */
-    public static AbstractOpenFlowSwitch getOFSwitchImpl(Dpid dpid,
+    @Override
+    public OpenFlowSwitchDriver getOFSwitchImpl(Dpid dpid,
             OFDescStatsReply desc, OFVersion ofv) {
         String vendor = desc.getMfrDesc();
         String hw = desc.getHwDesc();
@@ -53,42 +52,7 @@
 
         log.warn("DriverManager could not identify switch desc: {}. "
                 + "Assigning OFSwitchImplBase", desc);
-        AbstractOpenFlowSwitch base = new AbstractOpenFlowSwitch(dpid) {
-
-
-            @Override
-            public void sendMsg(OFMessage m) {
-                channel.write(m);
-            }
-
-            @Override
-            public Boolean supportNxRole() {
-                return false;
-            }
-
-            @Override
-            public void startDriverHandshake() {}
-
-            @Override
-            public void setFeaturesReply(OFFeaturesReply featuresReply) {
-                this.features = featuresReply;
-            }
-
-            @Override
-            public void processDriverHandshakeMessage(OFMessage m) {}
-
-            @Override
-            public boolean isDriverHandshakeComplete() {
-                return true;
-            }
-
-            @Override
-            public RoleState getRole() {
-                return role;
-            }
-        };
-        base.setSwitchDescription(desc);
-        return base;
+        return null;
     }
 
     /**
@@ -108,4 +72,10 @@
     public static void setConfigForCpqd(boolean usePipeline13) {
         cpqdUsePipeline13 = usePipeline13;
     }
+
+    public static OpenFlowSwitchDriver getSwitch(Dpid dpid,
+            OFDescStatsReply desc, OFVersion ofv) {
+        return new DriverManager().getOFSwitchImpl(dpid, desc, ofv);
+    }
+
 }
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplCPqD13.java b/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplCPqD13.java
index 6f78e8f..b2881ba 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplCPqD13.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplCPqD13.java
@@ -10,15 +10,14 @@
 
 import org.onlab.onos.of.controller.Dpid;
 import org.onlab.onos.of.controller.RoleState;
-import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
-import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeAlreadyStarted;
-import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeCompleted;
-import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted;
+import org.onlab.onos.of.controller.driver.AbstractOpenFlowSwitch;
+import org.onlab.onos.of.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
+import org.onlab.onos.of.controller.driver.SwitchDriverSubHandshakeCompleted;
+import org.onlab.onos.of.controller.driver.SwitchDriverSubHandshakeNotStarted;
 import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
 import org.projectfloodlight.openflow.protocol.OFBucket;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFErrorMsg;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
@@ -61,11 +60,11 @@
  */
 public class OFSwitchImplCPqD13 extends AbstractOpenFlowSwitch {
 
-    private Logger log =
+    private final Logger log =
             LoggerFactory.getLogger(OFSwitchImplCPqD13.class);
 
     private static final int VLAN_ID_OFFSET = 16;
-    private AtomicBoolean driverHandshakeComplete;
+    private final AtomicBoolean driverHandshakeComplete;
     private OFFactory factory;
     private static final int OFPCML_NO_BUFFER = 0xffff;
     // Configuration of asynch messages to controller. We need different
@@ -96,7 +95,7 @@
     private static final short MIN_PRIORITY = 0x0;
     private static final U64 METADATA_MASK = U64.of(Long.MAX_VALUE << 1 | 0x1);
 
-    private Map<Integer, OFGroup> l2groups;
+    private final Map<Integer, OFGroup> l2groups;
 
     private final boolean usePipeline13;
 
@@ -131,7 +130,7 @@
             // Send packet-in to controller if a packet misses the first table
             populateTableMissEntry(0, true, false, false, 0);
         } //else {
-            // configureSwitch();
+        // configureSwitch();
         //}
         sendBarrier(true);
     }
@@ -146,14 +145,7 @@
 
     @Override
     public void processDriverHandshakeMessage(OFMessage m) {
-        if (!startDriverHandshakeCalled) {
-            throw new SwitchDriverSubHandshakeNotStarted();
-        }
-        if (driverHandshakeComplete.get()) {
-            throw new SwitchDriverSubHandshakeCompleted(m);
-        }
-
-        if (!startDriverHandshakeCalled) {
+        if (!startDriverHandshakeCalled || !startDriverHandshakeCalled) {
             throw new SwitchDriverSubHandshakeNotStarted();
         }
         if (driverHandshakeComplete.get()) {
@@ -168,30 +160,23 @@
             break;
 
         case ERROR:
-            log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
+            log.error("Switch {} Error {}", getStringId(), m);
             break;
 
-        case FEATURES_REPLY:
-            break;
-        case FLOW_REMOVED:
-            break;
         case GET_ASYNC_REPLY:
             OFAsyncGetReply asrep = (OFAsyncGetReply) m;
             decodeAsyncGetReply(asrep);
             break;
-
-        case PACKET_IN:
-            break;
-        case PORT_STATUS:
-            break;
-        case QUEUE_GET_CONFIG_REPLY:
-            break;
-        case ROLE_REPLY:
-            break;
-
         case STATS_REPLY:
             processStatsReply((OFStatsReply) m);
             break;
+        case PACKET_IN:
+        case PORT_STATUS:
+        case QUEUE_GET_CONFIG_REPLY:
+        case ROLE_REPLY:
+        case FEATURES_REPLY:
+        case FLOW_REMOVED:
+            break;
 
         default:
             log.debug("Received message {} during switch-driver subhandshake "
@@ -254,7 +239,7 @@
                 .build();
         msglist.add(getAC);
 
-        write(msglist);
+        sendMsg(msglist);
     }
 
     private void decodeAsyncGetReply(OFAsyncGetReply rep) {
@@ -327,7 +312,7 @@
             }
         }
         log.debug("Creating {} L2 groups in sw {}", msglist.size(), getStringId());
-        write(msglist);
+        sendMsg(msglist);
     }
 
     private int getVlanConfig(int portnum) {
@@ -405,9 +390,9 @@
 
             List<OFAction> actions = new ArrayList<OFAction>();
             actions.add(decTtl); // decrement the IP TTL/do-checksum/check TTL
-                                 // and MTU
+            // and MTU
             actions.add(setVlan); // set the vlan-id of the exit-port (and
-                                  // l2group)
+            // l2group)
             actions.add(setSA); // set this routers mac address
             // make L3Unicast group setDA for known (configured) ports
             // that connect to other routers
@@ -428,7 +413,7 @@
                     .build();
             msglist.add(gmAdd);
         }
-        write(msglist);
+        sendMsg(msglist);
         log.debug("Creating {} L3 groups in sw {}", msglist.size(), getStringId());
     }
 
@@ -449,8 +434,8 @@
             // setDA will only be non-null for ports connected to routers
             if (setDA != null) {
                 OFGroup gl3 = OFGroup.of(0xa0000000 | portnum); // different id
-                                                                // for mpls
-                                                                // group
+                // for mpls
+                // group
                 OFAction group = factory.actions().buildGroup()
                         .setGroup(gl2).build();
                 OFOxmEthSrc srcAddr = factory.oxms().ethSrc(sAddr);
@@ -462,9 +447,9 @@
                 OFAction decMplsTtl = factory.actions().decMplsTtl();
                 List<OFAction> actions = new ArrayList<OFAction>();
                 actions.add(decMplsTtl); // decrement the MPLS
-                                         // TTL/do-checksum/check TTL and MTU
+                // TTL/do-checksum/check TTL and MTU
                 actions.add(setVlan); // set the vlan-id of the exit-port (and
-                                      // l2group)
+                // l2group)
                 actions.add(setSA); // set this routers mac address
                 actions.add(setDA);
                 actions.add(group);
@@ -480,7 +465,7 @@
                 msglist.add(gmAdd);
             }
         }
-        write(msglist);
+        sendMsg(msglist);
         log.debug("Creating {} MPLS groups in sw {}", msglist.size(), getStringId());
     }
 
@@ -586,7 +571,7 @@
                         .setMatch(match)
                         .setInstructions(instructions)
                         .setPriority(1000) // does not matter - all rules
-                                           // exclusive
+                        // exclusive
                         .setBufferId(OFBufferId.NO_BUFFER)
                         .setIdleTimeout(0)
                         .setHardTimeout(0)
@@ -597,7 +582,7 @@
         }
         // table-vlan has no table-miss entry, and so packets that miss are
         // essentially dropped
-        write(msglist);
+        sendMsg(msglist);
         log.debug("Adding {} vlan-rules in sw {}", msglist.size(), getStringId());
     }
 
@@ -615,7 +600,7 @@
                 .setMatch(matchIp)
                 .setInstructions(instructionsIp)
                 .setPriority(1000) // strict priority required lower than
-                                   // multicastMac
+                // multicastMac
                 .setBufferId(OFBufferId.NO_BUFFER)
                 .setIdleTimeout(0)
                 .setHardTimeout(0)
@@ -635,7 +620,7 @@
                 .setMatch(matchMpls)
                 .setInstructions(instructionsMpls)
                 .setPriority(1001) // strict priority required lower than
-                                   // multicastMac
+                // multicastMac
                 .setBufferId(OFBufferId.NO_BUFFER)
                 .setIdleTimeout(0)
                 .setHardTimeout(0)
@@ -649,7 +634,7 @@
         List<OFMessage> msglist = new ArrayList<OFMessage>(2);
         msglist.add(ipEntry);
         msglist.add(mplsEntry);
-        write(msglist);
+        sendMsg(msglist);
     }
 
     private List<String> getMyIps() { // send to controller
@@ -712,13 +697,13 @@
         List<RouteEntry> routerNextHopIps = new ArrayList<RouteEntry>();
         if (getId() == 0x1) {
             routerNextHopIps
-                    .add(new RouteEntry("192.168.0.2", "255.255.255.255", 6, 102));
+            .add(new RouteEntry("192.168.0.2", "255.255.255.255", 6, 102));
             routerNextHopIps
-                    .add(new RouteEntry("192.168.0.3", "255.255.255.255", 6, 103));
+            .add(new RouteEntry("192.168.0.3", "255.255.255.255", 6, 103));
             routerNextHopIps.add(new RouteEntry("7.7.7.0", "255.255.255.0", 6, 103));
         }
         //if (getId() == 0x2) {
-            /* These are required for normal IP routing without labels.
+        /* These are required for normal IP routing without labels.
             routerNextHopIps.add(new RouteEntry("192.168.0.1","255.255.255.255",1));
             routerNextHopIps.add(new RouteEntry("192.168.0.3","255.255.255.255",2));
             routerNextHopIps.add(new RouteEntry("10.0.1.0","255.255.255.0",1));
@@ -728,9 +713,9 @@
         //}
         if (getId() == 0x3) {
             routerNextHopIps
-                    .add(new RouteEntry("192.168.0.2", "255.255.255.255", 2, 102));
+            .add(new RouteEntry("192.168.0.2", "255.255.255.255", 2, 102));
             routerNextHopIps
-                    .add(new RouteEntry("192.168.0.1", "255.255.255.255", 2, 101));
+            .add(new RouteEntry("192.168.0.1", "255.255.255.255", 2, 101));
             routerNextHopIps.add(new RouteEntry("10.0.1.0", "255.255.255.0", 2, 101));
             routerNextHopIps.add(new RouteEntry("10.0.2.0", "255.255.255.0", 2, 101));
             routerNextHopIps.add(new RouteEntry("10.0.3.0", "255.255.255.0", 2, 101));
@@ -794,7 +779,7 @@
                     .setMatch(match)
                     .setInstructions(instructions)
                     .setPriority(MAX_PRIORITY) // highest priority for exact
-                                               // match
+                    // match
                     .setBufferId(OFBufferId.NO_BUFFER)
                     .setIdleTimeout(0)
                     .setHardTimeout(0)
@@ -802,7 +787,7 @@
                     .build();
             msglist.add(myIpEntry);
         }
-        write(msglist);
+        sendMsg(msglist);
         log.debug("Adding {} my-ip-rules in sw {}", msglist.size(), getStringId());
     }
 
@@ -844,7 +829,7 @@
                     .build();
             msglist.add(myIpEntry);
         }
-        write(msglist);
+        sendMsg(msglist);
         log.debug("Adding {} subnet-ip-rules in sw {}", msglist.size(), getStringId());
         msglist.clear();
     }
@@ -861,14 +846,14 @@
                     .ipv4DstMasked(
                             IPv4Address.of(routerNextHopIps.get(i).prefix),
                             IPv4Address.of(routerNextHopIps.get(i).mask)
-                    );
+                            );
             OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
             OFMatchV3 match = factory.buildMatchV3()
                     .setOxmList(oxmListSlash32).build();
             OFAction outg = factory.actions().buildGroup()
                     .setGroup(OFGroup.of(0xa0000000 | // mpls group id
                             routerNextHopIps.get(i).nextHopPort))
-                    .build();
+                            .build();
             // lots of actions before forwarding to mpls group, and
             // unfortunately
             // they need to be apply-actions
@@ -887,7 +872,7 @@
             writeActions.add(copyTtlOut); // matched in pseudo-table
             //writeActions.add(setlabelid); // bad support in cpqd
             //writeActions.add(setBos); no support in loxigen
-            */
+             */
 
             List<OFAction> applyActions = new ArrayList<OFAction>();
             applyActions.add(pushlabel);
@@ -896,7 +881,7 @@
                     .setActions(applyActions).build();
             List<OFAction> writeActions = new ArrayList<OFAction>();
             writeActions.add(outg); // group will decr mpls-ttl, set mac-sa/da,
-                                    // vlan
+            // vlan
             OFInstruction writeInstr = factory.instructions().buildWriteActions()
                     .setActions(writeActions).build();
 
@@ -950,7 +935,7 @@
             OFAction outg2 = factory.actions().buildGroup()
                     .setGroup(OFGroup.of(routerNextHopIps.get(i).nextHopPort |
                             (192 << VLAN_ID_OFFSET)))
-                    .build();
+                            .build();
             writeActions2.add(outg2);
             OFInstruction writeInstr2 = factory.instructions().buildWriteActions()
                     .setActions(writeActions2).build();
@@ -989,7 +974,7 @@
             msglist.add(myMetaEntry);
 
         }
-        write(msglist);
+        sendMsg(msglist);
         log.debug("Adding {} next-hop-router-rules in sw {}", msglist.size(),
                 getStringId());
 
@@ -1022,7 +1007,7 @@
                     .setField(dmac).build();
             outg = factory.actions().buildGroup()
                     .setGroup(OFGroup.of(0x20000000 | hostNextHopIps.get(i).nextHopPort)) // l3group
-                                                                                          // id
+                    // id
                     .build();
             List<OFAction> writeActions = new ArrayList<OFAction>();
             writeActions.add(setDmac);
@@ -1039,7 +1024,7 @@
                     .setMatch(match)
                     .setInstructions(instructions)
                     .setPriority(MAX_PRIORITY) // highest priority for exact
-                                               // match
+                    // match
                     .setBufferId(OFBufferId.NO_BUFFER)
                     .setIdleTimeout(0)
                     .setHardTimeout(0)
@@ -1047,7 +1032,7 @@
                     .build();
             msglist.add(myIpEntry);
         }
-        write(msglist);
+        sendMsg(msglist);
         log.debug("Adding {} next-hop-host-rules in sw {}", msglist.size(), getStringId());
     }
 
@@ -1121,7 +1106,7 @@
                     .build();
             msglist.add(myMplsEntry);
         }
-        write(msglist);
+        sendMsg(msglist);
         log.debug("Adding {} mpls-forwarding-rules in sw {}", msglist.size(),
                 getStringId());
 
@@ -1190,7 +1175,7 @@
             // executed - if there is an action to output/group in the action
             // set
             // the packet will be sent there, otherwise it will be dropped.
-            instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
+            instructions = Collections.EMPTY_LIST;
         }
 
         OFMessage tableMissEntry = factory.buildFlowAdd()
@@ -1219,20 +1204,19 @@
     }
 
     @Override
-    public void sendMsg(OFMessage m) {
-        channel.write(m);
+    public Boolean supportNxRole() {
+        return false;
+    }
+
+    @Override
+    public void write(OFMessage msg) {
+        this.channel.write(msg);
+
     }
 
     @Override
     public void write(List<OFMessage> msgs) {
-        for (OFMessage m : msgs) {
-            channel.write(m);
-        }
-    }
-
-    @Override
-    public Boolean supportNxRole() {
-        return false;
+        this.channel.write(msgs);
     }
 
 }
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS10.java b/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS10.java
index 45228dc..bc42636 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS10.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS10.java
@@ -1,7 +1,9 @@
 package org.onlab.onos.of.drivers;
 
+import java.util.List;
+
 import org.onlab.onos.of.controller.Dpid;
-import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
+import org.onlab.onos.of.controller.driver.AbstractOpenFlowSwitch;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 
@@ -29,11 +31,6 @@
     }
 
     @Override
-    public void sendMsg(OFMessage m) {
-        channel.write(m);
-    }
-
-    @Override
     public Boolean supportNxRole() {
         return true;
     }
@@ -48,4 +45,15 @@
 
     @Override
     public void processDriverHandshakeMessage(OFMessage m) {}
+
+    @Override
+    public void write(OFMessage msg) {
+        channel.write(msg);
+
+    }
+
+    @Override
+    public void write(List<OFMessage> msgs) {
+        channel.write(msgs);
+    }
 }
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS13.java b/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS13.java
index 1ab1f047..40750f7 100644
--- a/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS13.java
+++ b/of/ctl/src/main/java/org/onlab/onos/of/drivers/OFSwitchImplOVS13.java
@@ -1,15 +1,15 @@
 package org.onlab.onos.of.drivers;
 
+import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.onlab.onos.of.controller.Dpid;
-import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
-import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeAlreadyStarted;
-import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeCompleted;
-import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted;
+import org.onlab.onos.of.controller.driver.AbstractOpenFlowSwitch;
+import org.onlab.onos.of.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
+import org.onlab.onos.of.controller.driver.SwitchDriverSubHandshakeCompleted;
+import org.onlab.onos.of.controller.driver.SwitchDriverSubHandshakeNotStarted;
 import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
-import org.projectfloodlight.openflow.protocol.OFErrorMsg;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.slf4j.Logger;
@@ -25,7 +25,7 @@
     private static Logger log =
             LoggerFactory.getLogger(OFSwitchImplOVS13.class);
 
-    private AtomicBoolean driverHandshakeComplete;
+    private final AtomicBoolean driverHandshakeComplete;
     private OFFactory factory;
     private long barrierXidToWaitFor = -1;
 
@@ -78,7 +78,7 @@
             break;
 
         case ERROR:
-            log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
+            log.error("Switch {} Error {}", getStringId(), m);
             break;
 
         case FEATURES_REPLY:
@@ -129,12 +129,18 @@
     }
 
     @Override
-    public void sendMsg(OFMessage m) {
-        channel.write(m);
+    public Boolean supportNxRole() {
+        return false;
     }
 
     @Override
-    public Boolean supportNxRole() {
-        return false;
+    public void write(OFMessage msg) {
+        channel.write(msg);
+
+    }
+
+    @Override
+    public void write(List<OFMessage> msgs) {
+        channel.write(msgs);
     }
 }