diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
index b9a628ba84d16c812d6b7309696eb05251f885f1..67b54290dc237baa634a822a77c264dc8bbdc0eb 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -17,6 +17,7 @@
 
 package net.floodlightcontroller.core;
 
+import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
@@ -215,5 +216,17 @@ public interface IFloodlightProviderService extends
     */
    public void addOFSwitchDriver(String desc, IOFSwitchDriver driver);
 
+   /**
+    * Send an HA role request to switch with the given paramaters in the
+    * form of Nicira Vendor extensions.
+    * 
+    * @param sw Switch to send the request
+    * @param xid Transaction ID of the OF message
+    * @param role The role to set the switch to
+    * @param cookie Cookie from IOFSwitch.sendHARoleRequest
+    * @throws IOException 
+    */
+   public void sendNxRoleRequest(IOFSwitch sw, int xid, Role role, long cookie)
+           throws IOException;
 
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
index 04d46480f7580cdd4f98eee01c44c399498ab012..d57124578cf944cc8bdd936729e0d9ca29194ab0 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -391,14 +391,17 @@ public interface IOFSwitch {
      */
     public int sendHARoleRequest(Role role, long cookie)
             throws IOException, HARoleUnsupportedException;
-
+    
     /**
-     * Check HA role request cookie
+     * Set switch's HA role to role. The haRoleReplyReceived indicates
+     * if a reply was received from the switch (error replies excluded).
      * 
-     * @param cookie
-     * @return
+     * If role is null, the switch should close the channel connection.
+     * 
+     * @param role
+     * @param haRoleReplyReceived
      */
-    public boolean checkFirstPendingRoleRequestCookie(long cookie);
+    public void setHARole(Role role, boolean haRoleReplyReceived);
 
     public void setChannel(Channel channel);
 
@@ -406,13 +409,8 @@ public interface IOFSwitch {
 
     public void setThreadPoolService(IThreadPoolService threadPool);
 
-    public void deliverRoleReply(int xid, Role role);
-
-    public void deliverRoleRequestNotSupported(int xid);
-
     public Lock getListenerReadLock();
 
-    public boolean checkFirstPendingRoleRequestXid(int xid);
-
     public Lock getListenerWriteLock();
+
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index cfe1d85bb60a96ef5e60ec732fd7b1953560c328..55eb924ddb6a596c6aa2a2845bce1faf46ba635f 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -874,7 +874,7 @@ public class Controller implements IFloodlightProviderService,
                       new Object[] { role, sw, Controller.this.role} 
                       );
             
-            sw.deliverRoleReply(vendorMessage.getXid(), role);
+            roleChanger.deliverRoleReply(sw, vendorMessage.getXid(), role);
             
             if (sw.isActive()) {
             // Transition from SLAVE to MASTER.
@@ -1060,7 +1060,8 @@ public class Controller implements IFloodlightProviderService,
                     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())) {
+                    if (roleChanger.checkFirstPendingRoleRequestXid(
+                            sw, error.getXid())) {
                         boolean isBadVendorError =
                             (error.getErrorType() == OFError.OFErrorType.
                                     OFPET_BAD_REQUEST.getValue());
@@ -1081,17 +1082,16 @@ public class Controller implements IFloodlightProviderService,
                                           +"role reply earlier", sw);
                             }
                             state.firstRoleReplyReceived = true;
-                            sw.deliverRoleRequestNotSupported(error.getXid());
+                            roleChanger.deliverRoleRequestNotSupported(sw, error.getXid());
                             synchronized(roleChanger) {
-                                if (sw.getRole() == null &&
-                                        Controller.this.role==Role.SLAVE) {
+                                if (Controller.this.role==Role.SLAVE) {
                                     // the switch doesn't understand role request
                                     // messages and the current controller role is
                                     // slave. We need to disconnect the switch. 
                                     // @see RoleChanger for rationale
-                                    sw.getChannel().close();
+                                    sw.disconnectOutputStream();
                                 }
-                                else if (sw.getRole() == null) {
+                                else {
                                     // Controller's role is master: add to
                                     // active 
                                     // TODO: check if clearing flow table is
@@ -2129,5 +2129,44 @@ public class Controller implements IFloodlightProviderService,
             switchDescSortedList.add(description);
         }
     }
+    
+    public void sendNxRoleRequest(IOFSwitch sw, int xid,
+            Role role, long cookie) throws IOException {
+        // 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.", sw);
+                // TODO: should throw an error
+                return;
+        }
+        
+        // Construct the role request message
+        OFVendor roleRequest = (OFVendor)this.
+                getOFMessageFactory().getMessage(OFType.VENDOR);
+        roleRequest.setXid(xid);
+        roleRequest.setVendor(OFNiciraVendorData.NX_VENDOR_ID);
+        OFRoleRequestVendorData roleRequestData = new OFRoleRequestVendorData();
+        roleRequestData.setRole(nxRole);
+        roleRequest.setVendorData(roleRequestData);
+        roleRequest.setLengthU(OFVendor.MINIMUM_LENGTH + 
+                               roleRequestData.getLength());
+        
+        // Send it to the switch
+        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        msglist.add(roleRequest);
+        sw.write(msglist, new FloodlightContext());
+    }
 
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
index becbdb561c24260fa6e94af1b03ebf9775375a21..ed972cd691d7e9d920f7ac281afa399f74ee4e36 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
@@ -24,7 +24,6 @@ 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.concurrent.ConcurrentHashMap;
@@ -41,7 +40,6 @@ import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
 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;
@@ -58,7 +56,6 @@ import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFPhysicalPort;
 import org.openflow.protocol.OFPort;
 import org.openflow.protocol.OFType;
-import org.openflow.protocol.OFVendor;
 import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
 import org.openflow.protocol.OFPhysicalPort.OFPortState;
 import org.openflow.protocol.OFStatisticsRequest;
@@ -66,9 +63,6 @@ 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;
 
@@ -80,11 +74,6 @@ public class OFSwitchImpl implements IOFSwitch {
     // exception that can then be handled by callers?
     protected 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;
@@ -110,17 +99,6 @@ public class OFSwitchImpl implements IOFSwitch {
     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.
-     * 
-     * 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;
@@ -141,18 +119,6 @@ public class OFSwitchImpl implements IOFSwitch {
     // 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>();
@@ -169,7 +135,6 @@ public class OFSwitchImpl implements IOFSwitch {
         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);
@@ -637,177 +602,53 @@ public class OFSwitchImpl implements IOFSwitch {
      */
     public int sendHARoleRequest(Role role, long cookie)
             throws IOException, HARoleUnsupportedException {
+        // 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 simply throw an unsupported exception.
         Boolean supportsNxRole = (Boolean)
                 getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
         if ((supportsNxRole != null) && !supportsNxRole) {
             throw new HARoleUnsupportedException();
         }
 
-        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;
-        }
+        int xid = this.getNextTransactionId();
+        floodlightProvider.sendNxRoleRequest(this, 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. 
-     * 
-     * We must not check the received role against the controller's current
-     * role because there's no synchronization but that's fine @see RoleChanger
-     * 
-     * 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)                           
-    })
-    public 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 
-     */
-    public 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
-     */
-    public boolean checkFirstPendingRoleRequestCookie(long cookie) {
-        synchronized(pendingRoleRequests) {
-            PendingRoleRequestEntry head = pendingRoleRequests.peek();
-            if (head == null)
-                return false;
-            else 
-                return head.cookie == cookie;
+    public void setHARole(Role role, boolean replyReceived) {
+        /* null role implies disconnect the switch */
+        if (role == null) {
+            this.channel.close();
+            return;
         }
-    }
-    
-    /**
-     * 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
-     */
-    public void deliverRoleRequestNotSupported(int xid) {
-        synchronized(pendingRoleRequests) {
-            PendingRoleRequestEntry head = pendingRoleRequests.poll();
-            this.role = null;
-            if (head!=null && head.xid == xid) {
-                setAttribute(SWITCH_SUPPORTS_NX_ROLE, false);
-            }
-            else {
-                this.channel.close();
-            }
+        
+        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, replyReceived);
         }
+        this.role = role;
     }
-
+     
     @Override
     public Future<OFFeaturesReply> querySwitchFeaturesReply()
             throws IOException {
diff --git a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
index b7a8ba9bca1557d97cea79d7522c86dae9faa2d7..cf13919c06c55150a5ebd1673594203a6dd768ce 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
@@ -4,6 +4,8 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.DelayQueue;
 import java.util.concurrent.Delayed;
 import java.util.concurrent.TimeUnit;
@@ -15,6 +17,7 @@ import net.floodlightcontroller.core.HARoleUnsupportedException;
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
+import net.floodlightcontroller.core.annotations.LogMessageDocs;
 
 /** 
  * This class handles sending of RoleRequest messages to all connected switches.
@@ -120,8 +123,16 @@ public class RoleChanger {
     protected long lastSubmitTime;
     protected Thread workerThread;
     protected long timeout;
+    protected ConcurrentHashMap<IOFSwitch, LinkedList<PendingRoleRequestEntry>>
+                pendingRequestMap;
+    
     protected static long DEFAULT_TIMEOUT = 15L*1000*1000*1000L; // 15s
     protected static Logger log = LoggerFactory.getLogger(RoleChanger.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.";
+    
     /** 
      * A queued task to be handled by the Role changer thread. 
      */
@@ -157,6 +168,22 @@ public class RoleChanger {
         }
     }
     
+    /**
+     * Per-switch list of pending HA role requests.
+     * @author shudongz
+     */
+    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;
+        }
+    }
+    
     @LogMessageDoc(level="ERROR",
                    message="RoleRequestWorker task had an uncaught exception.",
                    explanation="An unknown occured while processing an HA " +
@@ -203,6 +230,8 @@ public class RoleChanger {
     }
     
     public RoleChanger() {
+        this.pendingRequestMap = new ConcurrentHashMap<IOFSwitch,
+                LinkedList<PendingRoleRequestEntry>>();
         this.pendingTasks = new DelayQueue<RoleChangeTask>();
         this.workerThread = new Thread(new RoleRequestWorker());
         this.timeout = DEFAULT_TIMEOUT;
@@ -224,12 +253,10 @@ public class RoleChanger {
     }
     
     /**
-     * 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
+     * Send a role request message to switches. The sw implementation throws
+     * HARoleUnsupportedException if HA is not supported. Otherwise, it
+     * returns the transaction id of the request message.
+     * @param switches the collection of switches to send the request too
      * @param role the role to request
      */
     @LogMessageDoc(level="WARN",
@@ -240,39 +267,23 @@ public class RoleChanger {
             recommendation=LogMessageDoc.CHECK_SWITCH)                              
     protected void sendRoleRequest(Collection<IOFSwitch> 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<IOFSwitch> iter = switches.iterator();
         while(iter.hasNext()) {
             IOFSwitch sw = iter.next();
             try {
-                sw.sendHARoleRequest(role, cookie);
+                int xid = sw.sendHARoleRequest(role, cookie);
+                PendingRoleRequestEntry entry =
+                        new PendingRoleRequestEntry(xid, role, cookie);
+                LinkedList<PendingRoleRequestEntry> pendingList
+                    = pendingRequestMap.get(sw);
+                if (pendingList == null) {
+                    pendingList = new LinkedList<PendingRoleRequestEntry>();
+                    pendingRequestMap.put(sw, pendingList);
+                }
+                // Need to synchronize against removal from list
+                synchronized(pendingList) {
+                    pendingList.add(entry);
+                }
             } catch (IOException e) {
                 log.warn("Failed to send role request message " + 
                          "to switch {}: {}. Disconnecting",
@@ -280,7 +291,7 @@ public class RoleChanger {
                 sw.getChannel().close();
                 iter.remove();
             } catch (HARoleUnsupportedException e) {
-                // Handle case #3
+                // Switch doesn't support HA role, remove if role is slave
                 if (role == Role.SLAVE) {
                     log.debug("Disconnecting switch {} that doesn't support " +
                     "role request messages from a controller that went to SLAVE mode");
@@ -307,11 +318,151 @@ public class RoleChanger {
     protected void verifyRoleReplyReceived(Collection<IOFSwitch> switches,
                                    long cookie) {
         for (IOFSwitch sw: switches) {
-            if (sw.checkFirstPendingRoleRequestCookie(cookie)) {
-                sw.getChannel().close();
+            if (checkFirstPendingRoleRequestCookie(sw, cookie)) {
+                sw.setHARole(null,  false);
                 log.warn("Timeout while waiting for role reply from switch {}."
                          + " Disconnecting", sw);
             }
         }
     }
+    
+    /** 
+     * Deliver a RoleReply message for a 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. 
+     * 
+     * We must not check the received role against the controller's current
+     * role because there's no synchronization but that's fine @see RoleChanger
+     * 
+     * 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)                           
+    })
+    
+    public void deliverRoleReply(IOFSwitch sw, int xid, Role role) {
+        LinkedList<PendingRoleRequestEntry> pendingRoleRequests =
+                pendingRequestMap.get(sw);
+        if (pendingRoleRequests == null) {
+            log.warn("Switch {}: received unexpected role reply for Role {}" + 
+                    ", ignored", sw, role );
+            return;
+        }
+        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", sw, role );
+                sw.disconnectOutputStream();
+            }
+            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 } );
+                sw.disconnectOutputStream();
+            }
+            else if (head.role != role) {
+                log.error("Switch {}: expected role reply with " +
+                       "Role {}, got {}. Disconnecting switch",
+                       new Object[] { this, head.role, role } );
+                sw.disconnectOutputStream();
+            }
+            else {
+                log.debug("Received role reply message from {}, setting role to {}",
+                          this, role);
+                sw.setHARole(role, true);
+            }
+        }
+    }
+    
+    /** 
+     * Checks whether the given xid matches the xid of the first pending
+     * role request. 
+     * @param xid
+     * @return 
+     */
+    public boolean checkFirstPendingRoleRequestXid (IOFSwitch sw, int xid) {
+        LinkedList<PendingRoleRequestEntry> pendingRoleRequests =
+                pendingRequestMap.get(sw);
+        if (pendingRoleRequests == null) {
+            return false;
+        }
+        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
+     */
+    public boolean checkFirstPendingRoleRequestCookie(IOFSwitch sw, long cookie)
+    {
+        LinkedList<PendingRoleRequestEntry> pendingRoleRequests =
+                pendingRequestMap.get(sw);
+        if (pendingRoleRequests == null) {
+            return false;
+        }
+        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
+     */
+    public void deliverRoleRequestNotSupported(IOFSwitch sw, int xid) {
+        LinkedList<PendingRoleRequestEntry> pendingRoleRequests =
+                pendingRequestMap.get(sw);
+        if (pendingRoleRequests == null) {
+            log.warn("Switch {}: received unexpected error for xid {}" + 
+                    ", ignored", sw, xid);
+            return;
+        }
+        synchronized(pendingRoleRequests) {
+            PendingRoleRequestEntry head = pendingRoleRequests.poll();
+            if (head != null && head.xid == xid) {
+                sw.setHARole(head.role, false);
+            } else {
+                sw.disconnectOutputStream();
+            }
+        }
+    }
+
 }