diff --git a/build.xml b/build.xml
index b141553d79e18362ce9fc1b1a839bf3ea53c12ec..c28b90b5fda6d0782f2c01a5b299142f8b03e901 100644
--- a/build.xml
+++ b/build.xml
@@ -64,6 +64,7 @@
         <include name="concurrentlinkedhashmap-lru-1.2.jar"/>
         <include name="jython-2.5.2.jar"/>
         <include name="libthrift-0.7.0.jar"/>
+        <include name="guava-13.0.1.jar" />
     </patternset>
 
     <path id="classpath">
diff --git a/lib/guava-13.0.1.jar b/lib/guava-13.0.1.jar
new file mode 100644
index 0000000000000000000000000000000000000000..09c5449115df66fdd2611e2c4f8c362fbb6aaff3
Binary files /dev/null and b/lib/guava-13.0.1.jar differ
diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
index b9a628ba84d16c812d6b7309696eb05251f885f1..e73972ac6fe5f857e7de69fec56b47b79851cdb5 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -215,5 +215,4 @@ public interface IFloodlightProviderService extends
     */
    public void addOFSwitchDriver(String desc, IOFSwitchDriver driver);
 
-
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
index 68e025b807cc8212a432f343a732714497eadd97..902dfdf5f9055b442f5d917e4ce1dbac4184d130 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -18,6 +18,7 @@
 package net.floodlightcontroller.core;
 
 import java.io.IOException;
+import java.net.SocketAddress;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
@@ -53,7 +54,57 @@ public interface IOFSwitch {
     public static final String PROP_SUPPORTS_OFPP_TABLE = "supportsOfppTable";
     public static final String PROP_SUPPORTS_OFPP_FLOOD = "supportsOfppFlood";
     public static final String PROP_SUPPORTS_NETMASK_TBL = "supportsNetmaskTbl";
-    
+
+    public enum OFPortType {
+        NORMAL("normal"),         // normal port (default)
+        TUNNEL("tunnel"),         // tunnel port
+        UPLINK("uplink"),         // uplink port (on a virtual switch)
+        MANAGEMENT("management"); // for in-band management
+        
+        private String value;
+        OFPortType(String v) {
+            value = v;
+        }
+        
+        @Override
+        public String toString() {
+            return value;
+        }
+
+        public static OFPortType fromString(String str) {
+            for (OFPortType m : OFPortType.values()) {
+                if (m.value.equals(str)) {
+                    return m;
+                }
+            }
+            return OFPortType.NORMAL;
+        }
+    }
+
+    /**
+     * Set IFloodlightProviderService for this switch instance
+     * Called immediately after instantiation
+     * 
+     * @param controller
+     */
+    public void setFloodlightProvider(Controller controller);
+
+    /**
+     * Set IThreadPoolService for this switch instance
+     * Called immediately after instantiation
+     * 
+     * @param threadPool
+     */
+    public void setThreadPoolService(IThreadPoolService threadPool);
+
+    /**
+     * Set the netty Channel this switch instance is associated with
+     * Called immediately after instantiation
+     * 
+     * @param channel
+     */
+    public void setChannel(Channel channel);
+
     /**
      * Writes to the OFMessage to the output stream.
      * The message will be handed to the floodlightProvider for possible filtering
@@ -80,13 +131,6 @@ public interface IOFSwitch {
      */
     public void disconnectOutputStream();
 
-    /**
-     * FIXME: remove getChannel(). All access to the channel should be through
-     *        wrapper functions in IOFSwitch
-     * @return
-     */
-    public Channel getChannel();
-
     /**
      * Returns switch features from features Reply
      * @return
@@ -106,12 +150,6 @@ public interface IOFSwitch {
      */
     public void setFeaturesReply(OFFeaturesReply featuresReply);
     
-    /**
-     * Set the SwitchProperties based on it's description
-     * @param description
-     */
-    public void setSwitchProperties(OFDescriptionStatistics description);    
-
     /**
      * Get list of all enabled ports. This will typically be different from
      * the list of ports in the OFFeaturesReply, since that one is a static
@@ -287,15 +325,19 @@ public interface IOFSwitch {
      * Get the current role of the controller for the switch
      * @return the role of the controller
      */
-    public Role getRole();
+    public Role getHARole();
     
     /**
-     * Check if the controller is an active controller for the switch.
-     * The controller is active if its role is MASTER or EQUAL.
-     * @return whether the controller is active
+     * Set switch's HA role to role. The haRoleReplyReceived indicates
+     * if a reply was received from the switch (error replies excluded).
+     * 
+     * If role is null, the switch should close the channel connection.
+     * 
+     * @param role
+     * @param haRoleReplyReceived
      */
-    public boolean isActive();
-    
+    public void setHARole(Role role, boolean haRoleReplyReceived);
+
     /**
      * Deliver the statistics future reply
      * @param reply the reply to deliver
@@ -382,36 +424,59 @@ public interface IOFSwitch {
     public void flush();
 
     /**
-     * Send HA role request
-     * 
-     * @param role
-     * @param cookie
+     * Return a read lock that must be held while calling the listeners for
+     * messages from the switch. Holding the read lock prevents the active
+     * switch list from being modified out from under the listeners.
      * @return 
-     * @throws IOException 
      */
-    public int sendNxRoleRequest(Role role, long cookie) throws IOException;
+    public Lock getListenerReadLock();
 
     /**
-     * Check HA role request cookie
-     * 
-     * @param cookie
+     * Return a write lock that must be held when the controllers modifies the
+     * list of active switches. This is to ensure that the active switch list
+     * doesn't change out from under the listeners as they are handling a
+     * message from the switch.
      * @return
      */
-    public boolean checkFirstPendingRoleRequestCookie(long cookie);
-
-    public void setChannel(Channel channel);
-
-    public void setFloodlightProvider(Controller controller);
-
-    public void setThreadPoolService(IThreadPoolService threadPool);
+    public Lock getListenerWriteLock();
 
-    public void deliverRoleReply(int xid, Role role);
+    /**
+     * Get the IP Address for the switch
+     * @return the inet address
+     */
+    public SocketAddress getInetAddress();
 
-    public void deliverRoleRequestNotSupported(int xid);
 
-    public Lock getListenerReadLock();
+    /***********************************************
+     * The following method can be overridden by
+     * specific types of switches
+     ***********************************************
+     */
+    
+    /**
+     * Set the SwitchProperties based on it's description
+     * @param description
+     */
+    public void setSwitchProperties(OFDescriptionStatistics description);    
 
-    public boolean checkFirstPendingRoleRequestXid(int xid);
+    /**
+     * Return the type of OFPort
+     * @param port_num
+     * @return
+     */
+    public OFPortType getPortType(short port_num);
+    
+    /**
+     * Can the port be turned on without forming a new loop?
+     * @param port_num
+     * @return
+     */
+    public boolean isFastPort(short port_num);
 
-    public Lock getListenerWriteLock();
+    /**
+     * Retun a list of uplink port (for virtual switches only)
+     * @return
+     */
+    public List<Short> getUplinkPorts();
+    
 }
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
index 197642959516a2b2353cdf695d2217efbcd856c1..918ddfb0d4fcc9c95363f3593c0e9cf410268479 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchDriver.java
@@ -6,7 +6,9 @@ public interface IOFSwitchDriver {
     /**
      * Return an IOFSwitch object based on switch's manufacturer description
      * from OFDescriptionStatitics.
-     * @param description
+     * @param registered_desc string used to register this driver
+     * @param description DescriptionStatistics from the switch instance
      */
-    public IOFSwitch getOFSwitchImpl(OFDescriptionStatistics description);
+    public IOFSwitch getOFSwitchImpl(String registered_desc,
+            OFDescriptionStatistics description);
 }
diff --git a/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java b/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..95f20f424e1a8e9b698067ab64a711a9be0a3f09
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/OFSwitchBase.java
@@ -0,0 +1,651 @@
+/**
+*    Copyright 2012, Big Switch Networks, Inc. 
+*    Originally created by David Erickson, Stanford University
+* 
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package net.floodlightcontroller.core;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+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.internal.Controller;
+import net.floodlightcontroller.core.internal.OFFeaturesReplyFuture;
+import net.floodlightcontroller.core.internal.OFStatisticsFuture;
+import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.util.TimedCache;
+
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.ser.ToStringSerializer;
+import org.jboss.netty.channel.Channel;
+import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
+import org.openflow.protocol.OFPhysicalPort.OFPortState;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.openflow.util.HexString;
+import org.openflow.util.U16;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is the internal representation of an openflow switch.
+ */
+public abstract class OFSwitchBase implements IOFSwitch {
+    // TODO: should we really do logging in the class or should we throw
+    // exception that can then be handled by callers?
+    protected static Logger log = LoggerFactory.getLogger(OFSwitchBase.class);
+
+    protected ConcurrentMap<Object, Object> attributes;
+    protected IFloodlightProviderService floodlightProvider;
+    protected IThreadPoolService threadPool;
+    protected Date connectedSince;
+    
+    /* Switch features from initial featuresReply */
+    protected int capabilities;
+    protected int buffers;
+    protected int actions;
+    protected byte tables;
+    protected long datapathId;
+    protected Role role;
+    protected String stringId;
+
+    /**
+     * Members hidden from subclasses
+     */
+    private Channel channel;
+    private AtomicInteger transactionIdSource;
+    // Lock to protect modification of the port maps. We only need to 
+    // synchronize on modifications. For read operations we are fine since
+    // we rely on ConcurrentMaps which works for our use case.
+    private Object portLock;
+    // Map port numbers to the appropriate OFPhysicalPort
+    private ConcurrentHashMap<Short, OFPhysicalPort> portsByNumber;
+    // Map port names to the appropriate OFPhyiscalPort
+    // XXX: The OF spec doesn't specify if port names need to be unique but
+    //      according it's always the case in practice. 
+    private ConcurrentHashMap<String, OFPhysicalPort> portsByName;
+    private Map<Integer,OFStatisticsFuture> statsFutureMap;
+    private Map<Integer, IOFMessageListener> iofMsgListenersMap;
+    private Map<Integer,OFFeaturesReplyFuture> featuresFutureMap;
+    private volatile boolean connected;
+    private TimedCache<Long> timedCache;
+    private ReentrantReadWriteLock listenerLock;
+    private ConcurrentMap<Short, Long> portBroadcastCacheHitMap;
+    
+
+    protected static  ThreadLocal<Map<IOFSwitch,List<OFMessage>>> local_msg_buffer =
+            new ThreadLocal<Map<IOFSwitch,List<OFMessage>>>() {
+        @Override
+        protected Map<IOFSwitch,List<OFMessage>> initialValue() {
+            return new HashMap<IOFSwitch,List<OFMessage>>();
+        }
+    };
+    
+    // for managing our map sizes
+    protected static  int MAX_MACS_PER_SWITCH  = 1000;
+    
+    public OFSwitchBase() {
+        this.stringId = null;
+        this.attributes = new ConcurrentHashMap<Object, Object>();
+        this.connectedSince = new Date();
+        this.transactionIdSource = new AtomicInteger();
+        this.portLock = new Object();
+        this.portsByNumber = new ConcurrentHashMap<Short, OFPhysicalPort>();
+        this.portsByName = new ConcurrentHashMap<String, OFPhysicalPort>();
+        this.connected = true;
+        this.statsFutureMap = new ConcurrentHashMap<Integer,OFStatisticsFuture>();
+        this.featuresFutureMap = new ConcurrentHashMap<Integer,OFFeaturesReplyFuture>();
+        this.iofMsgListenersMap = new ConcurrentHashMap<Integer,IOFMessageListener>();
+        this.role = null;
+        this.timedCache = new TimedCache<Long>(100, 5*1000 );  // 5 seconds interval
+        this.listenerLock = new ReentrantReadWriteLock();
+        this.portBroadcastCacheHitMap = new ConcurrentHashMap<Short, Long>();
+        
+        // Defaults properties for an ideal switch
+        this.setAttribute(PROP_FASTWILDCARDS, OFMatch.OFPFW_ALL);
+        this.setAttribute(PROP_SUPPORTS_OFPP_FLOOD, new Boolean(true));
+        this.setAttribute(PROP_SUPPORTS_OFPP_TABLE, new Boolean(true));
+    }
+    
+
+    @Override
+    public Object getAttribute(String name) {
+        if (this.attributes.containsKey(name)) {
+            return this.attributes.get(name);
+        }
+        return null;
+    }
+    
+    @Override
+    public void setAttribute(String name, Object value) {
+        this.attributes.put(name, value);
+        return;
+    }
+
+    @Override
+    public Object removeAttribute(String name) {
+        return this.attributes.remove(name);
+    }
+    
+    @Override
+    public boolean hasAttribute(String name) {
+        return this.attributes.containsKey(name);
+    }
+        
+    @JsonIgnore
+    public void setChannel(Channel channel) {
+        this.channel = channel;
+    }
+    
+    @Override
+    public void write(OFMessage m, FloodlightContext bc)
+            throws IOException {
+        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        List<OFMessage> msg_buffer = msg_buffer_map.get(this);
+        if (msg_buffer == null) {
+            msg_buffer = new ArrayList<OFMessage>();
+            msg_buffer_map.put(this, msg_buffer);
+        }
+
+        this.floodlightProvider.handleOutgoingMessage(this, m, bc);
+        msg_buffer.add(m);
+
+        if ((msg_buffer.size() >= Controller.BATCH_MAX_SIZE) ||
+            ((m.getType() != OFType.PACKET_OUT) && (m.getType() != OFType.FLOW_MOD))) {
+            this.write(msg_buffer);
+            msg_buffer.clear();
+        }
+    }
+
+    @Override
+    @LogMessageDoc(level="WARN",
+                   message="Sending OF message that modifies switch " +
+                           "state while in the slave role: {switch}",
+                   explanation="An application has sent a message to a switch " +
+                           "that is not valid when the switch is in a slave role",
+                   recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+    public void write(List<OFMessage> msglist, 
+                      FloodlightContext bc) throws IOException {
+        for (OFMessage m : msglist) {
+            if (role == Role.SLAVE) {
+                switch (m.getType()) {
+                    case PACKET_OUT:
+                    case FLOW_MOD:
+                    case PORT_MOD:
+                        log.warn("Sending OF message that modifies switch " +
+                                 "state while in the slave role: {}", 
+                                 m.getType().name());
+                        break;
+                    default:
+                        break;
+                }
+            }
+            this.floodlightProvider.handleOutgoingMessage(this, m, bc);
+        }
+        this.write(msglist);
+    }
+
+    private void write(List<OFMessage> msglist) throws IOException {
+        this.channel.write(msglist);
+    }
+    
+    @Override
+    public void disconnectOutputStream() {
+        channel.close();
+    }
+
+    @Override
+    @JsonIgnore
+    public void setFeaturesReply(OFFeaturesReply featuresReply) {
+        synchronized(portLock) {
+            if (stringId == null) {
+                /* ports are updated via port status message, so we
+                 * only fill in ports on initial connection.
+                 */
+                for (OFPhysicalPort port : featuresReply.getPorts()) {
+                    setPort(port);
+                }
+            }
+            this.datapathId = featuresReply.getDatapathId();
+            this.capabilities = featuresReply.getCapabilities();
+            this.buffers = featuresReply.getBuffers();
+            this.actions = featuresReply.getActions();
+            this.tables = featuresReply.getTables();
+            this.stringId = HexString.toHexString(this.datapathId);
+        }
+    }
+
+    @Override
+    @JsonIgnore
+    public Collection<OFPhysicalPort> getEnabledPorts() {
+        List<OFPhysicalPort> result = new ArrayList<OFPhysicalPort>();
+        for (OFPhysicalPort port : portsByNumber.values()) {
+            if (portEnabled(port)) {
+                result.add(port);
+            }
+        }
+        return result;
+    }
+    
+    @Override
+    @JsonIgnore
+    public Collection<Short> getEnabledPortNumbers() {
+        List<Short> result = new ArrayList<Short>();
+        for (OFPhysicalPort port : portsByNumber.values()) {
+            if (portEnabled(port)) {
+                result.add(port.getPortNumber());
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public OFPhysicalPort getPort(short portNumber) {
+        return portsByNumber.get(portNumber);
+    }
+    
+    @Override
+    public OFPhysicalPort getPort(String portName) {
+        return portsByName.get(portName);
+    }
+
+    @Override
+    @JsonIgnore
+    public void setPort(OFPhysicalPort port) {
+        synchronized(portLock) {
+            portsByNumber.put(port.getPortNumber(), port);
+            portsByName.put(port.getName(), port);
+        }
+    }
+    
+    @Override
+    @JsonProperty("ports")
+    public Collection<OFPhysicalPort> getPorts() {
+        return Collections.unmodifiableCollection(portsByNumber.values());
+    }
+    
+    @Override
+    public void deletePort(short portNumber) {
+        synchronized(portLock) {
+            portsByName.remove(portsByNumber.get(portNumber).getName());
+            portsByNumber.remove(portNumber);
+        }
+    }
+    
+    @Override
+    public void deletePort(String portName) {
+        synchronized(portLock) {
+            portsByNumber.remove(portsByName.get(portName).getPortNumber());
+            portsByName.remove(portName);
+        }
+    }
+
+    @Override
+    public boolean portEnabled(short portNumber) {
+        if (portsByNumber.get(portNumber) == null) return false;
+        return portEnabled(portsByNumber.get(portNumber));
+    }
+    
+    @Override
+    public boolean portEnabled(String portName) {
+        if (portsByName.get(portName) == null) return false;
+        return portEnabled(portsByName.get(portName));
+    }
+    
+    @Override
+    public boolean portEnabled(OFPhysicalPort port) {
+        if (port == null)
+            return false;
+        if ((port.getConfig() & OFPortConfig.OFPPC_PORT_DOWN.getValue()) > 0)
+            return false;
+        if ((port.getState() & OFPortState.OFPPS_LINK_DOWN.getValue()) > 0)
+            return false;
+        // Port STP state doesn't work with multiple VLANs, so ignore it for now
+        //if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue())
+        //    return false;
+        return true;
+    }
+    
+    @Override
+    @JsonSerialize(using=DPIDSerializer.class)
+    @JsonProperty("dpid")
+    public long getId() {
+        if (this.stringId == null)
+            throw new RuntimeException("Features reply has not yet been set");
+        return this.datapathId;
+    }
+
+    @JsonIgnore
+    @Override
+    public String getStringId() {
+        return stringId;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "OFSwitchBase [" + channel.getRemoteAddress() + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
+    }
+
+    @Override
+    public ConcurrentMap<Object, Object> getAttributes() {
+        return this.attributes;
+    }
+
+    @Override
+    public Date getConnectedSince() {
+        return connectedSince;
+    }
+
+    @JsonIgnore
+    @Override
+    public int getNextTransactionId() {
+        return this.transactionIdSource.incrementAndGet();
+    }
+
+    @Override
+    public void sendStatsQuery(OFStatisticsRequest request, int xid,
+                                IOFMessageListener caller) throws IOException {
+        request.setXid(xid);
+        this.iofMsgListenersMap.put(xid, caller);
+        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        msglist.add(request);
+        this.channel.write(msglist);
+        return;
+    }
+
+    @Override
+    public Future<List<OFStatistics>> getStatistics(OFStatisticsRequest request) throws IOException {
+        request.setXid(getNextTransactionId());
+        OFStatisticsFuture future = new OFStatisticsFuture(threadPool, this, request.getXid());
+        this.statsFutureMap.put(request.getXid(), future);
+        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        msglist.add(request);
+        this.channel.write(msglist);
+        return future;
+    }
+
+    @Override
+    public void deliverStatisticsReply(OFMessage reply) {
+        OFStatisticsFuture future = this.statsFutureMap.get(reply.getXid());
+        if (future != null) {
+            future.deliverFuture(this, reply);
+            // The future will ultimately unregister itself and call
+            // cancelStatisticsReply
+            return;
+        }
+        /* Transaction id was not found in statsFutureMap.check the other map */
+        IOFMessageListener caller = this.iofMsgListenersMap.get(reply.getXid());
+        if (caller != null) {
+            caller.receive(this, reply, null);
+        }
+    }
+
+    @Override
+    public void cancelStatisticsReply(int transactionId) {
+        if (null ==  this.statsFutureMap.remove(transactionId)) {
+            this.iofMsgListenersMap.remove(transactionId);
+        }
+    }
+
+    @Override
+    public void cancelAllStatisticsReplies() {
+        /* we don't need to be synchronized here. Even if another thread
+         * modifies the map while we're cleaning up the future will eventuall
+         * timeout */
+        for (OFStatisticsFuture f : statsFutureMap.values()) {
+            f.cancel(true);
+        }
+        statsFutureMap.clear();
+        iofMsgListenersMap.clear();
+    }
+ 
+    
+    /**
+     * @param floodlightProvider the floodlightProvider to set
+     */
+    @JsonIgnore
+    public void setFloodlightProvider(
+            IFloodlightProviderService floodlightProvider) {
+        this.floodlightProvider = floodlightProvider;
+    }
+    
+    @JsonIgnore
+    public void setThreadPoolService(IThreadPoolService tp) {
+        this.threadPool = tp;
+    }
+
+    @JsonIgnore
+    @Override
+    public boolean isConnected() {
+        // No lock needed since we use volatile
+        return connected;
+    }
+
+    @Override
+    @JsonIgnore
+    public void setConnected(boolean connected) {
+        // No lock needed since we use volatile
+        this.connected = connected;
+    }
+    
+    @Override
+    public Role getHARole() {
+        return role;
+    }
+
+    @JsonIgnore
+    @Override
+    public void setHARole(Role role, boolean replyReceived) {        
+        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
+    @LogMessageDoc(level="ERROR",
+                   message="Failed to clear all flows on switch {switch}",
+                   explanation="An I/O error occured while trying to clear " +
+                               "flows on the switch.",
+                   recommendation=LogMessageDoc.CHECK_SWITCH)
+    public void clearAllFlowMods() {
+        // Delete all pre-existing flows
+        OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
+        OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory()
+            .getMessage(OFType.FLOW_MOD))
+                .setMatch(match)
+            .setCommand(OFFlowMod.OFPFC_DELETE)
+            .setOutPort(OFPort.OFPP_NONE)
+            .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
+        try {
+            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+            msglist.add(fm);
+            channel.write(msglist);
+        } catch (Exception e) {
+            log.error("Failed to clear all flows on switch " + this, e);
+        }
+    }
+
+    @Override
+    public boolean updateBroadcastCache(Long entry, Short port) {
+        if (timedCache.update(entry)) {
+            Long count = portBroadcastCacheHitMap.putIfAbsent(port, new Long(1));
+            if (count != null) {
+                count++;
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    @JsonIgnore
+    public Map<Short, Long> getPortBroadcastHits() {
+        return this.portBroadcastCacheHitMap;
+    }
+    
+
+    @Override
+    public void flush() {
+        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        List<OFMessage> msglist = msg_buffer_map.get(this);
+        if ((msglist != null) && (msglist.size() > 0)) {
+            try {
+                this.write(msglist);
+            } catch (IOException e) {
+                // TODO: log exception
+                e.printStackTrace();
+            }
+            msglist.clear();
+        }
+    }
+
+    public static void flush_all() {
+        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
+        for (IOFSwitch sw : msg_buffer_map.keySet()) {
+            sw.flush();
+        }
+    }
+
+    /**
+     * Return a read lock that must be held while calling the listeners for
+     * messages from the switch. Holding the read lock prevents the active
+     * switch list from being modified out from under the listeners.
+     * @return 
+     */
+    @JsonIgnore
+    public Lock getListenerReadLock() {
+        return listenerLock.readLock();
+    }
+
+    /**
+     * Return a write lock that must be held when the controllers modifies the
+     * list of active switches. This is to ensure that the active switch list
+     * doesn't change out from under the listeners as they are handling a
+     * message from the switch.
+     * @return
+     */
+    @JsonIgnore
+    public Lock getListenerWriteLock() {
+        return listenerLock.writeLock();
+    }
+
+    /**
+     * Get the IP Address for the switch
+     * @return the inet address
+     */
+    @JsonSerialize(using=ToStringSerializer.class)
+    public SocketAddress getInetAddress() {
+        return channel.getRemoteAddress();
+    }
+    
+    @Override
+    public Future<OFFeaturesReply> querySwitchFeaturesReply()
+            throws IOException {
+        OFMessage request = 
+                floodlightProvider.getOFMessageFactory().
+                    getMessage(OFType.FEATURES_REQUEST);
+        request.setXid(getNextTransactionId());
+        OFFeaturesReplyFuture future =
+                new OFFeaturesReplyFuture(threadPool, this, request.getXid());
+        this.featuresFutureMap.put(request.getXid(), future);
+        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
+        msglist.add(request);
+        this.channel.write(msglist);
+        return future;
+    }
+
+    @Override
+    public void deliverOFFeaturesReply(OFMessage reply) {
+        OFFeaturesReplyFuture future = this.featuresFutureMap.get(reply.getXid());
+        if (future != null) {
+            future.deliverFuture(this, reply);
+            // The future will ultimately unregister itself and call
+            // cancelFeaturesReply
+            return;
+        }
+        log.error("Switch {}: received unexpected featureReply", this);
+    }
+
+    @Override
+    public void cancelFeaturesReply(int transactionId) {
+        this.featuresFutureMap.remove(transactionId);
+    }
+
+
+    @Override
+    public int getBuffers() {
+        return buffers;
+    }
+
+
+    @Override
+    public int getActions() {
+        return actions;
+    }
+
+
+    @Override
+    public int getCapabilities() {
+        return capabilities;
+    }
+
+
+    @Override
+    public byte getTables() {
+        return tables;
+    }
+
+
+    @Override
+    public void setFloodlightProvider(Controller controller) {
+        floodlightProvider = controller;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/annotations/LogMessageDoc.java b/src/main/java/net/floodlightcontroller/core/annotations/LogMessageDoc.java
index c703687a1d92362638b0e77098d9a47f9e27d2df..08b48dc849009d62de8f04a6d948eac8f36dc39f 100644
--- a/src/main/java/net/floodlightcontroller/core/annotations/LogMessageDoc.java
+++ b/src/main/java/net/floodlightcontroller/core/annotations/LogMessageDoc.java
@@ -35,6 +35,10 @@ public @interface LogMessageDoc {
     public static final String CHECK_SWITCH = 
             "Check the health of the indicated switch.  " + 
             "Test and troubleshoot IP connectivity.";
+    public 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.";
     public static final String CHECK_CONTROLLER = 
             "Verify controller system health, CPU usage, and memory.  " + 
             "Rebooting the controller node may help if the controller " +
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index cfe1d85bb60a96ef5e60ec732fd7b1953560c328..b7b048874a874b508e327bd87998832898f2c93f 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -1,7 +1,7 @@
 /**
-*    Copyright 2011, Big Switch Networks, Inc. 
+*    Copyright 2011, Big Switch Networks, Inc.
 *    Originally created by David Erickson, Stanford University
-* 
+*
 *    Licensed under the Apache License, Version 2.0 (the "License"); you may
 *    not use this file except in compliance with the License. You may obtain
 *    a copy of the License at
@@ -20,8 +20,8 @@ package net.floodlightcontroller.core.internal;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.net.InetSocketAddress;
-import java.util.ArrayList;
 import java.nio.channels.ClosedChannelException;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -41,16 +41,18 @@ import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.Executors;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.RejectedExecutionException;
+
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IHAListener;
 import net.floodlightcontroller.core.IInfoProvider;
-import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IListener.Command;
+import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.IOFSwitchDriver;
 import net.floodlightcontroller.core.IOFSwitchFilter;
 import net.floodlightcontroller.core.IOFSwitchListener;
+import net.floodlightcontroller.core.OFSwitchBase;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
 import net.floodlightcontroller.core.annotations.LogMessageDocs;
 import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState;
@@ -113,14 +115,10 @@ import org.openflow.protocol.factory.MessageParseException;
 import org.openflow.protocol.statistics.OFDescriptionStatistics;
 import org.openflow.protocol.statistics.OFStatistics;
 import org.openflow.protocol.statistics.OFStatisticsType;
-import org.openflow.protocol.vendor.OFBasicVendorDataType;
-import org.openflow.protocol.vendor.OFBasicVendorId;
-import org.openflow.protocol.vendor.OFVendorId;
 import org.openflow.util.HexString;
 import org.openflow.vendor.nicira.OFNiciraVendorData;
+import org.openflow.vendor.nicira.OFNiciraVendorExtensions;
 import org.openflow.vendor.nicira.OFRoleReplyVendorData;
-import org.openflow.vendor.nicira.OFRoleRequestVendorData;
-import org.openflow.vendor.nicira.OFRoleVendorData;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -128,22 +126,22 @@ import org.slf4j.LoggerFactory;
 /**
  * The main controller class.  Handles all setup and network listeners
  */
-public class Controller implements IFloodlightProviderService, 
+public class Controller implements IFloodlightProviderService,
             IStorageSourceListener {
-    
+
     protected static Logger log = LoggerFactory.getLogger(Controller.class);
 
-    private static final String ERROR_DATABASE = 
+    private static final String ERROR_DATABASE =
             "The controller could not communicate with the system database.";
-    
+
     protected BasicFactory factory;
     protected ConcurrentMap<OFType,
-                            ListenerDispatcher<OFType,IOFMessageListener>> 
+                            ListenerDispatcher<OFType,IOFMessageListener>>
                                 messageListeners;
     // OFSwitch driver binding map and order
     protected Map<String, IOFSwitchDriver>switchBindingMap;
     protected List<String> switchDescSortedList;
-    
+
     // The activeSwitches map contains only those switches that are actively
     // being controlled by us -- it doesn't contain switches that are
     // in the slave role
@@ -154,16 +152,16 @@ public class Controller implements IFloodlightProviderService,
     // We add a switch to this set after it successfully completes the
     // handshake. Access to this Set needs to be synchronized with roleChanger
     protected HashSet<IOFSwitch> connectedSwitches;
-    
-    // The controllerNodeIPsCache maps Controller IDs to their IP address. 
+
+    // The controllerNodeIPsCache maps Controller IDs to their IP address.
     // It's only used by handleControllerNodeIPsChanged
     protected HashMap<String, String> controllerNodeIPsCache;
-    
+
     protected Set<IOFSwitchListener> switchListeners;
     protected Set<IHAListener> haListeners;
     protected Map<String, List<IInfoProvider>> providerMap;
     protected BlockingQueue<IUpdate> updates;
-    
+
     // Module dependencies
     protected IRestApiService restApi;
     protected ICounterStoreService counterStore = null;
@@ -171,43 +169,43 @@ public class Controller implements IFloodlightProviderService,
     protected IStorageSourceService storageSource;
     protected IPktInProcessingTimeService pktinProcTime;
     protected IThreadPoolService threadPool;
-    
+
     // Configuration options
     protected int openFlowPort = 6633;
     protected int workerThreads = 0;
     // The id for this controller node. Should be unique for each controller
     // node in a controller cluster.
     protected String controllerId = "localhost";
-    
+
     // The current role of the controller.
     // If the controller isn't configured to support roles, then this is null.
     protected Role role;
     // A helper that handles sending and timeout handling for role requests
     protected RoleChanger roleChanger;
-    
+
     // Start time of the controller
     protected long systemStartTime;
-    
+
     // Flag to always flush flow table on switch reconnect (HA or otherwise)
     protected boolean alwaysClearFlowsOnSwAdd = false;
-    
+
     // Storage table names
     protected static final String CONTROLLER_TABLE_NAME = "controller_controller";
     protected static final String CONTROLLER_ID = "id";
-    
+
     protected static final String SWITCH_CONFIG_TABLE_NAME = "controller_switchconfig";
     protected static final String SWITCH_CONFIG_CORE_SWITCH = "core_switch";
-    
+
     protected static final String CONTROLLER_INTERFACE_TABLE_NAME = "controller_controllerinterface";
     protected static final String CONTROLLER_INTERFACE_ID = "id";
     protected static final String CONTROLLER_INTERFACE_CONTROLLER_ID = "controller_id";
     protected static final String CONTROLLER_INTERFACE_TYPE = "type";
     protected static final String CONTROLLER_INTERFACE_NUMBER = "number";
     protected static final String CONTROLLER_INTERFACE_DISCOVERED_IP = "discovered_ip";
-    
+
     // Perf. related configuration
     protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
-    protected static final int BATCH_MAX_SIZE = 100;
+    public static final int BATCH_MAX_SIZE = 100;
     protected static final boolean ALWAYS_DECODE_ETH = true;
 
     // Load monitor for overload protection
@@ -216,10 +214,10 @@ public class Controller implements IFloodlightProviderService,
     protected final LoadMonitor loadmonitor = new LoadMonitor(log);
 
     /**
-     *  Updates handled by the main loop 
+     *  Updates handled by the main loop
      */
     protected interface IUpdate {
-        /** 
+        /**
          * Calls the appropriate listeners
          */
         public void dispatch();
@@ -230,7 +228,7 @@ public class Controller implements IFloodlightProviderService,
         PORTCHANGED
     }
     /**
-     * Update message indicating a switch was added or removed 
+     * Update message indicating a switch was added or removed
      */
     protected class SwitchUpdate implements IUpdate {
         public IOFSwitch sw;
@@ -239,6 +237,7 @@ public class Controller implements IFloodlightProviderService,
             this.sw = sw;
             this.switchUpdateType = switchUpdateType;
         }
+        @Override
         public void dispatch() {
             if (log.isTraceEnabled()) {
                 log.trace("Dispatching switch update {} {}",
@@ -261,7 +260,7 @@ public class Controller implements IFloodlightProviderService,
             }
         }
     }
-    
+
     /**
      * Update message indicating controller's role has changed
      */
@@ -272,6 +271,7 @@ public class Controller implements IFloodlightProviderService,
             this.oldRole = oldRole;
             this.newRole = newRole;
         }
+        @Override
         public void dispatch() {
             // Make sure that old and new roles are different.
             if (oldRole == newRole) {
@@ -293,7 +293,7 @@ public class Controller implements IFloodlightProviderService,
             }
         }
     }
-    
+
     /**
      * Update message indicating
      * IPs of controllers in controller cluster have changed.
@@ -303,13 +303,14 @@ public class Controller implements IFloodlightProviderService,
         public Map<String,String> addedControllerNodeIPs;
         public Map<String,String> removedControllerNodeIPs;
         public HAControllerNodeIPUpdate(
-                HashMap<String,String> curControllerNodeIPs,  
-                HashMap<String,String> addedControllerNodeIPs,  
+                HashMap<String,String> curControllerNodeIPs,
+                HashMap<String,String> addedControllerNodeIPs,
                 HashMap<String,String> removedControllerNodeIPs) {
             this.curControllerNodeIPs = curControllerNodeIPs;
             this.addedControllerNodeIPs = addedControllerNodeIPs;
             this.removedControllerNodeIPs = removedControllerNodeIPs;
         }
+        @Override
         public void dispatch() {
             if (log.isTraceEnabled()) {
                 log.trace("Dispatching HA Controller Node IP update "
@@ -326,31 +327,31 @@ public class Controller implements IFloodlightProviderService,
             }
         }
     }
-    
+
     // ***************
     // Getters/Setters
     // ***************
-    
+
     public void setStorageSourceService(IStorageSourceService storageSource) {
         this.storageSource = storageSource;
     }
-    
+
     public void setCounterStore(ICounterStoreService counterStore) {
         this.counterStore = counterStore;
     }
-    
+
     public void setFlowCacheMgr(IFlowCacheService flowCacheMgr) {
         this.bigFlowCacheMgr = flowCacheMgr;
     }
-    
+
     public void setPktInProcessingService(IPktInProcessingTimeService pits) {
         this.pktinProcTime = pits;
     }
-    
+
     public void setRestApiService(IRestApiService restApi) {
         this.restApi = restApi;
     }
-    
+
     public void setThreadPoolService(IThreadPoolService tp) {
         this.threadPool = tp;
     }
@@ -361,14 +362,14 @@ public class Controller implements IFloodlightProviderService,
             return role;
         }
     }
-    
+
     @Override
     public void setRole(Role role) {
         if (role == null) throw new NullPointerException("Role can not be null.");
-        
+
         // Need to synchronize to ensure a reliable ordering on role request
         // messages send and to ensure the list of connected switches is stable
-        // RoleChanger will handle the actual sending of the message and 
+        // RoleChanger will handle the actual sending of the message and
         // timeout handling
         // @see RoleChanger
         synchronized(roleChanger) {
@@ -379,10 +380,10 @@ public class Controller implements IFloodlightProviderService,
 
             Role oldRole = this.role;
             this.role = role;
-            
+
             log.debug("Submitting role change request to role {}", role);
             roleChanger.submitRequest(connectedSwitches, role);
-            
+
             // Enqueue an update for our listeners.
             try {
                 this.updates.put(new HARoleUpdate(role, oldRole));
@@ -391,13 +392,13 @@ public class Controller implements IFloodlightProviderService,
             }
         }
     }
-    
-    
-    
+
+
+
     // **********************
     // ChannelUpstreamHandler
     // **********************
-    
+
     /**
      * Return a new channel handler for processing a switch connections
      * @param state The channel state object for the connection
@@ -406,28 +407,28 @@ public class Controller implements IFloodlightProviderService,
     protected ChannelUpstreamHandler getChannelHandler(OFChannelState state) {
         return new OFChannelHandler(state);
     }
-    
+
     /**
      * Channel handler deals with the switch connection and dispatches
      * switch messages to the appropriate locations.
      * @author readams
      */
-    protected class OFChannelHandler 
+    protected class OFChannelHandler
         extends IdleStateAwareChannelUpstreamHandler {
         protected IOFSwitch sw;
         protected Channel channel;
         protected OFChannelState state;
-        
+
         public OFChannelHandler(OFChannelState state) {
             this.state = state;
         }
 
         @Override
         @LogMessageDoc(message="New switch connection from {ip address}",
-                       explanation="A new switch has connected from the " + 
+                       explanation="A new switch has connected from the " +
                                 "specified IP address")
         public void channelConnected(ChannelHandlerContext ctx,
-                                     ChannelStateEvent e) throws Exception {            
+                                     ChannelStateEvent e) throws Exception {
             channel = e.getChannel();
             log.info("New switch connection from {}",
                      channel.getRemoteAddress());
@@ -442,12 +443,13 @@ public class Controller implements IFloodlightProviderService,
             if (sw != null && state.hsState == HandshakeState.READY) {
                 if (activeSwitches.containsKey(sw.getId())) {
                     // It's safe to call removeSwitch even though the map might
-                    // not contain this particular switch but another with the 
+                    // not contain this particular switch but another with the
                     // same DPID
                     removeSwitch(sw);
                 }
                 synchronized(roleChanger) {
                     connectedSwitches.remove(sw);
+                    roleChanger.removePendingRequests(sw);
                 }
                 sw.setConnected(false);
             }
@@ -458,13 +460,13 @@ public class Controller implements IFloodlightProviderService,
         @LogMessageDocs({
             @LogMessageDoc(level="ERROR",
                     message="Disconnecting switch {switch} due to read timeout",
-                    explanation="The connected switch has failed to send any " + 
+                    explanation="The connected switch has failed to send any " +
                                 "messages or respond to echo requests",
                     recommendation=LogMessageDoc.CHECK_SWITCH),
             @LogMessageDoc(level="ERROR",
-                    message="Disconnecting switch {switch}: failed to " + 
+                    message="Disconnecting switch {switch}: failed to " +
                             "complete handshake",
-                    explanation="The switch did not respond correctly " + 
+                    explanation="The switch did not respond correctly " +
                                 "to handshake messages",
                     recommendation=LogMessageDoc.CHECK_SWITCH),
             @LogMessageDoc(level="ERROR",
@@ -472,7 +474,7 @@ public class Controller implements IFloodlightProviderService,
                     explanation="There was an error communicating with the switch",
                     recommendation=LogMessageDoc.CHECK_SWITCH),
             @LogMessageDoc(level="ERROR",
-                    message="Disconnecting switch {switch} due to switch " + 
+                    message="Disconnecting switch {switch} due to switch " +
                             "state error: {error}",
                     explanation="The switch sent an unexpected message",
                     recommendation=LogMessageDoc.CHECK_SWITCH),
@@ -503,7 +505,7 @@ public class Controller implements IFloodlightProviderService,
                 log.error("Disconnecting switch {} due to read timeout", sw);
                 ctx.getChannel().close();
             } else if (e.getCause() instanceof HandshakeTimeoutException) {
-                log.error("Disconnecting switch {}: failed to complete handshake", 
+                log.error("Disconnecting switch {}: failed to complete handshake",
                           sw);
                 ctx.getChannel().close();
             } else if (e.getCause() instanceof ClosedChannelException) {
@@ -513,16 +515,16 @@ public class Controller implements IFloodlightProviderService,
                           sw, e.getCause().getMessage());
                 ctx.getChannel().close();
             } else if (e.getCause() instanceof SwitchStateException) {
-                log.error("Disconnecting switch {} due to switch state error: {}", 
+                log.error("Disconnecting switch {} due to switch state error: {}",
                           sw, e.getCause().getMessage());
                 ctx.getChannel().close();
             } else if (e.getCause() instanceof MessageParseException) {
                 log.error("Disconnecting switch " + sw +
-                          " due to message parse failure", 
+                          " due to message parse failure",
                           e.getCause());
                 ctx.getChannel().close();
             } else if (e.getCause() instanceof StorageException) {
-                log.error("Terminating controller due to storage exception", 
+                log.error("Terminating controller due to storage exception",
                           e.getCause());
                 terminate();
             } else if (e.getCause() instanceof RejectedExecutionException) {
@@ -605,8 +607,8 @@ public class Controller implements IFloodlightProviderService,
 
                     }
                     catch (Exception ex) {
-                        // We are the last handler in the stream, so run the 
-                        // exception through the channel again by passing in 
+                        // We are the last handler in the stream, so run the
+                        // exception through the channel again by passing in
                         // ctx.getChannel().
                         Channels.fireExceptionCaught(ctx.getChannel(), ex);
                     }
@@ -624,26 +626,26 @@ public class Controller implements IFloodlightProviderService,
                 }
 
                 // Flush all flow-mods/packet-out/stats generated from this "train"
-                OFSwitchImpl.flush_all();
+                OFSwitchBase.flush_all();
                 counterStore.updateFlush();
                 bigFlowCacheMgr.updateFlush();
             }
         }
-        
+
         /**
          * Process the request for the switch description
          */
         @LogMessageDoc(level="ERROR",
-                message="Exception in reading description " + 
+                message="Exception in reading description " +
                         " during handshake {exception}",
                 explanation="Could not process the switch description string",
                 recommendation=LogMessageDoc.CHECK_SWITCH)
         void processSwitchDescReply(OFStatisticsReply m) {
             try {
                 // Read description, if it has been updated
-                OFDescriptionStatistics description = 
+                OFDescriptionStatistics description =
                         new OFDescriptionStatistics();
-                ChannelBuffer data = 
+                ChannelBuffer data =
                         ChannelBuffers.buffer(description.getLength());
                 OFStatistics f = m.getFirstStatistics();
                 f.writeTo(data);
@@ -653,7 +655,7 @@ public class Controller implements IFloodlightProviderService,
                 checkSwitchReady();
             }
             catch (Exception ex) {
-                log.error("Exception in reading description " + 
+                log.error("Exception in reading description " +
                           " during handshake", ex);
             }
         }
@@ -669,7 +671,7 @@ public class Controller implements IFloodlightProviderService,
             msglist.add(factory.getMessage(type));
             channel.write(msglist);
         }
-        
+
         /**
          * Send the configuration requests we can only do after we have
          * the features reply
@@ -685,7 +687,7 @@ public class Controller implements IFloodlightProviderService,
                 .setLengthU(OFSwitchConfig.MINIMUM_LENGTH);
             configSet.setXid(-4);
             msglist.add(configSet);
-            
+
             // Verify (need barrier?)
             OFGetConfigRequest configReq = (OFGetConfigRequest)
                     factory.getMessage(OFType.GET_CONFIG_REQUEST);
@@ -698,10 +700,10 @@ public class Controller implements IFloodlightProviderService,
             req.setXid(-2);  // something "large"
             req.setLengthU(req.getLengthU());
             msglist.add(req);
-            
+
             channel.write(msglist);
         }
-        
+
         protected void checkSwitchReady() {
             if (!state.switchBindingDone) {
                 bindSwitchToDriver();
@@ -709,49 +711,47 @@ public class Controller implements IFloodlightProviderService,
 
             if (state.hsState == HandshakeState.FEATURES_REPLY &&
                     state.switchBindingDone) {
-                
+
                 state.hsState = HandshakeState.READY;
-                
+
+                // replay queued port status messages
+                for (OFMessage m : state.queuedOFMessages) {
+                    try {
+                        processOFMessage(m);
+                    } catch (Exception e) {
+                        log.error("Failed to process delayed OFMessage {} {}",
+                                m, e.getCause());
+                    }
+                }
+
+                state.queuedOFMessages.clear();
                 synchronized(roleChanger) {
                     // We need to keep track of all of the switches that are connected
-                    // to the controller, in any role, so that we can later send the 
+                    // to the controller, in any role, so that we can later send the
                     // role request messages when the controller role changes.
-                    // We need to be synchronized while doing this: we must not 
+                    // We need to be synchronized while doing this: we must not
                     // send a another role request to the connectedSwitches until
-                    // we were able to add this new switch to connectedSwitches 
+                    // we were able to add this new switch to connectedSwitches
                     // *and* send the current role to the new switch.
                     connectedSwitches.add(sw);
-                    
-                    if (role != null) {
-                        // Send a role request if role support is enabled for the controller
-                        // This is a probe that we'll use to determine if the switch
-                        // actually supports the role request message. If it does we'll
-                        // get back a role reply message. If it doesn't we'll get back an
-                        // OFError message. 
-                        // If role is MASTER we will promote switch to active
-                        // list when we receive the switch's role reply messages
-                        log.debug("This controller's role is {}, " + 
-                                "sending initial role request msg to {}",
-                                role, sw);
-                        Collection<IOFSwitch> swList = new ArrayList<IOFSwitch>(1);
-                        swList.add(sw);
-                        roleChanger.submitRequest(swList, role);
-                    }
-                    else {
-                        // Role supported not enabled on controller (for now)
-                        // automatically promote switch to active state. 
-                        log.debug("This controller's role is null, " + 
-                                "not sending role request msg to {}",
-                                role, sw);
-                        // Need to clear FlowMods before we add the switch
-                        // and dispatch updates otherwise we have a race condition.
-                        addSwitch(sw, true);
-                        state.firstRoleReplyReceived = true;
-                    }
+
+                    // Send a role request.
+                    // This is a probe that we'll use to determine if the switch
+                    // actually supports the role request message. If it does we'll
+                    // get back a role reply message. If it doesn't we'll get back an
+                    // OFError message.
+                    // If role is MASTER we will promote switch to active
+                    // list when we receive the switch's role reply messages
+                    log.debug("This controller's role is {}, " +
+                            "sending initial role request msg to {}",
+                            role, sw);
+                    Collection<IOFSwitch> swList = new ArrayList<IOFSwitch>(1);
+                    swList.add(sw);
+                    roleChanger.submitRequest(swList, role);
                 }
             }
         }
-                
+
         protected void bindSwitchToDriver() {
             if (!state.hasGetConfigReply) {
                 log.debug("Waiting for config reply from switch {}",
@@ -763,12 +763,12 @@ public class Controller implements IFloodlightProviderService,
                         channel.getRemoteAddress());
                 return;
             }
-            
+
             for (String desc : switchDescSortedList) {
                 if (state.description.getManufacturerDescription()
                         .startsWith(desc)) {
                     sw = switchBindingMap.get(desc)
-                            .getOFSwitchImpl(state.description);
+                            .getOFSwitchImpl(desc, state.description);
                     if (sw != null) {
                         break;
                     }
@@ -783,40 +783,38 @@ public class Controller implements IFloodlightProviderService,
             sw.setFloodlightProvider(Controller.this);
             sw.setThreadPoolService(threadPool);
             sw.setFeaturesReply(state.featuresReply);
-            sw.setAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA,
-                        state.description);
             sw.setSwitchProperties(state.description);
             readPropertyFromStorage();
 
+            log.info("Switch {} bound to class {}",
+                    HexString.toHexString(sw.getId()), sw.getClass().getName());
+            log.info("{}", state.description);
+
             state.featuresReply = null;
             state.description = null;
             state.switchBindingDone = true;
-
-            log.info("Switch {} bound to class {}",
-                    HexString.toHexString(sw.getId()), sw.getClass().getName());
-            return;
         }
-        
-        private void readPropertyFromStorage() {
+
+       private void readPropertyFromStorage() {
             // At this time, also set other switch properties from storage
             boolean is_core_switch = false;
             IResultSet resultSet = null;
             try {
                 String swid = sw.getStringId();
-                resultSet = 
+                resultSet =
                         storageSource.getRow(SWITCH_CONFIG_TABLE_NAME, swid);
-                for (Iterator<IResultSet> it = 
+                for (Iterator<IResultSet> it =
                         resultSet.iterator(); it.hasNext();) {
                     // In case of multiple rows, use the status
                     // in last row?
                     Map<String, Object> row = it.next().getRow();
                     if (row.containsKey(SWITCH_CONFIG_CORE_SWITCH)) {
                         if (log.isDebugEnabled()) {
-                            log.debug("Reading SWITCH_IS_CORE_SWITCH " + 
+                            log.debug("Reading SWITCH_IS_CORE_SWITCH " +
                                     "config for switch={}, is-core={}",
                                     sw, row.get(SWITCH_CONFIG_CORE_SWITCH));
                         }
-                        String ics = 
+                        String ics =
                                 (String)row.get(SWITCH_CONFIG_CORE_SWITCH);
                         is_core_switch = ics.equals("true");
                     }
@@ -827,109 +825,11 @@ public class Controller implements IFloodlightProviderService,
                     resultSet.close();
             }
             if (is_core_switch) {
-                sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, 
+                sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH,
                         new Boolean(true));
             }
         }
 
-        /* Handle a role reply message we received from the switch. Since
-         * netty serializes message dispatch we don't need to synchronize 
-         * against other receive operations from the same switch, so no need
-         * to synchronize addSwitch(), removeSwitch() operations from the same
-         * connection. 
-         * FIXME: However, when a switch with the same DPID connects we do
-         * need some synchronization. However, handling switches with same
-         * DPID needs to be revisited anyways (get rid of r/w-lock and synchronous
-         * removedSwitch notification):1
-         * 
-         */
-        @LogMessageDoc(level="ERROR",
-                message="Invalid role value in role reply message",
-                explanation="Was unable to set the HA role (master or slave) " +
-                        "for the controller.",
-                recommendation=LogMessageDoc.CHECK_CONTROLLER)
-        protected void handleRoleReplyMessage(OFVendor vendorMessage,
-                                    OFRoleReplyVendorData roleReplyVendorData) {
-            // Map from the role code in the message to our role enum
-            int nxRole = roleReplyVendorData.getRole();
-            Role role = null;
-            switch (nxRole) {
-                case OFRoleVendorData.NX_ROLE_OTHER:
-                    role = Role.EQUAL;
-                    break;
-                case OFRoleVendorData.NX_ROLE_MASTER:
-                    role = Role.MASTER;
-                    break;
-                case OFRoleVendorData.NX_ROLE_SLAVE:
-                    role = Role.SLAVE;
-                    break;
-                default:
-                    log.error("Invalid role value in role reply message");
-                    sw.getChannel().close();
-                    return;
-            }
-            
-            log.debug("Handling role reply for role {} from {}. " +
-                      "Controller's role is {} ", 
-                      new Object[] { role, sw, Controller.this.role} 
-                      );
-            
-            sw.deliverRoleReply(vendorMessage.getXid(), role);
-            
-            if (sw.isActive()) {
-            // Transition from SLAVE to MASTER.
-                boolean shouldClearFlowMods = false;
-                if (!state.firstRoleReplyReceived || 
-                    getAlwaysClearFlowsOnSwAdd()) {
-                    // This is the first role-reply message we receive from
-                    // this switch or roles were disabled when the switch
-                    // connected: 
-                    // Delete all pre-existing flows for new connections to 
-                    // the master
-                    //
-                    // FIXME: Need to think more about what the test should 
-                    // be for when we flush the flow-table? For example, 
-                    // if all the controllers are temporarily in the backup 
-                    // role (e.g. right after a failure of the master 
-                    // controller) at the point the switch connects, then 
-                    // all of the controllers will initially connect as 
-                    // backup controllers and not flush the flow-table. 
-                    // Then when one of them is promoted to master following
-                    // the master controller election the flow-table
-                    // will still not be flushed because that's treated as 
-                    // a failover event where we don't want to flush the 
-                    // flow-table. The end result would be that the flow 
-                    // table for a newly connected switch is never
-                    // flushed. Not sure how to handle that case though...
-                    shouldClearFlowMods = true;
-                    log.debug("First role reply from master switch {}, " +
-                              "clear FlowTable to active switch list",
-                             HexString.toHexString(sw.getId()));
-                }
-                
-                // Only add the switch to the active switch list if 
-                // we're not in the slave role. Note that if the role 
-                // attribute is null, then that means that the switch 
-                // doesn't support the role request messages, so in that
-                // case we're effectively in the EQUAL role and the 
-                // switch should be included in the active switch list.
-                addSwitch(sw, shouldClearFlowMods);
-                log.debug("Added master switch {} to active switch list",
-                         HexString.toHexString(sw.getId()));
-
-            } 
-            else {
-                // Transition from MASTER to SLAVE: remove switch 
-                // from active switch list. 
-                log.debug("Removed slave switch {} from active switch" +
-                          " list", HexString.toHexString(sw.getId()));
-                removeSwitch(sw);
-            }
-            
-            // Indicate that we have received a role reply message. 
-            state.firstRoleReplyReceived = true;
-        }
-
         protected boolean handleVendorMessage(OFVendor vendorMessage) {
             boolean shouldHandleMessage = false;
             int vendor = vendorMessage.getVendor();
@@ -942,8 +842,8 @@ public class Controller implements IFloodlightProviderService,
                         case OFRoleReplyVendorData.NXT_ROLE_REPLY:
                             OFRoleReplyVendorData roleReplyVendorData =
                                     (OFRoleReplyVendorData) niciraVendorData;
-                            handleRoleReplyMessage(vendorMessage, 
-                                                   roleReplyVendorData);
+                            roleChanger.handleRoleReplyMessage(sw,
+                                    vendorMessage, roleReplyVendorData);
                             break;
                         default:
                             log.warn("Unhandled Nicira VENDOR message; " +
@@ -955,7 +855,7 @@ public class Controller implements IFloodlightProviderService,
                     log.warn("Unhandled VENDOR message; vendor id = {}", vendor);
                     break;
             }
-            
+
             return shouldHandleMessage;
         }
 
@@ -964,7 +864,7 @@ public class Controller implements IFloodlightProviderService,
          * handler.
          * @param m The message to process
          * @throws IOException
-         * @throws SwitchStateException 
+         * @throws SwitchStateException
          */
         @LogMessageDocs({
             @LogMessageDoc(level="WARN",
@@ -986,17 +886,17 @@ public class Controller implements IFloodlightProviderService,
         protected void processOFMessage(OFMessage m)
                 throws IOException, SwitchStateException {
             boolean shouldHandleMessage = false;
-            
+
             switch (m.getType()) {
                 case HELLO:
                     if (log.isTraceEnabled())
                         log.trace("HELLO from {}", sw);
-                    
+
                     if (state.hsState.equals(HandshakeState.START)) {
                         state.hsState = HandshakeState.HELLO;
                         sendHandShakeMessage(OFType.FEATURES_REQUEST);
                     } else {
-                        throw new SwitchStateException("Unexpected HELLO from " 
+                        throw new SwitchStateException("Unexpected HELLO from "
                                                        + sw);
                     }
                     break;
@@ -1013,14 +913,11 @@ public class Controller implements IFloodlightProviderService,
                 case FEATURES_REPLY:
                     if (log.isTraceEnabled())
                         log.trace("Features Reply from {}", sw);
-                    
+
                     if (state.hsState.equals(HandshakeState.HELLO)) {
                         sendFeatureReplyConfiguration();
                         state.featuresReply = (OFFeaturesReply) m;
                         state.hsState = HandshakeState.FEATURES_REPLY;
-                        // uncomment to enable "dumb" switches like cbench
-                        // state.hsState = HandshakeState.READY;
-                        // addSwitch(sw);
                     } else {
                         // return results to rest api caller
                         sw.setFeaturesReply((OFFeaturesReply) m);
@@ -1030,18 +927,18 @@ public class Controller implements IFloodlightProviderService,
                 case GET_CONFIG_REPLY:
                     if (log.isTraceEnabled())
                         log.trace("Get config reply from {}", sw);
-                    
+
                     if (!state.hsState.equals(HandshakeState.FEATURES_REPLY)) {
                         String em = "Unexpected GET_CONFIG_REPLY from " + sw;
                         throw new SwitchStateException(em);
                     }
                     OFGetConfigReply cr = (OFGetConfigReply) m;
                     if (cr.getMissSendLength() == (short)0xffff) {
-                        log.trace("Config Reply from {} confirms " + 
+                        log.trace("Config Reply from {} confirms " +
                                   "miss length set to 0xffff", sw);
                     } else {
                         log.warn("Config Reply from {} has " +
-                                 "miss length set to {}", 
+                                 "miss length set to {}",
                                  sw, cr.getMissSendLength() & 0xffff);
                     }
                     state.hasGetConfigReply = true;
@@ -1051,134 +948,73 @@ public class Controller implements IFloodlightProviderService,
                     shouldHandleMessage = handleVendorMessage((OFVendor)m);
                     break;
                 case ERROR:
-                    // TODO: we need better error handling. Especially for 
+                    // TODO: we need better error handling. Especially for
                     // request/reply style message (stats, roles) we should have
-                    // a unified way to lookup the xid in the error message. 
+                    // a unified way to lookup the xid in the error message.
                     // This will probable involve rewriting the way we handle
                     // request/reply style messages.
                     OFError error = (OFError) m;
-                    boolean shouldLogError = true;
-                    // TODO: should we check that firstRoleReplyReceived is false,
-                    // i.e., check only whether the first request fails?
-                    if (sw.checkFirstPendingRoleRequestXid(error.getXid())) {
-                        boolean isBadVendorError =
-                            (error.getErrorType() == OFError.OFErrorType.
-                                    OFPET_BAD_REQUEST.getValue());
-                        // We expect to receive a bad vendor error when 
-                        // we're connected to a switch that doesn't support 
-                        // the Nicira vendor extensions (i.e. not OVS or 
-                        // derived from OVS).  By protocol, it should also be
-                        // BAD_VENDOR, but too many switch implementations
-                        // get it wrong and we can already check the xid()
-                        // so we can ignore the type with confidence that this
-                        // is not a spurious error
-                        shouldLogError = !isBadVendorError;
-                        if (isBadVendorError) {
-                            if (state.firstRoleReplyReceived && (role != null)) {
-                                log.warn("Received ERROR from sw {} that "
-                                          +"indicates roles are not supported "
-                                          +"but we have received a valid "
-                                          +"role reply earlier", sw);
-                            }
-                            state.firstRoleReplyReceived = true;
-                            sw.deliverRoleRequestNotSupported(error.getXid());
-                            synchronized(roleChanger) {
-                                if (sw.getRole() == null &&
-                                        Controller.this.role==Role.SLAVE) {
-                                    // the switch doesn't understand role request
-                                    // messages and the current controller role is
-                                    // slave. We need to disconnect the switch. 
-                                    // @see RoleChanger for rationale
-                                    sw.getChannel().close();
-                                }
-                                else if (sw.getRole() == null) {
-                                    // Controller's role is master: add to
-                                    // active 
-                                    // TODO: check if clearing flow table is
-                                    // right choice here.
-                                    // Need to clear FlowMods before we add the switch
-                                    // and dispatch updates otherwise we have a race condition.
-                                    // TODO: switch update is async. Won't we still have a potential
-                                    //       race condition? 
-                                    addSwitch(sw, true);
-                                }
-                            }
-                        }
-                        else {
-                            // TODO: Is this the right thing to do if we receive
-                            // some other error besides a bad vendor error? 
-                            // Presumably that means the switch did actually
-                            // understand the role request message, but there 
-                            // was some other error from processing the message.
-                            // OF 1.2 specifies a OFPET_ROLE_REQUEST_FAILED
-                            // error code, but it doesn't look like the Nicira 
-                            // role request has that. Should check OVS source 
-                            // code to see if it's possible for any other errors
-                            // to be returned.
-                            // If we received an error the switch is not
-                            // in the correct role, so we need to disconnect it. 
-                            // We could also resend the request but then we need to
-                            // check if there are other pending request in which
-                            // case we shouldn't resend. If we do resend we need
-                            // to make sure that the switch eventually accepts one
-                            // of our requests or disconnect the switch. This feels
-                            // cumbersome. 
-                            sw.getChannel().close();
-                        }
+
+                    if (roleChanger.checkFirstPendingRoleRequestXid(
+                            sw, error.getXid())) {
+                        roleChanger.deliverRoleRequestError(sw, error);
                     }
-                    // Once we support OF 1.2, we'd add code to handle it here.
-                    //if (error.getXid() == state.ofRoleRequestXid) {
-                    //}
-                    if (shouldLogError)
+                    else {
                         logError(sw, error);
+                    }
                     break;
                 case STATS_REPLY:
-                    if (state.hsState.ordinal() < 
+                    if (state.hsState.ordinal() <
                         HandshakeState.FEATURES_REPLY.ordinal()) {
                         String em = "Unexpected STATS_REPLY from " + sw;
                         throw new SwitchStateException(em);
                     }
-                    if (sw == null) { 
+                    if (sw == null) {
                         processSwitchDescReply((OFStatisticsReply) m);
                     } else {
                         sw.deliverStatisticsReply(m);
                     }
                     break;
                 case PORT_STATUS:
-                    handlePortStatusMessage(sw, (OFPortStatus)m);
-                    shouldHandleMessage = true;
+                    if (sw != null) {
+                        handlePortStatusMessage(sw, (OFPortStatus)m);
+                        shouldHandleMessage = true;
+                    } else {
+                        // Queue till we complete driver binding
+                        state.queuedOFMessages.add((OFPortStatus) m);
+                    }
                     break;
 
                 default:
                     shouldHandleMessage = true;
                     break;
             }
-            
+
             if (shouldHandleMessage) {
                 // WARNING: sw is null if handshake is not complete
                 if (!state.hsState.equals(HandshakeState.READY)) {
-                    log.debug("Ignoring message type {} received " + 
-                              "from switch {} before switch is " + 
+                    log.debug("Ignoring message type {} received " +
+                              "from switch {} before switch is " +
                               "fully configured.", m.getType(), sw);
                 } else {
                     sw.getListenerReadLock().lock();
                     try {
 
                         if (sw.isConnected()) {
-                            // Check if the controller is in the slave role for the 
-                            // switch. If it is, then don't dispatch the message to 
+                            // Check if the controller is in the slave role for the
+                            // switch. If it is, then don't dispatch the message to
                             // the listeners.
-                            // TODO: Should we dispatch messages that we expect to 
-                            // receive when we're in the slave role, e.g. port 
-                            // status messages? Since we're "hiding" switches from 
-                            // the listeners when we're in the slave role, then it 
+                            // TODO: Should we dispatch messages that we expect to
+                            // receive when we're in the slave role, e.g. port
+                            // status messages? Since we're "hiding" switches from
+                            // the listeners when we're in the slave role, then it
                             // seems a little weird to dispatch port status messages
-                            // to them. On the other hand there might be special 
+                            // to them. On the other hand there might be special
                             // modules that care about all of the connected switches
                             // and would like to receive port status notifications.
-                            if (sw.getRole() == Role.SLAVE) {
-                                // Don't log message if it's a port status message 
-                                // since we expect to receive those from the switch 
+                            if (sw.getHARole() == Role.SLAVE) {
+                                // Don't log message if it's a port status message
+                                // since we expect to receive those from the switch
                                 // and don't want to emit spurious messages.
                                 if (m.getType() != OFType.PORT_STATUS) {
                                     log.debug("Ignoring message type {} received " +
@@ -1201,7 +1037,7 @@ public class Controller implements IFloodlightProviderService,
     // ****************
     // Message handlers
     // ****************
-    
+
     protected void handlePortStatusMessage(IOFSwitch sw, OFPortStatus m) {
         short portNumber = m.getDesc().getPortNumber();
         OFPhysicalPort port = m.getDesc();
@@ -1211,7 +1047,7 @@ public class Controller implements IFloodlightProviderService,
         } else if (m.getReason() == (byte)OFPortReason.OFPPR_ADD.ordinal()) {
             sw.setPort(port);
             log.debug("Port #{} added for {}", portNumber, sw);
-        } else if (m.getReason() == 
+        } else if (m.getReason() ==
                    (byte)OFPortReason.OFPPR_DELETE.ordinal()) {
             sw.deletePort(portNumber);
             log.debug("Port #{} deleted for {}", portNumber, sw);
@@ -1223,7 +1059,7 @@ public class Controller implements IFloodlightProviderService,
             log.error("Failure adding update to queue", e);
         }
     }
-    
+
     /**
      * flcontext_cache - Keep a thread local stack of contexts
      */
@@ -1289,13 +1125,13 @@ public class Controller implements IFloodlightProviderService,
         switch (m.getType()) {
             case PACKET_IN:
                 OFPacketIn pi = (OFPacketIn)m;
-                
+
                 if (pi.getPacketData().length <= 0) {
-                    log.error("Ignoring PacketIn (Xid = " + pi.getXid() + 
+                    log.error("Ignoring PacketIn (Xid = " + pi.getXid() +
                               ") because the data field is empty.");
                     return;
                 }
-                
+
                 if (Controller.ALWAYS_DECODE_ETH) {
                     eth = new Ethernet();
                     eth.deserialize(pi.getPacketData(), 0,
@@ -1305,17 +1141,17 @@ public class Controller implements IFloodlightProviderService,
                 // fall through to default case...
 
             default:
-                
+
                 List<IOFMessageListener> listeners = null;
                 if (messageListeners.containsKey(m.getType())) {
                     listeners = messageListeners.get(m.getType()).
                             getOrderedListeners();
                 }
-                        
+
                 FloodlightContext bc = null;
                 if (listeners != null) {
-                    // Check if floodlight context is passed from the calling 
-                    // function, if so use that floodlight context, otherwise 
+                    // Check if floodlight context is passed from the calling
+                    // function, if so use that floodlight context, otherwise
                     // allocate one
                     if (bContext == null) {
                         bc = flcontext_alloc();
@@ -1323,16 +1159,16 @@ public class Controller implements IFloodlightProviderService,
                         bc = bContext;
                     }
                     if (eth != null) {
-                        IFloodlightProviderService.bcStore.put(bc, 
-                                IFloodlightProviderService.CONTEXT_PI_PAYLOAD, 
+                        IFloodlightProviderService.bcStore.put(bc,
+                                IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
                                 eth);
                     }
-                    
-                    // Get the starting time (overall and per-component) of 
+
+                    // Get the starting time (overall and per-component) of
                     // the processing chain for this packet if performance
                     // monitoring is turned on
                     pktinProcTime.bootstrap(listeners);
-                    pktinProcTime.recordStartTimePktIn();                     
+                    pktinProcTime.recordStartTimePktIn();
                     Command cmd;
                     for (IOFMessageListener listener : listeners) {
                         if (listener instanceof IOFSwitchFilter) {
@@ -1344,7 +1180,7 @@ public class Controller implements IFloodlightProviderService,
                         pktinProcTime.recordStartTimeComp(listener);
                         cmd = listener.receive(sw, m, bc);
                         pktinProcTime.recordEndTimeComp(listener);
-                        
+
                         if (Command.STOP.equals(cmd)) {
                             break;
                         }
@@ -1353,11 +1189,11 @@ public class Controller implements IFloodlightProviderService,
                 } else {
                     log.warn("Unhandled OF Message: {} from {}", m, sw);
                 }
-                
+
                 if ((bContext == null) && (bc != null)) flcontext_free(bc);
         }
     }
-    
+
     /**
      * Log an OpenFlow error message from a switch
      * @param sw The switch that sent the error
@@ -1379,12 +1215,12 @@ public class Controller implements IFloodlightProviderService,
         OFErrorType et = OFErrorType.values()[etint];
         switch (et) {
             case OFPET_HELLO_FAILED:
-                OFHelloFailedCode hfc = 
+                OFHelloFailedCode hfc =
                     OFHelloFailedCode.values()[0xffff & error.getErrorCode()];
                 log.error("Error {} {} from {}", new Object[] {et, hfc, sw});
                 break;
             case OFPET_BAD_REQUEST:
-                OFBadRequestCode brc = 
+                OFBadRequestCode brc =
                     OFBadRequestCode.values()[0xffff & error.getErrorCode()];
                 log.error("Error {} {} from {}", new Object[] {et, brc, sw});
                 break;
@@ -1412,16 +1248,16 @@ public class Controller implements IFloodlightProviderService,
                 break;
         }
     }
-    
+
     /**
      * Add a switch to the active switch list and call the switch listeners.
      * This happens either when a switch first connects (and the controller is
      * not in the slave role) or when the role of the controller changes from
      * slave to master.
-     * 
-     * FIXME: remove shouldReadSwitchPortStateFromStorage argument once 
+     *
+     * FIXME: remove shouldReadSwitchPortStateFromStorage argument once
      * performance problems are solved. We should call it always or never.
-     * 
+     *
      * @param sw the switch that has been added
      */
     // TODO: need to rethink locking and the synchronous switch update.
@@ -1440,7 +1276,7 @@ public class Controller implements IFloodlightProviderService,
                     "network problem that can be ignored."
             )
     protected void addSwitch(IOFSwitch sw, boolean shouldClearFlowMods) {
-        // TODO: is it safe to modify the HashMap without holding 
+        // TODO: is it safe to modify the HashMap without holding
         // the old switch's lock?
         IOFSwitch oldSw = this.activeSwitches.put(sw.getId(), sw);
         if (sw == oldSw) {
@@ -1448,9 +1284,9 @@ public class Controller implements IFloodlightProviderService,
             log.info("New add switch for pre-existing switch {}", sw);
             return;
         }
-        
-        
-        
+
+
+
         if (oldSw != null) {
             oldSw.getListenerWriteLock().lock();
             try {
@@ -1459,10 +1295,10 @@ public class Controller implements IFloodlightProviderService,
                 // Set the connected flag to false to suppress calling
                 // the listeners for this switch in processOFMessage
                 oldSw.setConnected(false);
-                
+
                 oldSw.cancelAllStatisticsReplies();
-                
-                // we need to clean out old switch state definitively 
+
+                // we need to clean out old switch state definitively
                 // before adding the new switch
                 // FIXME: It seems not completely kosher to call the
                 // switch listeners here. I thought one of the points of
@@ -1479,16 +1315,16 @@ public class Controller implements IFloodlightProviderService,
                 // a "Not removing Switch ... already removed debug message.
                 // TODO: Figure out a way to handle this that avoids the
                 // spurious debug message.
-                oldSw.getChannel().close();
+                oldSw.disconnectOutputStream();
             }
             finally {
                 oldSw.getListenerWriteLock().unlock();
             }
         }
-        
+
         if (shouldClearFlowMods)
             sw.clearAllFlowMods();
-        
+
         SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.ADDED);
         try {
             this.updates.put(update);
@@ -1513,11 +1349,11 @@ public class Controller implements IFloodlightProviderService,
             return;
         }
         // We cancel all outstanding statistics replies if the switch transition
-        // from active. In the future we might allow statistics requests 
+        // from active. In the future we might allow statistics requests
         // from slave controllers. Then we need to move this cancelation
         // to switch disconnect
         sw.cancelAllStatisticsReplies();
-            
+
         // FIXME: I think there's a race condition if we call updateInactiveSwitchInfo
         // here if role support is enabled. In that case if the switch is being
         // removed because we've been switched to being in the slave role, then I think
@@ -1526,7 +1362,7 @@ public class Controller implements IFloodlightProviderService,
         // updateInactiveSwitchInfo we may wipe out all of the state that was
         // written out by the new master. Maybe need to revisit how we handle all
         // of the switch state that's written to storage.
-        
+
         SwitchUpdate update = new SwitchUpdate(sw, SwitchUpdateType.REMOVED);
         try {
             this.updates.put(update);
@@ -1534,15 +1370,15 @@ public class Controller implements IFloodlightProviderService,
             log.error("Failure adding update to queue", e);
         }
     }
-    
+
     // ***************
     // IFloodlightProvider
     // ***************
-    
+
     @Override
-    public synchronized void addOFMessageListener(OFType type, 
+    public synchronized void addOFMessageListener(OFType type,
                                                   IOFMessageListener listener) {
-        ListenerDispatcher<OFType, IOFMessageListener> ldd = 
+        ListenerDispatcher<OFType, IOFMessageListener> ldd =
             messageListeners.get(type);
         if (ldd == null) {
             ldd = new ListenerDispatcher<OFType, IOFMessageListener>();
@@ -1554,23 +1390,23 @@ public class Controller implements IFloodlightProviderService,
     @Override
     public synchronized void removeOFMessageListener(OFType type,
                                                      IOFMessageListener listener) {
-        ListenerDispatcher<OFType, IOFMessageListener> ldd = 
+        ListenerDispatcher<OFType, IOFMessageListener> ldd =
             messageListeners.get(type);
         if (ldd != null) {
             ldd.removeListener(listener);
         }
     }
-    
+
     private void logListeners() {
         for (Map.Entry<OFType,
-                       ListenerDispatcher<OFType, 
+                       ListenerDispatcher<OFType,
                                           IOFMessageListener>> entry
              : messageListeners.entrySet()) {
-            
+
             OFType type = entry.getKey();
-            ListenerDispatcher<OFType, IOFMessageListener> ldd = 
+            ListenerDispatcher<OFType, IOFMessageListener> ldd =
                     entry.getValue();
-            
+
             StringBuffer sb = new StringBuffer();
             sb.append("OFListeners for ");
             sb.append(type);
@@ -1579,10 +1415,10 @@ public class Controller implements IFloodlightProviderService,
                 sb.append(l.getName());
                 sb.append(",");
             }
-            log.debug(sb.toString());            
+            log.debug(sb.toString());
         }
     }
-    
+
     public void removeOFMessageListeners(OFType type) {
         messageListeners.remove(type);
     }
@@ -1604,15 +1440,15 @@ public class Controller implements IFloodlightProviderService,
 
     @Override
     public Map<OFType, List<IOFMessageListener>> getListeners() {
-        Map<OFType, List<IOFMessageListener>> lers = 
+        Map<OFType, List<IOFMessageListener>> lers =
             new HashMap<OFType, List<IOFMessageListener>>();
-        for(Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e : 
+        for(Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e :
             messageListeners.entrySet()) {
             lers.put(e.getKey(), e.getValue().getOrderedListeners());
         }
         return Collections.unmodifiableMap(lers);
     }
-    
+
     @Override
     @LogMessageDocs({
         @LogMessageDoc(message="Failed to inject OFMessage {message} onto " +
@@ -1631,7 +1467,7 @@ public class Controller implements IFloodlightProviderService,
             log.info("Failed to inject OFMessage {} onto a null switch", msg);
             return false;
         }
-        
+
         // FIXME: Do we need to be able to inject messages to switches
         // where we're the slave controller (i.e. they're connected but
         // not active)?
@@ -1640,14 +1476,14 @@ public class Controller implements IFloodlightProviderService,
         // discussions it sounds like the right thing to do here would be to
         // inject the message as a netty upstream channel event so it goes
         // through the normal netty event processing, including being
-        // handled 
+        // handled
         if (!activeSwitches.containsKey(sw.getId())) return false;
-        
+
         try {
             // Pass Floodlight context to the handleMessages()
             handleMessage(sw, msg, bc);
         } catch (IOException e) {
-            log.error("Error reinjecting OFMessage on switch {}", 
+            log.error("Error reinjecting OFMessage on switch {}",
                       HexString.toHexString(sw.getId()));
             return false;
         }
@@ -1661,13 +1497,13 @@ public class Controller implements IFloodlightProviderService,
         log.info("Calling System.exit");
         System.exit(1);
     }
-    
+
     @Override
     public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) {
-        // call the overloaded version with floodlight context set to null    
+        // call the overloaded version with floodlight context set to null
         return injectOfMessage(sw, msg, null);
     }
-    
+
     @Override
     public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
                                       FloodlightContext bc) {
@@ -1678,11 +1514,11 @@ public class Controller implements IFloodlightProviderService,
 
         List<IOFMessageListener> listeners = null;
         if (messageListeners.containsKey(m.getType())) {
-            listeners = 
+            listeners =
                     messageListeners.get(m.getType()).getOrderedListeners();
         }
-            
-        if (listeners != null) {                
+
+        if (listeners != null) {
             for (IOFMessageListener listener : listeners) {
                 if (listener instanceof IOFSwitchFilter) {
                     if (!((IOFSwitchFilter)listener).isInterested(sw)) {
@@ -1700,12 +1536,12 @@ public class Controller implements IFloodlightProviderService,
     public BasicFactory getOFMessageFactory() {
         return factory;
     }
-    
+
     @Override
     public String getControllerId() {
         return controllerId;
     }
-    
+
     // **************
     // Initialization
     // **************
@@ -1717,7 +1553,7 @@ public class Controller implements IFloodlightProviderService,
         controllerInfo.put(CONTROLLER_ID, id);
         storageSource.updateRow(CONTROLLER_TABLE_NAME, controllerInfo);
     }
-    
+
 
     /**
      * Sets the initial role based on properties in the config params.
@@ -1744,12 +1580,12 @@ public class Controller implements IFloodlightProviderService,
                 explanation="Setting the initial HA role to "),
         @LogMessageDoc(level="ERROR",
                 message="Invalid current role value: {role}",
-                explanation="An invalid HA role value was read from the " + 
+                explanation="An invalid HA role value was read from the " +
                             "properties file",
                 recommendation=LogMessageDoc.CHECK_CONTROLLER)
     })
     protected Role getInitialRole(Map<String, String> configParams) {
-        Role role = null;
+        Role role = Role.MASTER;
         String roleString = configParams.get("role");
         if (roleString == null) {
             String rolePath = configParams.get("rolepath");
@@ -1768,7 +1604,7 @@ public class Controller implements IFloodlightProviderService,
                 }
             }
         }
-        
+
         if (roleString != null) {
             // Canonicalize the string to the form used for the enum constants
             roleString = roleString.trim().toUpperCase();
@@ -1779,21 +1615,22 @@ public class Controller implements IFloodlightProviderService,
                 log.error("Invalid current role value: {}", roleString);
             }
         }
-        
+
         log.info("Controller role set to {}", role);
-        
+
         return role;
     }
-    
+
     /**
      * Tell controller that we're ready to accept switches loop
-     * @throws IOException 
+     * @throws IOException
      */
+    @Override
     @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 " + 
+        @LogMessageDoc(message="Storage exception in controller " +
                         "updates loop; terminating process",
                 explanation=ERROR_DATABASE,
                 recommendation=LogMessageDoc.CHECK_CONTROLLER),
@@ -1806,8 +1643,8 @@ public class Controller implements IFloodlightProviderService,
         if (log.isDebugEnabled()) {
             logListeners();
         }
-        
-        try {            
+
+        try {
            final ServerBootstrap bootstrap = createServerBootStrap();
 
             bootstrap.setOption("reuseAddr", true);
@@ -1815,13 +1652,13 @@ public class Controller implements IFloodlightProviderService,
             bootstrap.setOption("child.tcpNoDelay", true);
             bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
 
-            ChannelPipelineFactory pfact = 
+            ChannelPipelineFactory pfact =
                     new OpenflowPipelineFactory(this, null);
             bootstrap.setPipelineFactory(pfact);
             InetSocketAddress sa = new InetSocketAddress(openFlowPort);
             final ChannelGroup cg = new DefaultChannelGroup();
             cg.add(bootstrap.bind(sa));
-            
+
             log.info("Listening for switch connections on {}", sa);
         } catch (Exception e) {
             throw new RuntimeException(e);
@@ -1835,7 +1672,7 @@ public class Controller implements IFloodlightProviderService,
             } catch (InterruptedException e) {
                 return;
             } catch (StorageException e) {
-                log.error("Storage exception in controller " + 
+                log.error("Storage exception in controller " +
                           "updates loop; terminating process", e);
                 return;
             } catch (Exception e) {
@@ -1857,7 +1694,7 @@ public class Controller implements IFloodlightProviderService,
                             Executors.newCachedThreadPool(), workerThreads));
         }
     }
-    
+
     public void setConfigParams(Map<String, String> configParams) {
         String ofPort = configParams.get("openflowport");
         if (ofPort != null) {
@@ -1879,21 +1716,9 @@ public class Controller implements IFloodlightProviderService,
     private void initVendorMessages() {
         // Configure openflowj to be able to parse the role request/reply
         // vendor messages.
-        OFBasicVendorId niciraVendorId = new OFBasicVendorId(
-                OFNiciraVendorData.NX_VENDOR_ID, 4);
-        OFVendorId.registerVendorId(niciraVendorId);
-        OFBasicVendorDataType roleRequestVendorData =
-                new OFBasicVendorDataType(
-                        OFRoleRequestVendorData.NXT_ROLE_REQUEST,
-                        OFRoleRequestVendorData.getInstantiable());
-        niciraVendorId.registerVendorDataType(roleRequestVendorData);
-        OFBasicVendorDataType roleReplyVendorData =
-                new OFBasicVendorDataType(
-                        OFRoleReplyVendorData.NXT_ROLE_REPLY,
-                        OFRoleReplyVendorData.getInstantiable());
-         niciraVendorId.registerVendorDataType(roleReplyVendorData);
+        OFNiciraVendorExtensions.initialize();
     }
-    
+
     /**
      * Initialize internal data structures
      */
@@ -1901,8 +1726,8 @@ public class Controller implements IFloodlightProviderService,
         // These data structures are initialized here because other
         // module's startUp() might be called before ours
         this.messageListeners =
-                new ConcurrentHashMap<OFType, 
-                                      ListenerDispatcher<OFType, 
+                new ConcurrentHashMap<OFType,
+                                      ListenerDispatcher<OFType,
                                                          IOFMessageListener>>();
         this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
         this.haListeners = new CopyOnWriteArraySet<IHAListener>();
@@ -1917,11 +1742,11 @@ public class Controller implements IFloodlightProviderService,
         this.providerMap = new HashMap<String, List<IInfoProvider>>();
         setConfigParams(configParams);
         this.role = getInitialRole(configParams);
-        this.roleChanger = new RoleChanger();
+        this.roleChanger = new RoleChanger(this);
         initVendorMessages();
         this.systemStartTime = System.currentTimeMillis();
     }
-    
+
     /**
      * Startup all of the controller's components
      */
@@ -1938,7 +1763,7 @@ public class Controller implements IFloodlightProviderService,
         storageSource.setTablePrimaryKeyName(CONTROLLER_TABLE_NAME,
                                              CONTROLLER_ID);
         storageSource.addListener(CONTROLLER_INTERFACE_TABLE_NAME, this);
-        
+
         while (true) {
             try {
                 updateControllerInfo();
@@ -1952,7 +1777,7 @@ public class Controller implements IFloodlightProviderService,
                 }
             }
         }
-       
+
         // Startup load monitoring
         if (overload_drop) {
             this.loadmonitor.startMonitoring(
@@ -1977,18 +1802,19 @@ public class Controller implements IFloodlightProviderService,
             log.debug("Provider type {} doesn't exist.", type);
             return;
         }
-        
+
         providerMap.get(type).remove(provider);
     }
-    
+
+    @Override
     public Map<String, Object> getControllerInfo(String type) {
         if (!providerMap.containsKey(type)) return null;
-        
+
         Map<String, Object> result = new LinkedHashMap<String, Object>();
         for (IInfoProvider provider : providerMap.get(type)) {
             result.putAll(provider.getInfo(type));
         }
-        
+
         return result;
     }
 
@@ -2001,26 +1827,26 @@ public class Controller implements IFloodlightProviderService,
     public void removeHAListener(IHAListener listener) {
         this.haListeners.remove(listener);
     }
-    
-    
+
+
     /**
-     * Handle changes to the controller nodes IPs and dispatch update. 
+     * Handle changes to the controller nodes IPs and dispatch update.
      */
     @SuppressWarnings("unchecked")
     protected void handleControllerNodeIPChanges() {
         HashMap<String,String> curControllerNodeIPs = new HashMap<String,String>();
         HashMap<String,String> addedControllerNodeIPs = new HashMap<String,String>();
         HashMap<String,String> removedControllerNodeIPs =new HashMap<String,String>();
-        String[] colNames = { CONTROLLER_INTERFACE_CONTROLLER_ID, 
-                           CONTROLLER_INTERFACE_TYPE, 
-                           CONTROLLER_INTERFACE_NUMBER, 
+        String[] colNames = { CONTROLLER_INTERFACE_CONTROLLER_ID,
+                           CONTROLLER_INTERFACE_TYPE,
+                           CONTROLLER_INTERFACE_NUMBER,
                            CONTROLLER_INTERFACE_DISCOVERED_IP };
         synchronized(controllerNodeIPsCache) {
             // We currently assume that interface Ethernet0 is the relevant
             // controller interface. Might change.
-            // We could (should?) implement this using 
+            // We could (should?) implement this using
             // predicates, but creating the individual and compound predicate
-            // seems more overhead then just checking every row. Particularly, 
+            // seems more overhead then just checking every row. Particularly,
             // since the number of rows is small and changes infrequent
             IResultSet res = storageSource.executeQuery(CONTROLLER_INTERFACE_TABLE_NAME,
                     colNames,null, null);
@@ -2030,14 +1856,14 @@ public class Controller implements IFloodlightProviderService,
                     String controllerID = res.getString(CONTROLLER_INTERFACE_CONTROLLER_ID);
                     String discoveredIP = res.getString(CONTROLLER_INTERFACE_DISCOVERED_IP);
                     String curIP = controllerNodeIPsCache.get(controllerID);
-                    
+
                     curControllerNodeIPs.put(controllerID, discoveredIP);
                     if (curIP == null) {
                         // new controller node IP
                         addedControllerNodeIPs.put(controllerID, discoveredIP);
-                    } 
+                    }
                     else if (curIP != discoveredIP) {
-                        // IP changed                    
+                        // IP changed
                         removedControllerNodeIPs.put(controllerID, curIP);
                         addedControllerNodeIPs.put(controllerID, discoveredIP);
                     }
@@ -2064,7 +1890,7 @@ public class Controller implements IFloodlightProviderService,
             }
         }
     }
-    
+
     @Override
     public Map<String, String> getControllerNodeIPs() {
         // We return a copy of the mapping so we can guarantee that
@@ -2082,7 +1908,7 @@ public class Controller implements IFloodlightProviderService,
         if (tableName.equals(CONTROLLER_INTERFACE_TABLE_NAME)) {
             handleControllerNodeIPChanges();
         }
-        
+
     }
 
     @Override
@@ -2101,7 +1927,7 @@ public class Controller implements IFloodlightProviderService,
     public void setAlwaysClearFlowsOnSwAdd(boolean value) {
         this.alwaysClearFlowsOnSwAdd = value;
     }
-    
+
     public boolean getAlwaysClearFlowsOnSwAdd() {
         return this.alwaysClearFlowsOnSwAdd;
     }
@@ -2119,7 +1945,7 @@ public class Controller implements IFloodlightProviderService,
         // Sort so we match the longest string first
         int index = -1;
         for (String desc : switchDescSortedList) {
-            if (description.compareTo(desc) < 0) {
+            if (description.compareTo(desc) > 0) {
                 index = switchDescSortedList.indexOf(desc);
                 switchDescSortedList.add(index, description);
                 break;
diff --git a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchFeatures.java b/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchFeatures.java
deleted file mode 100644
index ddbb0ef37e45ee27f2b3a731483eb2676e9abb63..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/internal/IOFSwitchFeatures.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.floodlightcontroller.core.internal;
-
-import org.openflow.protocol.statistics.OFDescriptionStatistics;
-
-import net.floodlightcontroller.core.IOFSwitch;
-
-public interface IOFSwitchFeatures {
-    public void setFromDescription(IOFSwitch sw, OFDescriptionStatistics description);
-}
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java
index 9a1f071f849569afb930b02d2728699878c489f3..2d281bb9243288bdab9f61b69255a9057a7b344d 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelState.java
@@ -17,7 +17,11 @@
 
 package net.floodlightcontroller.core.internal;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.openflow.protocol.OFFeaturesReply;
+import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.statistics.OFDescriptionStatistics;
 
 /**
@@ -60,12 +64,5 @@ class OFChannelState {
     
     protected OFFeaturesReply featuresReply = null;
     protected OFDescriptionStatistics description = null;
-    
-    // The firstRoleReplyRecevied flag indicates if we have received the
-    // first role reply message on this connection (in response to the 
-    // role request sent after the handshake). If role support is disabled
-    // on the controller we also set this flag to true. 
-    // The flag is used to decide if the flow table should be wiped
-    // @see Controller.handleRoleReplyMessage()
-    protected boolean firstRoleReplyReceived = false;
+    protected List<OFMessage> queuedOFMessages = new ArrayList<OFMessage>();
 }
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
index 0909709c2c5460c51f20bd87a0246e760b655d3f..fd6339338ccee39470298b0253de7f4d18bf4311 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
@@ -17,850 +17,39 @@
 
 package net.floodlightcontroller.core.internal;
 
-import java.io.IOException;
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.IFloodlightProviderService;
-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;
 
 import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
-import org.codehaus.jackson.map.ser.ToStringSerializer;
-import org.jboss.netty.channel.Channel;
-import org.openflow.protocol.OFFeaturesReply;
-import org.openflow.protocol.OFFlowMod;
-import org.openflow.protocol.OFMatch;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.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;
 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;
+
+import net.floodlightcontroller.core.OFSwitchBase;
 
 /**
  * This is the internal representation of an openflow switch.
  */
-public class OFSwitchImpl implements IOFSwitch {
-    // TODO: should we really do logging in the class or should we throw
-    // exception that can then be handled by callers?
-    protected static Logger log = LoggerFactory.getLogger(OFSwitchImpl.class);
-
-    private static final String HA_CHECK_SWITCH = 
-            "Check the health of the indicated switch.  If the problem " +
-            "persists or occurs repeatedly, it likely indicates a defect " +
-            "in the switch HA implementation.";
-    
-    protected ConcurrentMap<Object, Object> attributes;
-    protected IFloodlightProviderService floodlightProvider;
-    protected IThreadPoolService threadPool;
-    protected Date connectedSince;
-    protected String stringId;
-    protected Channel channel;
-    protected AtomicInteger transactionIdSource;
-    // Lock to protect modification of the port maps. We only need to 
-    // synchronize on modifications. For read operations we are fine since
-    // we rely on ConcurrentMaps which works for our use case.
-    private Object portLock;
-    // Map port numbers to the appropriate OFPhysicalPort
-    protected ConcurrentHashMap<Short, OFPhysicalPort> portsByNumber;
-    // Map port names to the appropriate OFPhyiscalPort
-    // XXX: The OF spec doesn't specify if port names need to be unique but
-    //      according it's always the case in practice. 
-    protected ConcurrentHashMap<String, OFPhysicalPort> portsByName;
-    protected Map<Integer,OFStatisticsFuture> statsFutureMap;
-    protected Map<Integer, IOFMessageListener> iofMsgListenersMap;
-    protected Map<Integer,OFFeaturesReplyFuture> featuresFutureMap;
-    protected volatile boolean connected;
-    protected Role role;
-    protected TimedCache<Long> timedCache;
-    protected ReentrantReadWriteLock listenerLock;
-    protected ConcurrentMap<Short, Long> portBroadcastCacheHitMap;
-    /**
-     * When sending a role request message, the role request is added
-     * to this queue. If a role reply is received this queue is checked to 
-     * verify that the reply matches the expected reply. We require in order
-     * delivery of replies. That's why we use a Queue. 
-     * The RoleChanger uses a timeout to ensure we receive a timely reply.
-     * 
-     * Need to synchronize on this instance if a request is sent, received, 
-     * checked. 
-     */
-    protected LinkedList<PendingRoleRequestEntry> pendingRoleRequests;
-    
-    /* Switch features from initial featuresReply */
-    protected int capabilities;
-    protected int buffers;
-    protected int actions;
-    protected byte tables;
-    protected long datapathId;
-
-    public static IOFSwitchFeatures switchFeatures;
-    protected static final ThreadLocal<Map<IOFSwitch,List<OFMessage>>> local_msg_buffer =
-            new ThreadLocal<Map<IOFSwitch,List<OFMessage>>>() {
-        @Override
-        protected Map<IOFSwitch,List<OFMessage>> initialValue() {
-            return new HashMap<IOFSwitch,List<OFMessage>>();
-        }
-    };
-    
-    // for managing our map sizes
-    protected static final int MAX_MACS_PER_SWITCH  = 1000;
-    
-    protected static class PendingRoleRequestEntry {
-        protected int xid;
-        protected Role role;
-        // cookie is used to identify the role "generation". roleChanger uses
-        protected long cookie;
-        public PendingRoleRequestEntry(int xid, Role role, long cookie) {
-            this.xid = xid;
-            this.role = role;
-            this.cookie = cookie;
-        }
-    }
-    
-    public OFSwitchImpl() {
-        this.stringId = null;
-        this.attributes = new ConcurrentHashMap<Object, Object>();
-        this.connectedSince = new Date();
-        this.transactionIdSource = new AtomicInteger();
-        this.portLock = new Object();
-        this.portsByNumber = new ConcurrentHashMap<Short, OFPhysicalPort>();
-        this.portsByName = new ConcurrentHashMap<String, OFPhysicalPort>();
-        this.connected = true;
-        this.statsFutureMap = new ConcurrentHashMap<Integer,OFStatisticsFuture>();
-        this.featuresFutureMap = new ConcurrentHashMap<Integer,OFFeaturesReplyFuture>();
-        this.iofMsgListenersMap = new ConcurrentHashMap<Integer,IOFMessageListener>();
-        this.role = null;
-        this.timedCache = new TimedCache<Long>(100, 5*1000 );  // 5 seconds interval
-        this.listenerLock = new ReentrantReadWriteLock();
-        this.portBroadcastCacheHitMap = new ConcurrentHashMap<Short, Long>();
-        this.pendingRoleRequests = new LinkedList<OFSwitchImpl.PendingRoleRequestEntry>();
-        
-        // Defaults properties for an ideal switch
-        this.setAttribute(PROP_FASTWILDCARDS, OFMatch.OFPFW_ALL);
-        this.setAttribute(PROP_SUPPORTS_OFPP_FLOOD, new Boolean(true));
-        this.setAttribute(PROP_SUPPORTS_OFPP_TABLE, new Boolean(true));
-    }
-    
-
-    @Override
-    public Object getAttribute(String name) {
-        if (this.attributes.containsKey(name)) {
-            return this.attributes.get(name);
-        }
-        return null;
-    }
-    
-    @Override
-    public void setAttribute(String name, Object value) {
-        this.attributes.put(name, value);
-        return;
-    }
-
-    @Override
-    public Object removeAttribute(String name) {
-        return this.attributes.remove(name);
-    }
-    
-    @Override
-    public boolean hasAttribute(String name) {
-        return this.attributes.containsKey(name);
-    }
-        
-    @Override
-    @JsonIgnore
-    public Channel getChannel() {
-        return this.channel;
-    }
-
-    @JsonIgnore
-    public void setChannel(Channel channel) {
-        this.channel = channel;
-    }
-    
-    @Override
-    public void write(OFMessage m, FloodlightContext bc) throws IOException {
-        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
-        List<OFMessage> msg_buffer = msg_buffer_map.get(this);
-        if (msg_buffer == null) {
-            msg_buffer = new ArrayList<OFMessage>();
-            msg_buffer_map.put(this, msg_buffer);
-        }
-
-        this.floodlightProvider.handleOutgoingMessage(this, m, bc);
-        msg_buffer.add(m);
-
-        if ((msg_buffer.size() >= Controller.BATCH_MAX_SIZE) ||
-            ((m.getType() != OFType.PACKET_OUT) && (m.getType() != OFType.FLOW_MOD))) {
-            this.write(msg_buffer);
-            msg_buffer.clear();
-        }
-    }
-
-    @Override
-    @LogMessageDoc(level="WARN",
-                   message="Sending OF message that modifies switch " +
-                           "state while in the slave role: {switch}",
-                   explanation="An application has sent a message to a switch " +
-                   		"that is not valid when the switch is in a slave role",
-                   recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    public void write(List<OFMessage> msglist, 
-                      FloodlightContext bc) throws IOException {
-        for (OFMessage m : msglist) {
-            if (role == Role.SLAVE) {
-                switch (m.getType()) {
-                    case PACKET_OUT:
-                    case FLOW_MOD:
-                    case PORT_MOD:
-                        log.warn("Sending OF message that modifies switch " +
-                        		 "state while in the slave role: {}", 
-                        		 m.getType().name());
-                        break;
-                    default:
-                        break;
-                }
-            }
-            this.floodlightProvider.handleOutgoingMessage(this, m, bc);
-        }
-        this.write(msglist);
-    }
-
-    public void write(List<OFMessage> msglist) throws IOException {
-        this.channel.write(msglist);
-    }
-    
-    @Override
-    public void disconnectOutputStream() {
-        channel.close();
-    }
-
-    @Override
-    @JsonIgnore
-    public void setFeaturesReply(OFFeaturesReply featuresReply) {
-        synchronized(portLock) {
-            if (stringId == null) {
-                /* ports are updated via port status message, so we
-                 * only fill in ports on initial connection.
-                 */
-                for (OFPhysicalPort port : featuresReply.getPorts()) {
-                    setPort(port);
-                }
-            }
-            this.datapathId = featuresReply.getDatapathId();
-            this.capabilities = featuresReply.getCapabilities();
-            this.buffers = featuresReply.getBuffers();
-            this.actions = featuresReply.getActions();
-            this.tables = featuresReply.getTables();
-            this.stringId = HexString.toHexString(this.datapathId);
-        }
-    }
-
-    @Override
-    @JsonIgnore
-    public Collection<OFPhysicalPort> getEnabledPorts() {
-        List<OFPhysicalPort> result = new ArrayList<OFPhysicalPort>();
-        for (OFPhysicalPort port : portsByNumber.values()) {
-            if (portEnabled(port)) {
-                result.add(port);
-            }
-        }
-        return result;
-    }
-    
-    @Override
-    @JsonIgnore
-    public Collection<Short> getEnabledPortNumbers() {
-        List<Short> result = new ArrayList<Short>();
-        for (OFPhysicalPort port : portsByNumber.values()) {
-            if (portEnabled(port)) {
-                result.add(port.getPortNumber());
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public OFPhysicalPort getPort(short portNumber) {
-        return portsByNumber.get(portNumber);
-    }
-    
-    @Override
-    public OFPhysicalPort getPort(String portName) {
-        return portsByName.get(portName);
-    }
-
-    @Override
-    @JsonIgnore
-    public void setPort(OFPhysicalPort port) {
-        synchronized(portLock) {
-            portsByNumber.put(port.getPortNumber(), port);
-            portsByName.put(port.getName(), port);
-        }
-    }
-    
-    @Override
-    @JsonProperty("ports")
-    public Collection<OFPhysicalPort> getPorts() {
-        return Collections.unmodifiableCollection(portsByNumber.values());
-    }
-    
-    @Override
-    public void deletePort(short portNumber) {
-        synchronized(portLock) {
-            portsByName.remove(portsByNumber.get(portNumber).getName());
-            portsByNumber.remove(portNumber);
-        }
-    }
-    
-    @Override
-    public void deletePort(String portName) {
-        synchronized(portLock) {
-            portsByNumber.remove(portsByName.get(portName).getPortNumber());
-            portsByName.remove(portName);
-        }
-    }
-
-    @Override
-    public boolean portEnabled(short portNumber) {
-        if (portsByNumber.get(portNumber) == null) return false;
-        return portEnabled(portsByNumber.get(portNumber));
-    }
-    
-    @Override
-    public boolean portEnabled(String portName) {
-        if (portsByName.get(portName) == null) return false;
-        return portEnabled(portsByName.get(portName));
-    }
-    
-    @Override
-    public boolean portEnabled(OFPhysicalPort port) {
-        if (port == null)
-            return false;
-        if ((port.getConfig() & OFPortConfig.OFPPC_PORT_DOWN.getValue()) > 0)
-            return false;
-        if ((port.getState() & OFPortState.OFPPS_LINK_DOWN.getValue()) > 0)
-            return false;
-        // Port STP state doesn't work with multiple VLANs, so ignore it for now
-        //if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue())
-        //    return false;
-        return true;
-    }
-    
-    @Override
-    @JsonSerialize(using=DPIDSerializer.class)
-    @JsonProperty("dpid")
-    public long getId() {
-        if (this.stringId == null)
-            throw new RuntimeException("Features reply has not yet been set");
-        return this.datapathId;
-    }
-
-    @JsonIgnore
-    @Override
-    public String getStringId() {
-        return stringId;
-    }
-
-    /* (non-Javadoc)
-     * @see java.lang.Object#toString()
-     */
-    @Override
-    public String toString() {
-        return "OFSwitchImpl [" + channel.getRemoteAddress() + " DPID[" + ((stringId != null) ? stringId : "?") + "]]";
-    }
-
-    @Override
-    public ConcurrentMap<Object, Object> getAttributes() {
-        return this.attributes;
-    }
-
-    @Override
-    public Date getConnectedSince() {
-        return connectedSince;
-    }
-
-    @JsonIgnore
-    @Override
-    public int getNextTransactionId() {
-        return this.transactionIdSource.incrementAndGet();
-    }
-
-    @Override
-    public void sendStatsQuery(OFStatisticsRequest request, int xid,
-                                IOFMessageListener caller) throws IOException {
-        request.setXid(xid);
-        this.iofMsgListenersMap.put(xid, caller);
-        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-        msglist.add(request);
-        this.channel.write(msglist);
-        return;
-    }
-
-    @Override
-    public Future<List<OFStatistics>> getStatistics(OFStatisticsRequest request) throws IOException {
-        request.setXid(getNextTransactionId());
-        OFStatisticsFuture future = new OFStatisticsFuture(threadPool, this, request.getXid());
-        this.statsFutureMap.put(request.getXid(), future);
-        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-        msglist.add(request);
-        this.channel.write(msglist);
-        return future;
-    }
-
-    @Override
-    public void deliverStatisticsReply(OFMessage reply) {
-        OFStatisticsFuture future = this.statsFutureMap.get(reply.getXid());
-        if (future != null) {
-            future.deliverFuture(this, reply);
-            // The future will ultimately unregister itself and call
-            // cancelStatisticsReply
-            return;
-        }
-        /* Transaction id was not found in statsFutureMap.check the other map */
-        IOFMessageListener caller = this.iofMsgListenersMap.get(reply.getXid());
-        if (caller != null) {
-            caller.receive(this, reply, null);
-        }
-    }
-
-    @Override
-    public void cancelStatisticsReply(int transactionId) {
-        if (null ==  this.statsFutureMap.remove(transactionId)) {
-            this.iofMsgListenersMap.remove(transactionId);
-        }
-    }
-
-    @Override
-    public void cancelAllStatisticsReplies() {
-        /* we don't need to be synchronized here. Even if another thread
-         * modifies the map while we're cleaning up the future will eventuall
-         * timeout */
-        for (OFStatisticsFuture f : statsFutureMap.values()) {
-            f.cancel(true);
-        }
-        statsFutureMap.clear();
-        iofMsgListenersMap.clear();
-    }
- 
-    
-    /**
-     * @param floodlightProvider the floodlightProvider to set
-     */
-    @JsonIgnore
-    public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) {
-        this.floodlightProvider = floodlightProvider;
-    }
-    
-    @JsonIgnore
-    public void setThreadPoolService(IThreadPoolService tp) {
-        this.threadPool = tp;
-    }
-
-    @JsonIgnore
-    @Override
-    public boolean isConnected() {
-        // No lock needed since we use volatile
-        return connected;
-    }
-
-    @Override
-    @JsonIgnore
-    public void setConnected(boolean connected) {
-        // No lock needed since we use volatile
-        this.connected = connected;
-    }
-    
-    @Override
-    public Role getRole() {
-        return role;
-    }
-    
-    @JsonIgnore
-    @Override
-    public boolean isActive() {
-        return (role != Role.SLAVE);
-    }
+public class OFSwitchImpl extends OFSwitchBase {
     
     @Override
     @JsonIgnore
     public void setSwitchProperties(OFDescriptionStatistics description) {
-        if (switchFeatures != null) {
-            switchFeatures.setFromDescription(this, description);
-        }
-    }
-
-    @Override
-    @LogMessageDoc(level="ERROR",
-                   message="Failed to clear all flows on switch {switch}",
-                   explanation="An I/O error occured while trying to clear " +
-                   		"flows on the switch.",
-                   recommendation=LogMessageDoc.CHECK_SWITCH)
-    public void clearAllFlowMods() {
-        // Delete all pre-existing flows
-        OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
-        OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory()
-            .getMessage(OFType.FLOW_MOD))
-                .setMatch(match)
-            .setCommand(OFFlowMod.OFPFC_DELETE)
-            .setOutPort(OFPort.OFPP_NONE)
-            .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
-        try {
-            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-            msglist.add(fm);
-            channel.write(msglist);
-        } catch (Exception e) {
-            log.error("Failed to clear all flows on switch " + this, e);
-        }
-    }
-
-    @Override
-    public boolean updateBroadcastCache(Long entry, Short port) {
-        if (timedCache.update(entry)) {
-            Long count = portBroadcastCacheHitMap.putIfAbsent(port, new Long(1));
-            if (count != null) {
-                count++;
-            }
-            return true;
-        } else {
-            return false;
-        }
+        // Nothing to do at the moment
     }
 
     @Override
-    @JsonIgnore
-    public Map<Short, Long> getPortBroadcastHits() {
-    	return this.portBroadcastCacheHitMap;
+    public OFPortType getPortType(short port_num) {
+        return OFPortType.NORMAL;
     }
-    
 
     @Override
-    public void flush() {
-        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
-        List<OFMessage> msglist = msg_buffer_map.get(this);
-        if ((msglist != null) && (msglist.size() > 0)) {
-            try {
-                this.write(msglist);
-            } catch (IOException e) {
-                // TODO: log exception
-                e.printStackTrace();
-            }
-            msglist.clear();
-        }
-    }
-
-    public static void flush_all() {
-        Map<IOFSwitch,List<OFMessage>> msg_buffer_map = local_msg_buffer.get();
-        for (IOFSwitch sw : msg_buffer_map.keySet()) {
-            sw.flush();
-        }
-    }
-
-    /**
-     * Return a read lock that must be held while calling the listeners for
-     * messages from the switch. Holding the read lock prevents the active
-     * switch list from being modified out from under the listeners.
-     * @return 
-     */
-    @JsonIgnore
-    public Lock getListenerReadLock() {
-        return listenerLock.readLock();
-    }
-
-    /**
-     * Return a write lock that must be held when the controllers modifies the
-     * list of active switches. This is to ensure that the active switch list
-     * doesn't change out from under the listeners as they are handling a
-     * message from the switch.
-     * @return
-     */
     @JsonIgnore
-    public Lock getListenerWriteLock() {
-        return listenerLock.writeLock();
-    }
-
-    /**
-     * Get the IP Address for the switch
-     * @return the inet address
-     */
-    @JsonSerialize(using=ToStringSerializer.class)
-    public SocketAddress getInetAddress() {
-        return channel.getRemoteAddress();
-    }
-    
-    /**
-     * Send NX role request message to the switch requesting the specified role.
-     * 
-     * This method should ONLY be called by @see RoleChanger.submitRequest(). 
-     * 
-     * After sending the request add it to the queue of pending request. We
-     * use the queue to later verify that we indeed receive the correct reply.
-     * @param sw switch to send the role request message to
-     * @param role role to request
-     * @param cookie an opaque value that will be stored in the pending queue so
-     *        RoleChanger can check for timeouts.
-     * @return transaction id of the role request message that was sent
-     */
-    public int sendNxRoleRequest(Role role, long cookie)
-            throws IOException {
-        synchronized(pendingRoleRequests) {
-            // Convert the role enum to the appropriate integer constant used
-            // in the NX role request message
-            int nxRole = 0;
-            switch (role) {
-                case EQUAL:
-                    nxRole = OFRoleVendorData.NX_ROLE_OTHER;
-                    break;
-                case MASTER:
-                    nxRole = OFRoleVendorData.NX_ROLE_MASTER;
-                    break;
-                case SLAVE:
-                    nxRole = OFRoleVendorData.NX_ROLE_SLAVE;
-                    break;
-                default:
-                    log.error("Invalid Role specified for switch {}."
-                              + " Disconnecting.", this);
-                    // TODO: should throw an error
-                    return 0;
-            }
-            
-            // Construct the role request message
-            OFVendor roleRequest = (OFVendor)floodlightProvider.
-                    getOFMessageFactory().getMessage(OFType.VENDOR);
-            int xid = this.getNextTransactionId();
-            roleRequest.setXid(xid);
-            roleRequest.setVendor(OFNiciraVendorData.NX_VENDOR_ID);
-            OFRoleRequestVendorData roleRequestData = new OFRoleRequestVendorData();
-            roleRequestData.setRole(nxRole);
-            roleRequest.setVendorData(roleRequestData);
-            roleRequest.setLengthU(OFVendor.MINIMUM_LENGTH + 
-                                   roleRequestData.getLength());
-            
-            // Send it to the switch
-            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-            msglist.add(roleRequest);
-            // FIXME: should this use this.write() in order for messages to
-            // be processed by handleOutgoingMessage()
-            this.channel.write(msglist);
-            
-            pendingRoleRequests.add(new PendingRoleRequestEntry(xid, role, cookie));
-            return xid;
-        }
-    }
-    
-    /** 
-     * Deliver a RoleReply message to this switch. Checks if the reply 
-     * message matches the expected reply (head of the pending request queue). 
-     * We require in-order delivery of replies. If there's any deviation from
-     * our expectations we disconnect the switch. 
-     * 
-     * 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;
-        }
-    }
-    
-    /**
-     * 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();
-            }
-        }
-    }
-
-    @Override
-    public Future<OFFeaturesReply> querySwitchFeaturesReply()
-            throws IOException {
-        OFMessage request = 
-                floodlightProvider.getOFMessageFactory().
-                    getMessage(OFType.FEATURES_REQUEST);
-        request.setXid(getNextTransactionId());
-        OFFeaturesReplyFuture future =
-                new OFFeaturesReplyFuture(threadPool, this, request.getXid());
-        this.featuresFutureMap.put(request.getXid(), future);
-        List<OFMessage> msglist = new ArrayList<OFMessage>(1);
-        msglist.add(request);
-        this.channel.write(msglist);
-        return future;
-    }
-
-    @Override
-    public void deliverOFFeaturesReply(OFMessage reply) {
-        OFFeaturesReplyFuture future = this.featuresFutureMap.get(reply.getXid());
-        if (future != null) {
-            future.deliverFuture(this, reply);
-            // The future will ultimately unregister itself and call
-            // cancelFeaturesReply
-            return;
-        }
-        log.error("Switch {}: received unexpected featureReply", this);
-    }
-
-    @Override
-    public void cancelFeaturesReply(int transactionId) {
-        this.featuresFutureMap.remove(transactionId);
-    }
-
-
-    @Override
-    public int getBuffers() {
-        return buffers;
-    }
-
-
-    @Override
-    public int getActions() {
-        return actions;
-    }
-
-
-    @Override
-    public int getCapabilities() {
-        return capabilities;
+    public boolean isFastPort(short port_num) {
+        return false;
     }
 
-
     @Override
-    public byte getTables() {
-        return tables;
+    public List<Short> getUplinkPorts() {
+        return null;
     }
 
-
-    @Override
-    public void setFloodlightProvider(Controller controller) {
-        floodlightProvider = controller;
-    }
+     
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
index 008e54232cfbe0bf2dd47e20f3690b11d57ad42e..f9ec793b3ba9797ec06912dc5579772fccd15fb1 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
@@ -4,16 +4,29 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.DelayQueue;
 import java.util.concurrent.Delayed;
 import java.util.concurrent.TimeUnit;
 
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.OFVendor;
+import org.openflow.vendor.nicira.OFNiciraVendorData;
+import org.openflow.vendor.nicira.OFRoleReplyVendorData;
+import org.openflow.vendor.nicira.OFRoleRequestVendorData;
+import org.openflow.vendor.nicira.OFRoleVendorData;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import net.floodlightcontroller.core.FloodlightContext;
 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.
@@ -67,22 +80,19 @@ import net.floodlightcontroller.core.annotations.LogMessageDoc;
  *   OFSwitchImpl's queue of pending requests)
  * - We handle requests and timeouts in the same thread. We use a priority queue
  *   to schedule them so we are guaranteed that they are processed in 
- *   the same order as they are submitted. If a request times out we drop
- *   the connection to this switch. 
+ *   the same order as they are submitted. If a request times out we assume
+ *   the switch doesn't support HA role (the same as receiving an error reply). 
  * - Since we decouple submission of role change requests and actually sending
  *   them we cannot check a received role reply against the controller's current 
  *   role because the controller's current role could have changed again. 
- * - Receiving Role Reply messages is handled by OFChannelHandler and
- *   OFSwitchImpl directly. The OFSwitchImpl checks if the received request 
- *   is as expected (xid and role match the head of the pending queue in 
- *   OFSwitchImpl). If so
- *   the switch updates its role. Otherwise the connection is dropped. If this
- *   is the first reply, the SWITCH_SUPPORTS_NX_ROLE attribute is set.
- *   Next, we call addSwitch(), removeSwitch() to update the list of active
- *   switches if appropriate.
+ * - Receiving Role Reply messages is received by OFChannelHandler and
+ *   delivered here. We call switch's setHARole() to mark the switch role and
+ *   indicate that a reply was received. Next, we call addSwitch(),
+ *   removeSwitch() to update the list of active switches if appropriate.
  * - If we receive an Error indicating that roles are not supported by the 
- *   switch, we set the SWITCH_SUPPORTS_NX_ROLE to false. We keep the 
- *   switch connection alive while in MASTER and EQUAL role. 
+ *   switch, we set the SWITCH_SUPPORTS_NX_ROLE to false. We call switch's
+ *   setHARole(), indicating no reply was received. We keep the switch
+ *   connection alive while in MASTER and EQUAL role. 
  *   (TODO: is this the right behavior for EQUAL??). If the role changes to
  *   SLAVE the switch connection is dropped (remember: only if the switch
  *   doesn't support role requests)  
@@ -94,13 +104,10 @@ import net.floodlightcontroller.core.annotations.LogMessageDoc;
  * New switch connection:
  * - Switch handshake is done without sending any role request messages.
  * - After handshake completes, switch is added to the list of connected switches
- *   and we send the first role request message if role
- *   requests are enabled. If roles are disabled automatically promote switch to
- *   active switch list and clear FlowTable.
+ *   and we send the first role request message. If role is disabled, we assume
+ *   the role is MASTER.
  * - When we receive the first reply we proceed as above. In addition, if
- *   the role request is for MASTER we wipe the flow table. We do not wipe
- *   the flow table if the switch connected while role supported was disabled
- *   on the controller. 
+ *   the role request is for MASTER we wipe the flow table. 
  *
  */
 public class RoleChanger {
@@ -119,8 +126,13 @@ public class RoleChanger {
     protected long lastSubmitTime;
     protected Thread workerThread;
     protected long timeout;
-    protected static long DEFAULT_TIMEOUT = 15L*1000*1000*1000L; // 15s
+    protected ConcurrentHashMap<IOFSwitch, LinkedList<PendingRoleRequestEntry>>
+                pendingRequestMap;
+    private Controller controller;
+    
+    protected static long DEFAULT_TIMEOUT = 5L*1000*1000*1000L; // 5s
     protected static Logger log = LoggerFactory.getLogger(RoleChanger.class);
+    
     /** 
      * A queued task to be handled by the Role changer thread. 
      */
@@ -156,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 " +
@@ -170,17 +198,25 @@ public class RoleChanger {
             try {
                 while (true) {
                     try {
-                        t = pendingTasks.take();
+                        t = pendingTasks.poll();
+                        if (t == null) {
+                            // Notify when there is no immediate tasks to run
+                            // For the convenience of RoleChanger unit tests
+                            synchronized (pendingTasks) {
+                                pendingTasks.notifyAll();
+                            }
+                            t = pendingTasks.take();
+                        }
                     } catch (InterruptedException e) {
                         // see http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html
                         interrupted = true;
                         continue;
                     }
                     if (t.type == RoleChangeTask.Type.REQUEST) {
+                        t.deadline += timeout;
                         sendRoleRequest(t.switches, t.role, t.deadline);
                         // Queue the timeout
                         t.type = RoleChangeTask.Type.TIMEOUT;
-                        t.deadline += timeout;
                         pendingTasks.put(t);
                     }
                     else {
@@ -201,7 +237,16 @@ public class RoleChanger {
         } // end loop
     }
     
-    public RoleChanger() {
+    protected class HARoleUnsupportedException extends Exception {
+        
+        private static final long serialVersionUID = -6854500893864114158L;
+        
+    }
+
+    public RoleChanger(Controller controller) {
+        this.controller = controller;
+        this.pendingRequestMap = new ConcurrentHashMap<IOFSwitch,
+                LinkedList<PendingRoleRequestEntry>>();
         this.pendingTasks = new DelayQueue<RoleChangeTask>();
         this.workerThread = new Thread(new RoleRequestWorker());
         this.timeout = DEFAULT_TIMEOUT;
@@ -223,12 +268,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",
@@ -239,60 +282,42 @@ 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 {
-                Boolean supportsNxRole = (Boolean)
-                        sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
-                if ((supportsNxRole == null) || supportsNxRole) {
-                    // Handle cases #1 and #2
-                    sw.sendNxRoleRequest(role, cookie);
-                } else {
-                    // Handle case #3
-                    if (role == Role.SLAVE) {
-                        log.debug("Disconnecting switch {} that doesn't support " +
-                        "role request messages from a controller that went to SLAVE mode");
-                        // Closing the channel should result in a call to
-                        // channelDisconnect which updates all state 
-                        sw.getChannel().close();
-                        iter.remove();
-                    }
+                LinkedList<PendingRoleRequestEntry> pendingList
+                    = pendingRequestMap.get(sw);
+                if (pendingList == null) {
+                    pendingList = new LinkedList<PendingRoleRequestEntry>();
+                    pendingRequestMap.put(sw, pendingList);
+                }
+                int xid = sendHARoleRequest(sw, role, cookie);
+                PendingRoleRequestEntry entry =
+                        new PendingRoleRequestEntry(xid, role, cookie);
+                // 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",
                          sw, e);
-                sw.getChannel().close();
+                sw.disconnectOutputStream();
                 iter.remove();
+            } catch (HARoleUnsupportedException e) {
+                // 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");
+                    // Closing the channel should result in a call to
+                    // channelDisconnect which updates all state 
+                    sw.disconnectOutputStream();
+                    iter.remove();
+                } else {
+                    sw.setHARole(role, false);
+                    controller.addSwitch(sw, true);
+                }
             }
         }
     }
@@ -311,11 +336,388 @@ public class RoleChanger {
     protected void verifyRoleReplyReceived(Collection<IOFSwitch> switches,
                                    long cookie) {
         for (IOFSwitch sw: switches) {
-            if (sw.checkFirstPendingRoleRequestCookie(cookie)) {
-                sw.getChannel().close();
-                log.warn("Timeout while waiting for role reply from switch {}."
-                         + " Disconnecting", sw);
+            PendingRoleRequestEntry entry =
+                    checkFirstPendingRoleRequestCookie(sw, cookie);
+            if (entry != null){
+                log.warn("Timeout while waiting for role reply from switch {}"
+                         + " with datapath {}", sw,
+                         sw.getAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA));
+                setSwitchHARole(sw, entry.role, false);
+            }
+        }
+    }
+    
+    /** 
+     * 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.
+     * 
+     * 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=LogMessageDoc.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=LogMessageDoc.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=LogMessageDoc.HA_CHECK_SWITCH)                           
+    })
+    
+    protected void deliverRoleReply(IOFSwitch sw, int xid, Role role) {
+        LinkedList<PendingRoleRequestEntry> pendingRoleRequests =
+                pendingRequestMap.get(sw);
+        if (pendingRoleRequests == null) {
+            log.debug("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);
+                setSwitchHARole(sw, 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. If so, return the entry
+     * @param cookie
+     * @return
+     */
+    protected PendingRoleRequestEntry checkFirstPendingRoleRequestCookie(
+            IOFSwitch sw, long cookie)
+    {
+        LinkedList<PendingRoleRequestEntry> pendingRoleRequests =
+                pendingRequestMap.get(sw);
+        if (pendingRoleRequests == null) {
+            return null;
+        }
+        synchronized(pendingRoleRequests) {
+            PendingRoleRequestEntry head = pendingRoleRequests.peek();
+            if (head == null)
+                return null;
+            if (head.cookie == cookie) {
+                return pendingRoleRequests.poll();
             }
         }
+        return null;
+    }
+    
+    /**
+     * 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
+     */
+    private 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) {
+                setSwitchHARole(sw, head.role, false);
+            }
+        }
+    }
+    
+    /**
+     * Send NX role request message to the switch requesting the specified role.
+     * 
+     * @param sw switch to send the role request message to
+     * @param role role to request
+     * @param cookie an opaque value that will be stored in the pending queue so
+     *        RoleChanger can check for timeouts.
+     * @return transaction id of the role request message that was sent
+     */
+    protected int sendHARoleRequest(IOFSwitch sw, 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)
+                sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
+        if ((supportsNxRole != null) && !supportsNxRole) {
+            throw new HARoleUnsupportedException();
+        }
+
+        int xid = sw.getNextTransactionId();
+        // 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);
+            throw new HARoleUnsupportedException();
+        }
+
+        // Construct the role request message
+        OFVendor roleRequest = (OFVendor)controller.
+                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());
+
+        return xid;
+    }
+    
+    /* Handle a role reply message we received from the switch. Since
+     * netty serializes message dispatch we don't need to synchronize 
+     * against other receive operations from the same switch, so no need
+     * to synchronize addSwitch(), removeSwitch() operations from the same
+     * connection. 
+     * FIXME: However, when a switch with the same DPID connects we do
+     * need some synchronization. However, handling switches with same
+     * DPID needs to be revisited anyways (get rid of r/w-lock and synchronous
+     * removedSwitch notification):1
+     * 
+     */
+    @LogMessageDoc(level="ERROR",
+            message="Invalid role value in role reply message",
+            explanation="Was unable to set the HA role (master or slave) " +
+                    "for the controller.",
+            recommendation=LogMessageDoc.CHECK_CONTROLLER)
+    protected void handleRoleReplyMessage(IOFSwitch sw, OFVendor vendorMessage,
+                                OFRoleReplyVendorData roleReplyVendorData) {
+        // Map from the role code in the message to our role enum
+        int nxRole = roleReplyVendorData.getRole();
+        Role role = null;
+        switch (nxRole) {
+            case OFRoleVendorData.NX_ROLE_OTHER:
+                role = Role.EQUAL;
+                break;
+            case OFRoleVendorData.NX_ROLE_MASTER:
+                role = Role.MASTER;
+                break;
+            case OFRoleVendorData.NX_ROLE_SLAVE:
+                role = Role.SLAVE;
+                break;
+            default:
+                log.error("Invalid role value in role reply message");
+                sw.disconnectOutputStream();
+                return;
+        }
+        
+        log.debug("Handling role reply for role {} from {}. " +
+                  "Controller's role is {} ", 
+                  new Object[] { role, sw, controller.role} 
+                  );
+        
+        deliverRoleReply(sw, vendorMessage.getXid(), role);
+    }
+
+    @LogMessageDocs({
+        @LogMessageDoc(level="ERROR",
+            message="Received ERROR from sw {switch} that indicates roles " +
+                    "are not supported but we have received a valid role " +
+                    "reply earlier",
+            explanation="Switch is responding to HA role request in an " +
+                        "inconsistent manner.",
+            recommendation=LogMessageDoc.CHECK_SWITCH),
+        @LogMessageDoc(level="ERROR",
+            message="Unexpected error {error} from switch {switch} " +
+                    "disconnecting",
+            explanation="Swith sent an error reply to request, but the error " +
+                        "type is not OPET_BAD_REQUEST as required by the protocol",
+            recommendation=LogMessageDoc.CHECK_SWITCH)
+    })
+    protected void deliverRoleRequestError(IOFSwitch sw, OFError error) {
+        // We expect to receive a bad request error when
+        // we're connected to a switch that doesn't support
+        // the Nicira vendor extensions (i.e. not OVS or
+        // derived from OVS).  By protocol, it should also be
+        // BAD_VENDOR, but too many switch implementations
+        // get it wrong and we can already check the xid()
+        // so we can ignore the type with confidence that this
+        // is not a spurious error
+        boolean isBadRequestError =
+                (error.getErrorType() == OFError.OFErrorType.
+                OFPET_BAD_REQUEST.getValue());
+        if (isBadRequestError) {
+            if (sw.getHARole() != null) {
+                log.warn("Received ERROR from sw {} that "
+                        +"indicates roles are not supported "
+                        +"but we have received a valid "
+                        +"role reply earlier", sw);
+            }
+            // First, clean up pending requests
+            deliverRoleRequestNotSupported(sw, error.getXid());
+        } else {
+            // TODO: Is this the right thing to do if we receive
+            // some other error besides a bad request error?
+            // Presumably that means the switch did actually
+            // understand the role request message, but there
+            // was some other error from processing the message.
+            // OF 1.2 specifies a OFPET_ROLE_REQUEST_FAILED
+            // error code, but it doesn't look like the Nicira
+            // role request has that. Should check OVS source
+            // code to see if it's possible for any other errors
+            // to be returned.
+            // If we received an error the switch is not
+            // in the correct role, so we need to disconnect it.
+            // We could also resend the request but then we need to
+            // check if there are other pending request in which
+            // case we shouldn't resend. If we do resend we need
+            // to make sure that the switch eventually accepts one
+            // of our requests or disconnect the switch. This feels
+            // cumbersome.
+            log.error("Unexpected error {} from switch {}, disconnecting",
+                    error, sw);
+            sw.disconnectOutputStream();
+        }
+    }
+
+    /**
+     * Set switch's HA role and adjust switch's list membership
+     * based on the new role and switch's HA capability. This is
+     * a synchronized method to keep role handling consistent.
+     * @param sw
+     * @param role
+     * @param replyReceived
+     */
+    private synchronized void setSwitchHARole(IOFSwitch sw, Role role,
+            boolean replyReceived) {
+        // Record previous role and set the current role
+        // We tell switch whether a correct reply was received.
+        // The switch may deduce if HA role request is supported
+        // (if it doesn't already know).
+        Role oldRole = sw.getHARole();
+        sw.setHARole(role,  replyReceived);
+        
+        // Adjust the active switch list based on the role
+        if (role != Role.SLAVE) {
+            // SLAVE->MASTER, need to add switch to active list.
+            // If this is the initial connection, clear flodmods.
+            boolean clearFlowMods = (oldRole == null) ||
+                    controller.getAlwaysClearFlowsOnSwAdd();
+            controller.addSwitch(sw, clearFlowMods);
+        } else {
+            // Initial SLAVE setting. Nothing to do if role reply received.
+            // Else disconnect the switch.
+            if (oldRole == null && !replyReceived) {
+                sw.disconnectOutputStream();
+            } else {
+                // MASTER->SLAVE transition. If switch supports HA roles,
+                // remove it from active list, but still leave it connected.
+                // Otherwise, disconnect it. Cleanup happens after channel
+                // handler receives the disconnect notification.
+                if (replyReceived) {
+                    controller.removeSwitch(sw);
+                } else {
+                    sw.disconnectOutputStream();
+                }
+            }
+        }
+    }
+
+    /**
+     * Cleanup pending requests associated witch switch. Called when
+     * switch disconnects.
+     * @param sw
+     */
+    public void removePendingRequests(IOFSwitch sw) {
+        pendingRequestMap.remove(sw);
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
index 0d73f93f12130c1df48fc995b1ccd50ad53ef82e..cf7c6ad43bf64e71ccb93824cf691471cdbd3426 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
@@ -29,18 +29,18 @@ public class SwitchRoleResource extends ServerResource {
         if (switchId.equalsIgnoreCase("all")) {
             HashMap<String,RoleInfo> model = new HashMap<String,RoleInfo>();
             for (IOFSwitch sw: floodlightProvider.getSwitches().values()) {
-            	switchId = sw.getStringId();
-            	roleInfo = new RoleInfo(sw.getRole());
-            	model.put(switchId, roleInfo);
+                switchId = sw.getStringId();
+                roleInfo = new RoleInfo(sw.getHARole());
+                model.put(switchId, roleInfo);
             }
             return model;
         }
         
-    	Long dpid = HexString.toLong(switchId);
-    	IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
-    	if (sw == null)
-    		return null;
-    	roleInfo = new RoleInfo(sw.getRole());
-    	return roleInfo;
+        Long dpid = HexString.toLong(switchId);
+        IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
+        if (sw == null)
+            return null;
+        roleInfo = new RoleInfo(sw.getHARole());
+        return roleInfo;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
index 645125e20f0797b4235fbb6a48a7fd191bf8e497..19cc0271bc38381ea4ff769e1f4a16200669f80a 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
@@ -60,6 +60,10 @@ public class Device implements IDevice {
     protected IEntityClass entityClass;
 
     protected String macAddressString;
+    // the vlan Ids from the entities of this device
+    protected Short[] vlanIds;
+    
+   
 
     /**
      * These are the old attachment points for the device that were
@@ -110,6 +114,7 @@ entity.getLastSeenTimestamp().getTime());
                 this.attachmentPoints.add(ap);
             }
         }
+        computeVlandIds();
     }
 
     /**
@@ -142,23 +147,53 @@ entity.getLastSeenTimestamp().getTime());
                 HexString.toHexString(this.entities[0].getMacAddress(), 6);
         this.entityClass = entityClass;
         Arrays.sort(this.entities);
+        computeVlandIds();
     }
 
     /**
      * Construct a new device consisting of the entities from the old device
-     * plus an additional entity
+     * plus an additional entity.
+     * The caller needs to ensure that the additional entity is not already 
+     * present in the array
      * @param device the old device object
      * @param newEntity the entity to add. newEntity must be have the same
      *        entity class as device
+     * @param if positive indicates the index in the entities array were the
+     *        new entity should be inserted. If negative we will compute the
+     *        correct insertion point
      */
     public Device(Device device,
-                  Entity newEntity) {
+                  Entity newEntity,
+                  int insertionpoint) {
         this.deviceManager = device.deviceManager;
         this.deviceKey = device.deviceKey;
+        
+        this.entities = new Entity[device.entities.length + 1];
+        if (insertionpoint < 0) {
+            insertionpoint = -(Arrays.binarySearch(device.entities, 
+                                                   newEntity)+1);
+        }
+        if (insertionpoint > 0) {
+            // insertion point is not the beginning:
+            // copy up to insertion point
+            System.arraycopy(device.entities, 0, 
+                             this.entities, 0,
+                             insertionpoint);
+        }
+        if (insertionpoint < device.entities.length) {
+            // insertion point is not the end 
+            // copy from insertion point
+            System.arraycopy(device.entities, insertionpoint, 
+                             this.entities, insertionpoint+1,
+                             device.entities.length-insertionpoint);
+        }
+        this.entities[insertionpoint] = newEntity;
+        /*
         this.entities = Arrays.<Entity>copyOf(device.entities,
                                               device.entities.length + 1);
         this.entities[this.entities.length - 1] = newEntity;
         Arrays.sort(this.entities);
+        */
         this.oldAPs = null;
         if (device.oldAPs != null) {
             this.oldAPs =
@@ -174,8 +209,29 @@ entity.getLastSeenTimestamp().getTime());
                 HexString.toHexString(this.entities[0].getMacAddress(), 6);
 
         this.entityClass = device.entityClass;
+        computeVlandIds();
+    }
+    
+    private void computeVlandIds() {
+        if (entities.length == 1) {
+            if (entities[0].getVlan() != null) {
+                vlanIds = new Short[]{ entities[0].getVlan() };
+            } else {
+                vlanIds = new Short[] { Short.valueOf((short)-1) };
+            }
+        }
+
+        TreeSet<Short> vals = new TreeSet<Short>();
+        for (Entity e : entities) {
+            if (e.getVlan() == null)
+                vals.add((short)-1);
+            else
+                vals.add(e.getVlan());
+        }
+        vlanIds = vals.toArray(new Short[vals.size()]);
     }
 
+
     /**
      * Given a list of attachment points (apList), the procedure would return
      * a map of attachment points for each L2 domain.  L2 domain id is the key.
@@ -566,22 +622,7 @@ entity.getLastSeenTimestamp().getTime());
 
     @Override
     public Short[] getVlanId() {
-        if (entities.length == 1) {
-            if (entities[0].getVlan() != null) {
-                return new Short[]{ entities[0].getVlan() };
-            } else {
-                return new Short[] { Short.valueOf((short)-1) };
-            }
-        }
-
-        TreeSet<Short> vals = new TreeSet<Short>();
-        for (Entity e : entities) {
-            if (e.getVlan() == null)
-                vals.add((short)-1);
-            else
-                vals.add(e.getVlan());
-        }
-        return vals.toArray(new Short[vals.size()]);
+        return Arrays.copyOf(vlanIds, vlanIds.length);
     }
 
     static final EnumSet<DeviceField> ipv4Fields = EnumSet.of(DeviceField.IPV4);
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
index 9f836b1c8c6d7b162d693da0dfc8093dbd3fd82c..f59d67c986c8a56982ea1448590c61a3ad0be859 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
@@ -1052,7 +1052,8 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                 entityClass = entityClassifier.classifyEntity(entity);
                 if (entityClass == null) {
                     // could not classify entity. No device
-                    return null;
+                    device = null;
+                    break;
                 }
                 ClassState classState = getClassState(entityClass);
 
@@ -1066,17 +1067,36 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                 // use resulting device key to look up the device in the
                 // device map, and use the referenced Device below.
                 device = deviceMap.get(deviceKey);
-                if (device == null)
-                    throw new IllegalStateException("Corrupted device index");
+                if (device == null) {
+                    // This can happen due to concurrent modification 
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("No device for deviceKey {} while "
+                                     + "while processing entity {}",
+                                     deviceKey, entity);
+                    }
+                }
             } else {
                 // If the secondary index does not contain the entity,
                 // create a new Device object containing the entity, and
-                // generate a new device ID. However, we first check if 
+                // generate a new device ID if the the entity is on an 
+                // attachment point port. Otherwise ignore. 
+                if (entity.hasSwitchPort() &&
+                        !topology.isAttachmentPointPort(entity.getSwitchDPID(), 
+                                                 entity.getSwitchPort().shortValue())) {
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("Not learning new device on internal"
+                                     + " link: {}", entity);
+                    }
+                    device = null;
+                    break;
+                }
+                // Before we create the new device also check if 
                 // the entity is allowed (e.g., for spoofing protection)
                 if (!isEntityAllowed(entity, entityClass)) {
                     logger.info("PacketIn is not allowed {} {}", 
                                 entityClass.getName(), entity);
-                    return null;
+                    device = null;
+                    break;
                 }
                 synchronized (deviceKeyLock) {
                     deviceKey = Long.valueOf(deviceKeyCounter++);
@@ -1113,56 +1133,36 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                             device.getEntityClass().getName(), entity);
                 return null;
             }
+            // If this is an internal port we don't learn the new entity
+            // and don't update indexes. We only learn on attachment point
+            // ports.
+            if (entity.hasSwitchPort() &&
+                    !topology.isAttachmentPointPort(entity.getSwitchDPID(), 
+                                                 entity.getSwitchPort().shortValue())) {
+                break;
+            }
             int entityindex = -1;
             if ((entityindex = device.entityIndex(entity)) >= 0) {
+                // Entity already exists 
                 // update timestamp on the found entity
                 Date lastSeen = entity.getLastSeenTimestamp();
-                if (lastSeen == null) lastSeen = new Date();
-                device.entities[entityindex].setLastSeenTimestamp(lastSeen);
-                if (device.entities[entityindex].getSwitchDPID() != null &&
-                        device.entities[entityindex].getSwitchPort() != null) {
-                    long sw = device.entities[entityindex].getSwitchDPID();
-                    short port = device.entities[entityindex].getSwitchPort().shortValue();
-
-                    boolean moved =
-                            device.updateAttachmentPoint(sw,
-                                                         port,
-                                                         lastSeen.getTime());
-
-                    if (moved) {
-                        sendDeviceMovedNotification(device);
-                        if (logger.isTraceEnabled()) {
-                            logger.trace("Device moved: attachment points {}," +
-                                    "entities {}", device.attachmentPoints,
-                                    device.entities);
-                        }
-                    } else {
-                        if (logger.isTraceEnabled()) {
-                            logger.trace("Device attachment point NOT updated: " +
-                                         "attachment points {}," +
-                                         "entities {}", device.attachmentPoints,
-                                         device.entities);
-                        }
-                    }
+                if (lastSeen == null) {
+                    lastSeen = new Date();
+                    entity.setLastSeenTimestamp(lastSeen);
                 }
-                break;
+                device.entities[entityindex].setLastSeenTimestamp(lastSeen);
+                // we break the loop after the else block and after checking
+                // for new AP
             } else {
-                boolean moved = false;
-                Device newDevice = allocateDevice(device, entity);
-                if (entity.getSwitchDPID() != null && entity.getSwitchPort() != null) {
-                    moved = newDevice.updateAttachmentPoint(entity.getSwitchDPID(),
-                                                            entity.getSwitchPort().shortValue(),
-                                                            entity.getLastSeenTimestamp().getTime());
-                }
-
+                // New entity for this devce
+                // compute the insertion point for the entity.
+                // see Arrays.binarySearch()
+                entityindex = -(entityindex + 1);
+                Device newDevice = allocateDevice(device, entity, entityindex);
+ 
                 // generate updates
                 EnumSet<DeviceField> changedFields =
                         findChangedFields(device, entity);
-                if (changedFields.size() > 0)
-                    deviceUpdates =
-                    updateUpdates(deviceUpdates,
-                                  new DeviceUpdate(newDevice, CHANGE,
-                                                   changedFields));
 
                 // update the device map with a replace call
                 boolean res = deviceMap.replace(deviceKey, device, newDevice);
@@ -1173,7 +1173,6 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                     continue;
 
                 device = newDevice;
-
                 // update indices
                 if (!updateIndices(device, deviceKey)) {
                     continue;
@@ -1181,36 +1180,45 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                 updateSecondaryIndices(entity,
                                        device.getEntityClass(),
                                        deviceKey);
-
+                
+                if (changedFields.size() > 0) {
+                    deviceUpdates =
+                    updateUpdates(deviceUpdates,
+                                  new DeviceUpdate(newDevice, CHANGE,
+                                                   changedFields));
+                }
+                // we break the loop after checking for changed AP 
+            }
+            // Update attachment point (will only be hit if the device 
+            // already existed and no concurrent modification
+            if (entity.hasSwitchPort()) {
+                boolean moved = 
+                        device.updateAttachmentPoint(entity.getSwitchDPID(),
+                                entity.getSwitchPort().shortValue(),
+                                entity.getLastSeenTimestamp().getTime());
                 if (moved) {
                     sendDeviceMovedNotification(device);
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("Device moved: attachment points {}," +
+                    if (logger.isTraceEnabled()) {
+                        logger.trace("Device moved: attachment points {}," +
                                 "entities {}", device.attachmentPoints,
                                 device.entities);
                     }
                 } else {
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("Device attachment point updated: " +
+                    if (logger.isTraceEnabled()) {
+                        logger.trace("Device attachment point updated: " +
                                      "attachment points {}," +
                                      "entities {}", device.attachmentPoints,
                                      device.entities);
                     }
                 }
-                break;
             }
+            break; 
         }
 
         if (deleteQueue != null) {
             for (Long l : deleteQueue) {
                 Device dev = deviceMap.get(l);
                 this.deleteDevice(dev);
-                
-
-                // generate new device update
-                deviceUpdates =
-                        updateUpdates(deviceUpdates,
-                                      new DeviceUpdate(dev, DELETE, null));
             }
         }
 
@@ -1479,9 +1487,9 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                     for (Entity e : toRemove) {
                         changedFields.addAll(findChangedFields(newDevice, e));
                     }
+                    DeviceUpdate update = null;
                     if (changedFields.size() > 0)
-                        deviceUpdates.add(new DeviceUpdate(d, CHANGE,
-                                                           changedFields));
+                        update = new DeviceUpdate(d, CHANGE, changedFields);
 
                     if (!deviceMap.replace(newDevice.getDeviceKey(),
                                            d,
@@ -1493,15 +1501,19 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                         if (null != d)
                             continue;
                     }
+                    if (update != null)
+                        deviceUpdates.add(update);
                 } else {
-                    deviceUpdates.add(new DeviceUpdate(d, DELETE, null));
-                    if (!deviceMap.remove(d.getDeviceKey(), d))
+                    DeviceUpdate update = new DeviceUpdate(d, DELETE, null);
+                    if (!deviceMap.remove(d.getDeviceKey(), d)) {
                         // concurrent modification; try again
                         // need to use device that is the map now for the next
                         // iteration
                         d = deviceMap.get(d.getDeviceKey());
                         if (null != d)
                             continue;
+                    }
+                    deviceUpdates.add(update);
                 }
                 processUpdates(deviceUpdates);
                 break;
@@ -1591,8 +1603,9 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
     }
 
     protected Device allocateDevice(Device device,
-                                    Entity entity) {
-        return new Device(device, entity);
+                                    Entity entity,
+                                    int insertionpoint) {
+        return new Device(device, entity, insertionpoint);
     }
     
     protected Device allocateDevice(Device device, Set <Entity> entities) {
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
index 36c5471fb7fb037b7c917a75c0f32e1875a8f638..5949a19e22d40542b83eef1660478a4655f8cce8 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
@@ -24,6 +24,7 @@ import net.floodlightcontroller.core.web.serializers.MACSerializer;
 import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
 import net.floodlightcontroller.packet.IPv4;
 
+import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 import org.openflow.util.HexString;
 
@@ -145,6 +146,11 @@ public class Entity implements Comparable<Entity> {
     public Integer getSwitchPort() {
         return switchPort;
     }
+    
+    @JsonIgnore
+    public boolean hasSwitchPort() {
+        return (switchDPID != null && switchPort != null);
+    }
 
     public Date getLastSeenTimestamp() {
         return lastSeenTimestamp;
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index 45e02915901cb759c3dd6b76efb439e4e14e344d..7fde1cd72d66c592da299908097df4936ca4d57e 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -304,10 +304,6 @@ IFloodlightModule, IInfoProvider, IHAListener {
         return shuttingDown;
     }
 
-    public boolean isFastPort(long sw, short port) {
-        return false;
-    }
-
     public boolean isTunnelPort(long sw, short port) {
         return false;
     }
@@ -567,7 +563,7 @@ IFloodlightModule, IInfoProvider, IHAListener {
         }
 
         // For fast ports, do not send forward LLDPs or BDDPs.
-        if (!isReverse && autoPortFastFeature && isFastPort(sw, port))
+        if (!isReverse && autoPortFastFeature && iofSwitch.isFastPort(port))
             return;
 
         if (log.isTraceEnabled()) {
@@ -692,7 +688,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
                 for (OFPhysicalPort ofp: iofSwitch.getEnabledPorts()) {
                     if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber()))
                         continue;
-                    if (autoPortFastFeature && isFastPort(sw, ofp.getPortNumber()))
+                    if (autoPortFastFeature &&
+                            iofSwitch.isFastPort(ofp.getPortNumber()))
                         continue;
 
                     // sends forward LLDP only non-fastports.
@@ -1326,21 +1323,23 @@ IFloodlightModule, IInfoProvider, IHAListener {
     private void processNewPort(long sw, short p) {
         if (isLinkDiscoverySuppressed(sw, p)) {
             // Do nothing as link discovery is suppressed.
+            return;
         }
-        else if (autoPortFastFeature && isFastPort(sw, p)) {
+
+        IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
+        if (autoPortFastFeature && iofSwitch.isFastPort(p)) {
             // Do nothing as the port is a fast port.
+            return;
         }
-        else {
-            NodePortTuple npt = new NodePortTuple(sw, p);
-            discover(sw, p);
-            // if it is not a fast port, add it to quarantine.
-            if (!isFastPort(sw, p)) {
-                addToQuarantineQueue(npt);
-            } else {
-                // Add to maintenance queue to ensure that BDDP packets
-                // are sent out.
-                addToMaintenanceQueue(npt);
-            }
+        NodePortTuple npt = new NodePortTuple(sw, p);
+        discover(sw, p);
+        // if it is not a fast port, add it to quarantine.
+        if (!iofSwitch.isFastPort(p)) {
+            addToQuarantineQueue(npt);
+        } else {
+            // Add to maintenance queue to ensure that BDDP packets
+            // are sent out.
+            addToMaintenanceQueue(npt);
         }
     }
 
@@ -2000,15 +1999,12 @@ IFloodlightModule, IInfoProvider, IHAListener {
             evTopoSwitch = new EventHistoryTopologySwitch();
         }
         evTopoSwitch.dpid     = sw.getId();
-        if ((sw.getChannel() != null) &&
-                (SocketAddress.class.isInstance(
-                                                sw.getChannel().getRemoteAddress()))) {
-            evTopoSwitch.ipv4Addr = 
-                    IPv4.toIPv4Address(((InetSocketAddress)(sw.getChannel().
-                            getRemoteAddress())).getAddress().getAddress());
+        if ((SocketAddress.class.isInstance(sw.getInetAddress()))) {
+            evTopoSwitch.ipv4Addr = IPv4.toIPv4Address(
+                    ((InetSocketAddress)(sw.getInetAddress()))
+                    .getAddress().getAddress());
             evTopoSwitch.l4Port   =
-                    ((InetSocketAddress)(sw.getChannel().
-                            getRemoteAddress())).getPort();
+                    ((InetSocketAddress)(sw.getInetAddress())).getPort();
         } else {
             evTopoSwitch.ipv4Addr = 0;
             evTopoSwitch.l4Port = 0;
diff --git a/src/main/java/org/openflow/protocol/OFMatch.java b/src/main/java/org/openflow/protocol/OFMatch.java
index 0336d7dbdc0b681ff5e97f4720320221837e193f..391610b0c4bf4cdd9f68d1dd705ba1fc2093ce54 100644
--- a/src/main/java/org/openflow/protocol/OFMatch.java
+++ b/src/main/java/org/openflow/protocol/OFMatch.java
@@ -1,7 +1,7 @@
 /**
 *    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
 *    University
-* 
+*
 *    Licensed under the Apache License, Version 2.0 (the "License"); you may
 *    not use this file except in compliance with the License. You may obtain
 *    a copy of the License at
@@ -21,7 +21,6 @@ import java.io.Serializable;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 
-
 import org.codehaus.jackson.map.annotate.JsonSerialize;
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.openflow.protocol.serializers.OFMatchJSONSerializer;
@@ -29,17 +28,19 @@ import org.openflow.util.HexString;
 import org.openflow.util.U16;
 import org.openflow.util.U8;
 
+
 /**
  * Represents an ofp_match structure
- * 
+ *
  * @author David Erickson (daviderickson@cs.stanford.edu)
  * @author Rob Sherwood (rob.sherwood@stanford.edu)
- * 
+ *
  */
 @JsonSerialize(using=OFMatchJSONSerializer.class)
 public class OFMatch implements Cloneable, Serializable {
+
     /**
-     * 
+     *
      */
     private static final long serialVersionUID = 1L;
     public static int MINIMUM_LENGTH = 40;
@@ -80,6 +81,10 @@ public class OFMatch implements Cloneable, Serializable {
                                                      * bits).
                                                      */
 
+    final public static int OFPFW_ALL_SANITIZED =
+            (((1 << 22) - 1) & ~OFPFW_NW_SRC_MASK & ~OFPFW_NW_DST_MASK)
+                    | OFPFW_NW_SRC_ALL | OFPFW_NW_DST_ALL;
+
     /* List of Strings for marshalling and unmarshalling to human readable forms */
     final public static String STR_IN_PORT = "in_port";
     final public static String STR_DL_DST = "dl_dst";
@@ -110,7 +115,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * By default, create a OFMatch that matches everything
-     * 
+     *
      * (mostly because it's the least amount of work to make a valid OFMatch)
      */
     public OFMatch() {
@@ -131,7 +136,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get dl_dst
-     * 
+     *
      * @return an arrays of bytes
      */
     public byte[] getDataLayerDestination() {
@@ -140,7 +145,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set dl_dst
-     * 
+     *
      * @param dataLayerDestination
      */
     public OFMatch setDataLayerDestination(byte[] dataLayerDestination) {
@@ -150,7 +155,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set dl_dst, but first translate to byte[] using HexString
-     * 
+     *
      * @param mac
      *            A colon separated string of 6 pairs of octets, e..g.,
      *            "00:17:42:EF:CD:8D"
@@ -166,7 +171,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get dl_src
-     * 
+     *
      * @return an array of bytes
      */
     public byte[] getDataLayerSource() {
@@ -175,7 +180,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set dl_src
-     * 
+     *
      * @param dataLayerSource
      */
     public OFMatch setDataLayerSource(byte[] dataLayerSource) {
@@ -185,7 +190,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set dl_src, but first translate to byte[] using HexString
-     * 
+     *
      * @param mac
      *            A colon separated string of 6 pairs of octets, e..g.,
      *            "00:17:42:EF:CD:8D"
@@ -201,7 +206,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get dl_type
-     * 
+     *
      * @return ether_type
      */
     public short getDataLayerType() {
@@ -210,7 +215,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set dl_type
-     * 
+     *
      * @param dataLayerType
      */
     public OFMatch setDataLayerType(short dataLayerType) {
@@ -220,7 +225,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get dl_vlan
-     * 
+     *
      * @return vlan tag; VLAN_NONE == no tag
      */
     public short getDataLayerVirtualLan() {
@@ -229,7 +234,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set dl_vlan
-     * 
+     *
      * @param dataLayerVirtualLan
      */
     public OFMatch setDataLayerVirtualLan(short dataLayerVirtualLan) {
@@ -239,7 +244,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get dl_vlan_pcp
-     * 
+     *
      * @return
      */
     public byte getDataLayerVirtualLanPriorityCodePoint() {
@@ -248,7 +253,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set dl_vlan_pcp
-     * 
+     *
      * @param pcp
      */
     public OFMatch setDataLayerVirtualLanPriorityCodePoint(byte pcp) {
@@ -258,7 +263,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get in_port
-     * 
+     *
      * @return
      */
     public short getInputPort() {
@@ -267,7 +272,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set in_port
-     * 
+     *
      * @param inputPort
      */
     public OFMatch setInputPort(short inputPort) {
@@ -277,7 +282,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get nw_dst
-     * 
+     *
      * @return
      */
     public int getNetworkDestination() {
@@ -286,7 +291,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set nw_dst
-     * 
+     *
      * @param networkDestination
      */
     public OFMatch setNetworkDestination(int networkDestination) {
@@ -297,10 +302,10 @@ public class OFMatch implements Cloneable, Serializable {
     /**
      * Parse this match's wildcard fields and return the number of significant
      * bits in the IP destination field.
-     * 
+     *
      * NOTE: this returns the number of bits that are fixed, i.e., like CIDR,
      * not the number of bits that are free like OpenFlow encodes.
-     * 
+     *
      * @return a number between 0 (matches all IPs) and 63 ( 32>= implies exact
      *         match)
      */
@@ -313,10 +318,10 @@ public class OFMatch implements Cloneable, Serializable {
     /**
      * Parse this match's wildcard fields and return the number of significant
      * bits in the IP destination field.
-     * 
+     *
      * NOTE: this returns the number of bits that are fixed, i.e., like CIDR,
      * not the number of bits that are free like OpenFlow encodes.
-     * 
+     *
      * @return a number between 0 (matches all IPs) and 32 (exact match)
      */
     public int getNetworkSourceMaskLen() {
@@ -327,7 +332,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get nw_proto
-     * 
+     *
      * @return
      */
     public byte getNetworkProtocol() {
@@ -336,7 +341,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set nw_proto
-     * 
+     *
      * @param networkProtocol
      */
     public OFMatch setNetworkProtocol(byte networkProtocol) {
@@ -346,7 +351,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get nw_src
-     * 
+     *
      * @return
      */
     public int getNetworkSource() {
@@ -355,7 +360,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set nw_src
-     * 
+     *
      * @param networkSource
      */
     public OFMatch setNetworkSource(int networkSource) {
@@ -367,7 +372,7 @@ public class OFMatch implements Cloneable, Serializable {
      * Get nw_tos
      * OFMatch stores the ToS bits as top 6-bits, so right shift by 2 bits
      * before returning the value
-     * 
+     *
      * @return : 6-bit DSCP value (0-63)
      */
     public byte getNetworkTypeOfService() {
@@ -378,18 +383,18 @@ public class OFMatch implements Cloneable, Serializable {
      * Set nw_tos
      * OFMatch stores the ToS bits as top 6-bits, so left shift by 2 bits
      * before storing the value
-     * 
+     *
      * @param networkTypeOfService : 6-bit DSCP value (0-63)
      */
     public OFMatch setNetworkTypeOfService(byte networkTypeOfService) {
         this.networkTypeOfService = (byte)(networkTypeOfService << 2);
         return this;
     }
-    
+
 
     /**
      * Get tp_dst
-     * 
+     *
      * @return
      */
     public short getTransportDestination() {
@@ -398,7 +403,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set tp_dst
-     * 
+     *
      * @param transportDestination
      */
     public OFMatch setTransportDestination(short transportDestination) {
@@ -408,7 +413,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get tp_src
-     * 
+     *
      * @return
      */
     public short getTransportSource() {
@@ -417,7 +422,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Set tp_src
-     * 
+     *
      * @param transportSource
      */
     public OFMatch setTransportSource(short transportSource) {
@@ -427,16 +432,25 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Get wildcards
-     * 
+     *
      * @return
      */
     public int getWildcards() {
         return this.wildcards;
     }
 
+    /**
+     * Get wildcards
+     *
+     * @return
+     */
+    public Wildcards getWildcardObj() {
+        return Wildcards.of(wildcards);
+    }
+
     /**
      * Set wildcards
-     * 
+     *
      * @param wildcards
      */
     public OFMatch setWildcards(int wildcards) {
@@ -444,16 +458,22 @@ public class OFMatch implements Cloneable, Serializable {
         return this;
     }
 
+    /** set the wildcard using the Wildcards convenience object */
+    public OFMatch setWildcards(Wildcards wildcards) {
+        this.wildcards = wildcards.getInt();
+        return this;
+    }
+
     /**
      * Initializes this OFMatch structure with the corresponding data from the
      * specified packet.
-     * 
+     *
      * Must specify the input port, to ensure that this.in_port is set
      * correctly.
-     * 
+     *
      * Specify OFPort.NONE or OFPort.ANY if input port not applicable or
      * available
-     * 
+     *
      * @param packetData
      *            The packet's data
      * @param inputPort
@@ -573,7 +593,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Read this message off the wire from the specified ByteBuffer
-     * 
+     *
      * @param data
      */
     public void readFrom(ChannelBuffer data) {
@@ -599,7 +619,7 @@ public class OFMatch implements Cloneable, Serializable {
 
     /**
      * Write this message's binary format to the specified ByteBuffer
-     * 
+     *
      * @param data
      */
     public void writeTo(ChannelBuffer data) {
@@ -718,10 +738,10 @@ public class OFMatch implements Cloneable, Serializable {
     /**
      * Output a dpctl-styled string, i.e., only list the elements that are not
      * wildcarded
-     * 
+     *
      * A match-everything OFMatch outputs "OFMatch[]"
-     * 
-     * @return 
+     *
+     * @return
      *         "OFMatch[dl_src:00:20:01:11:22:33,nw_src:192.168.0.0/24,tp_dst:80]"
      */
     @Override
@@ -778,6 +798,56 @@ public class OFMatch implements Cloneable, Serializable {
         return "OFMatch[" + str + "]";
     }
 
+    /**
+     * debug a set of wildcards
+     */
+    public static String debugWildCards(int wildcards) {
+        String str = "";
+
+        // l1
+        if ((wildcards & OFPFW_IN_PORT) != 0)
+            str += "|" + STR_IN_PORT;
+
+        // l2
+        if ((wildcards & OFPFW_DL_DST) != 0)
+            str += "|" + STR_DL_DST;
+        if ((wildcards & OFPFW_DL_SRC) != 0)
+            str += "|" + STR_DL_SRC;
+        if ((wildcards & OFPFW_DL_TYPE) != 0)
+            str += "|" + STR_DL_TYPE;
+        if ((wildcards & OFPFW_DL_VLAN) != 0)
+            str += "|" + STR_DL_VLAN;
+        if ((wildcards & OFPFW_DL_VLAN_PCP) != 0)
+            str += "|" + STR_DL_VLAN_PCP;
+
+        int nwDstMask = Math.max(32 - ((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT),
+                            0);
+        int nwSrcMask = Math.max(32 - ((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT),
+                0);
+
+        // l3
+        if (nwDstMask < 32)
+            str += "|" + STR_NW_DST + "(/" +nwDstMask + ")";
+
+        if (nwSrcMask < 32)
+            str += "|" + STR_NW_SRC + "(/" + nwSrcMask + ")";
+
+        if ((wildcards & OFPFW_NW_PROTO) != 0)
+            str += "|" + STR_NW_PROTO;
+        if ((wildcards & OFPFW_NW_TOS) != 0)
+            str += "|" + STR_NW_TOS;
+
+        // l4
+        if ((wildcards & OFPFW_TP_DST) != 0)
+            str += "|" + STR_TP_DST;
+        if ((wildcards & OFPFW_TP_SRC) != 0)
+            str += "|" + STR_TP_SRC;
+        if ((str.length() > 0) && (str.charAt(0) == '|'))
+            str = str.substring(1); // trim the leading ","
+        // done
+        return str;
+    }
+
     private String cidrToString(int ip, int prefix) {
         String str;
         if (prefix >= 32) {
@@ -826,7 +896,7 @@ public class OFMatch implements Cloneable, Serializable {
      * <p>
      * The CIDR-style netmasks assume 32 netmask if none given, so:
      * "128.8.128.118/32" is the same as "128.8.128.118"
-     * 
+     *
      * @param match
      *            a key=value comma separated string, e.g.
      *            "in_port=5,ip_dst=192.168.0.0/16,tp_src=80"
@@ -904,7 +974,7 @@ public class OFMatch implements Cloneable, Serializable {
     /**
      * Set the networkSource or networkDestionation address and their wildcards
      * from the CIDR string
-     * 
+     *
      * @param cidr
      *            "192.168.0.0/16" or "172.16.1.5"
      * @param which
diff --git a/src/main/java/org/openflow/protocol/OFMessage.java b/src/main/java/org/openflow/protocol/OFMessage.java
index 7ea69a7ef921334a5bce1bd18ac53b28ed1d6384..38f4e477317e79682416b2145985bd4fa3948f5f 100644
--- a/src/main/java/org/openflow/protocol/OFMessage.java
+++ b/src/main/java/org/openflow/protocol/OFMessage.java
@@ -41,6 +41,7 @@ import org.openflow.util.U8;
  * @author Rob Sherwood (rob.sherwood@stanford.edu) - Feb 3, 2010
  */
 public class OFMessage {
+    public static final int MAXIMUM_LENGTH = (1 << 16) - 1;
     public static byte OFP_VERSION = 0x01;
     public static int MINIMUM_LENGTH = 8;
 
@@ -48,14 +49,14 @@ public class OFMessage {
     protected OFType type;
     protected short length;
     protected int xid;
-    
+
     private ConcurrentHashMap<String, Object> storage;
-    
+
     public OFMessage() {
         storage = null;
         this.version = OFP_VERSION;
     }
-    
+
     protected synchronized ConcurrentHashMap<String, Object> getMessageStore() {
         if (storage == null) {
             storage = new ConcurrentHashMap<String, Object>();;
@@ -181,6 +182,7 @@ public class OFMessage {
      * Returns a summary of the message
      * @return "ofmsg=v=$version;t=$type:l=$len:xid=$xid"
      */
+    @Override
     public String toString() {
         return "ofmsg" +
             ":v=" + U8.f(this.getVersion()) +
@@ -230,7 +232,7 @@ public class OFMessage {
         }
         return true;
     }
-    
+
     public static String getDataAsString(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
 
         Ethernet eth;
diff --git a/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java b/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java
index 124a4013aaf3437db18041da630781d95bb3c9a6..9b3a6ca608aee1b37498e1b53f623ab28cb1aa10 100644
--- a/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java
+++ b/src/main/java/org/openflow/protocol/OFStatisticsMessageBase.java
@@ -41,7 +41,7 @@ public abstract class OFStatisticsMessageBase extends OFMessage implements
 
     // TODO: this should be List<? extends OFStatistics>, to
     // allow for type safe assignments of lists of specific message
-    protected List<OFStatistics> statistics;
+    protected List<? extends OFStatistics> statistics;
 
     /**
      * @return the statisticType
@@ -74,7 +74,7 @@ public abstract class OFStatisticsMessageBase extends OFMessage implements
     /**
      * @return the statistics
      */
-    public List<OFStatistics> getStatistics() {
+    public List<? extends OFStatistics> getStatistics() {
         return statistics;
     }
 
@@ -84,7 +84,7 @@ public abstract class OFStatisticsMessageBase extends OFMessage implements
      * flow stats request, port statsrequest)
      *
      * @return the first and only element in the list of statistics
-     * @throw NoSuchElementException if the list does not contain exactly one
+     * @throw IllegalArgumentException if the list does not contain exactly one
      *        element
      */
     public OFStatistics getFirstStatistics() {
@@ -98,7 +98,7 @@ public abstract class OFStatisticsMessageBase extends OFMessage implements
     /**
      * @param statistics the statistics to set
      */
-    public void setStatistics(List<OFStatistics> statistics) {
+    public void setStatistics(List<? extends OFStatistics> statistics) {
         this.statistics = statistics;
     }
 
diff --git a/src/main/java/org/openflow/protocol/Wildcards.java b/src/main/java/org/openflow/protocol/Wildcards.java
new file mode 100644
index 0000000000000000000000000000000000000000..f982e5ace6f7165c91ff265ef5b78b8e2d50da91
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/Wildcards.java
@@ -0,0 +1,587 @@
+package org.openflow.protocol;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.common.base.Joiner;
+
+/**
+ * a more user friendly representation of the wildcards bits in an OpenFlow
+ * match. The Wildcards object is
+ * <ul>
+ * <li>immutable (i.e., threadsafe)</li>
+ * <li>instance managed (don't instantiate it yourself), instead call "of"</li>
+ * <ul>
+ * <p>
+ * You can construct a Wildcard object from either its integer representation
+ * </p>
+ * <code>
+ *    Wildcard.of(0x3820e0);
+ *  </code>
+ * <p>
+ * Or start with either an empty or full wildcard, and select/unselect foo.
+ * </p>
+ * <code>
+ *  Wildcard w = Wildcards.NONE
+ *                .set(Flag.DL_SRC, Flag. DL_DST, Flag.DL_VLAN_PCP)
+ *                .setNwDstMask(8)
+ *                .setNwSrcMask(8);
+ *  </code>
+ * <p>
+ * <b>Remember:</b> Wildcards objects are immutable. set... operations have
+ * <b>NO EFFECT</b> on the current wildcard object. You HAVE to use the returned
+ * changed object.
+ * </p>
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class Wildcards {
+
+    public final static Wildcards FULL = new Wildcards(OFMatch.OFPFW_ALL_SANITIZED);
+    private static final int FULL_INT = FULL.getInt();
+
+    public final static Wildcards EXACT = new Wildcards(0);
+
+    // floodlight common case: matches on inport + l2
+    public final static int INT_INPORT_L2_MATCH = 0x3820e0;
+    public final static Wildcards INPORT_L2_MATCH = new Wildcards(
+            INT_INPORT_L2_MATCH);
+
+    /**
+     * enum type for the binary flags that can be set in the wildcards field of
+     * an OFMatch. Replaces the unwieldy c-ish int constants in OFMatch.
+     */
+    public static enum Flag {
+        IN_PORT(OFMatch.OFPFW_IN_PORT),  /* Switch input port. */
+        DL_VLAN(OFMatch.OFPFW_DL_VLAN), /* VLAN id. */
+        DL_SRC(OFMatch.OFPFW_DL_SRC), /* Ethernet source address. */
+        DL_DST(OFMatch.OFPFW_DL_DST), /* Ethernet destination addr */
+        DL_TYPE(OFMatch.OFPFW_DL_TYPE), /* Ethernet frame type. */
+        NW_PROTO(OFMatch.OFPFW_NW_PROTO), /* IP protocol. */
+        TP_SRC(OFMatch.OFPFW_TP_SRC), /* TCP/UDP source port. */
+        TP_DST(OFMatch.OFPFW_TP_DST), /* TCP/UDP destination port. */
+        DL_VLAN_PCP(OFMatch.OFPFW_DL_VLAN_PCP), /* VLAN priority. */
+        NW_SRC(-1) { /*
+                      * virtual NW_SRC flag => translates to the strange 6 bits
+                      * in the header
+                      */
+            @Override
+            boolean isBolean() {
+                return false;
+            }
+
+            @Override
+            int getInt(int flags) {
+                return ((flags & OFMatch.OFPFW_NW_SRC_MASK) >> OFMatch.OFPFW_NW_SRC_SHIFT);
+            }
+
+            @Override
+            int setInt(int flags, int srcMask) {
+                return (flags & ~OFMatch.OFPFW_NW_SRC_MASK) | (srcMask << OFMatch.OFPFW_NW_SRC_SHIFT);
+            }
+
+            @Override
+            int wildcard(int flags) {
+                return flags & ~OFMatch.OFPFW_NW_SRC_MASK;
+            }
+
+            @Override
+            int matchOn(int flags) {
+                return flags | OFMatch.OFPFW_NW_SRC_ALL;
+            }
+
+            @Override
+            boolean isPartiallyOn(int flags) {
+                int intValue = getInt(flags);
+                return intValue > 0 && intValue < 32;
+            }
+
+            @Override
+            boolean isFullyOn(int flags) {
+                return getInt(flags) >= 32;
+            }
+
+        },
+        NW_DST(-1) { /*
+                      * virtual NW_SRC flag => translates to the strange 6 bits
+                      * in the header
+                      */
+            @Override
+            boolean isBolean() {
+                return false;
+            }
+
+            @Override
+            int getInt(int flags) {
+                return ((flags & OFMatch.OFPFW_NW_DST_MASK) >> OFMatch.OFPFW_NW_DST_SHIFT);
+            }
+
+            @Override
+            int setInt(int flags, int srcMask) {
+                return (flags & ~OFMatch.OFPFW_NW_DST_MASK) | (srcMask << OFMatch.OFPFW_NW_DST_SHIFT);
+            }
+
+            @Override
+            int wildcard(int flags) {
+                return flags & ~OFMatch.OFPFW_NW_DST_MASK;
+            }
+
+            @Override
+            int matchOn(int flags) {
+                return flags | OFMatch.OFPFW_NW_DST_ALL;
+            }
+
+            @Override
+            boolean isFullyOn(int flags) {
+                return getInt(flags) >= 32;
+            }
+        },
+        NW_TOS(OFMatch.OFPFW_NW_TOS); /* IP ToS (DSCP field, 6 bits). */
+
+        final int bitPosition;
+
+        Flag(int bitPosition) {
+            this.bitPosition = bitPosition;
+        }
+
+        /**
+         * @return a modified OF-1.0 flags field with this flag cleared (match
+         *         on this field)
+         */
+        int matchOn(int flags) {
+            return flags & ~this.bitPosition;
+        }
+
+        /**
+         * @return a modified OF-1.0 flags field with this flag set (wildcard
+         *         this field)
+         */
+        int wildcard(int flags) {
+            return flags | this.bitPosition;
+        }
+
+        /**
+         * @return true iff this is a true boolean flag that can either be off
+         *         or on.True in OF-1.0 for all fields except NW_SRC and NW_DST
+         */
+        boolean isBolean() {
+            return false;
+        }
+
+        /**
+         * @return true iff this wildcard field is currently 'partially on'.
+         *         Always false for true Boolean Flags. Can be true in OF-1.0
+         *         for NW_SRC, NW_DST.
+         */
+        boolean isPartiallyOn(int flags) {
+            return false;
+        }
+
+        /**
+         * @return true iff this wildcard field currently fully on (fully
+         *         wildcarded). Equivalent to the boolean flag being set in the
+         *         bitmask for bit flags, and to the wildcarded bit length set
+         *         to >=32 for NW_SRC and NW_DST
+         * @param flags
+         * @return
+         */
+        boolean isFullyOn(int flags) {
+            return (flags & this.bitPosition) != 0;
+        }
+
+        /**
+         * set the integer representation of this flag. only for NW_SRC and
+         * NW_DST
+         */
+        int setInt(int flags, int srcMask) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * set the integer representation of this flag. only for NW_SRC and
+         * NW_DST
+         */
+        int getInt(int flags) {
+            throw new UnsupportedOperationException();
+        }
+
+
+    }
+
+    private final int flags;
+
+    /** private constructor. use Wildcard.of() instead */
+    private Wildcards(int flags) {
+        this.flags = flags;
+    }
+
+    /**
+     * return a wildcard object matching the given int flags. May reuse / cache
+     * frequently used wildcard instances. Don't rely on it though (use equals
+     * not ==).
+     *
+     * @param flags
+     * @return
+     */
+    public static Wildcards of(int paramFlags) {
+        int flags = sanitizeInt(paramFlags);
+        switch(flags) {
+            case 0x0000:
+                return EXACT;
+            case OFMatch.OFPFW_ALL_SANITIZED:
+                return FULL;
+            case INT_INPORT_L2_MATCH:
+                return INPORT_L2_MATCH;
+            default:
+                return new Wildcards(flags);
+        }
+    }
+
+    /** convience method return a wildcard for exactly one set flag */
+    public static Wildcards of(Wildcards.Flag setFlag) {
+        return Wildcards.of(setFlag.wildcard(0));
+    }
+
+    /** convience method return a wildcard for exactly two set flags */
+    public static Wildcards of(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
+        return Wildcards.of(setFlag.wildcard(setFlag2.wildcard(0)));
+    }
+
+    /** convience method return a wildcard for an arbitrary number of set flags */
+    public static Wildcards of(Wildcards.Flag... setFlags) {
+        int flags = 0;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.wildcard(0);
+        return Wildcards.of(flags);
+    }
+
+    /** convience method return a wildcards for ofmatches that match on one flag */
+    public static Wildcards ofMatches(Wildcards.Flag setFlag) {
+        return Wildcards.of(setFlag.matchOn(FULL_INT));
+    }
+
+    /**
+     * convience method return a wildcard for for an ofmatch that match on two
+     * flags
+     */
+    public static Wildcards ofMatches(Wildcards.Flag setFlag, Wildcards.Flag setFlag2) {
+        return Wildcards.of(setFlag.matchOn(setFlag2.matchOn(FULL_INT)));
+    }
+
+    /**
+     * convience method return a wildcard for an ofmatch that amtch on an
+     * arbitrary number of set flags
+     */
+    public static Wildcards ofMatches(Wildcards.Flag... setFlags) {
+        int flags = FULL_INT;
+        for (Wildcards.Flag flag : setFlags)
+           flags = flag.matchOn(flags);
+        return Wildcards.of(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags set
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag flag) {
+        int flags = flag.wildcard(this.flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags set
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag flag, Wildcards.Flag flag2) {
+        int flags = flag.wildcard(flag2.wildcard(this.flags));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that has the given flags wildcarded
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards wildcard(Wildcards.Flag... setFlags) {
+        int flags = this.flags;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.wildcard(flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flag
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag flag) {
+        int flags = flag.matchOn(this.flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flags
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag flag, Wildcards.Flag flag2) {
+        int flags = flag.matchOn(flag2.matchOn(this.flags));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcards object that matches on exactly the given flags
+     * <p>
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     */
+    public Wildcards matchOn(Wildcards.Flag... setFlags) {
+        int flags = this.flags;
+        for (Wildcards.Flag flag : setFlags)
+            flags = flag.matchOn(flags);
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return the nw src mask in normal CIDR style, e.g., 8 means x.x.x.x/8
+     * means 8 bits wildcarded
+     */
+    public int getNwSrcMask() {
+        return Math.max(0, 32 - Flag.NW_SRC.getInt(flags));
+    }
+
+    /**
+     * return the nw dst mask in normal CIDR style, e.g., 8 means x.x.x.x/8
+     * means 8 bits wildcarded
+     */
+    public int getNwDstMask() {
+        return Math.max(0, 32 - Flag.NW_DST.getInt(flags));
+    }
+
+    /**
+     * return a Wildcard object that has the given nwSrcCidrMask set.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     *
+     * @param srcCidrMask
+     *            source mask to set in <b>normal CIDR notation</b>, i.e., 8
+     *            means x.x.x.x/8
+     * @return a modified object
+     */
+    public Wildcards withNwSrcMask(int srcCidrMask) {
+        int flags = Flag.NW_SRC.setInt(this.flags, Math.max(0, 32 - srcCidrMask));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcard object that has the given nwDstCidrMask set.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     *
+     * @param dstCidrMask
+     *            dest mask to set in <b>normal CIDR notation</b>, i.e., 8 means
+     *            x.x.x.x/8
+     * @return a modified object
+     */
+    public Wildcards withNwDstMask(int dstCidrMask) {
+        int flags = Flag.NW_DST.setInt(this.flags, Math.max(0, 32 - dstCidrMask));
+        if (flags == this.flags)
+            return this;
+        else
+            return new Wildcards(flags);
+    }
+
+    /**
+     * return a Wildcard object that is inverted to this wildcard object.
+     * <b>NOTE:</b> NOT a mutator function. 'this' wildcard object stays
+     * unmodified. </b>
+     * @return a modified object
+     */
+    public Wildcards inverted() {
+        return Wildcards.of(flags ^ OFMatch.OFPFW_ALL_SANITIZED);
+    }
+
+    public boolean isWildcarded(Flag flag) {
+        return flag.isFullyOn(flags);
+    }
+
+    /**
+     * return all wildcard flags that are fully wildcarded as an EnumSet. Do not
+     * modify. Note: some flags (like NW_SRC and NW_DST) that are partially
+     * wildcarded are not returned in this set.
+     *
+     * @return the EnumSet of wildcards
+     */
+    public EnumSet<Wildcards.Flag> getWildcardedFlags() {
+        EnumSet<Wildcards.Flag> res = EnumSet.noneOf(Wildcards.Flag.class);
+        for (Wildcards.Flag flag : Flag.values()) {
+            if (flag.isFullyOn(flags)) {
+                res.add(flag);
+            }
+        }
+        return res;
+    }
+
+    /** return the OpenFlow 'wire' integer representation of these wildcards */
+    public int getInt() {
+        return flags;
+    }
+
+    /**
+     * return the OpenFlow 'wire' integer representation of these wildcards.
+     * Sanitize nw_src and nw_dst to be max. 32 (values > 32 are technically
+     * possible, but don't make semantic sense)
+     */
+    public static int sanitizeInt(int flags) {
+        if (((flags & OFMatch.OFPFW_NW_SRC_MASK) >> OFMatch.OFPFW_NW_SRC_SHIFT) > 32) {
+            flags = (flags & ~OFMatch.OFPFW_NW_SRC_MASK) | OFMatch.OFPFW_NW_SRC_ALL;
+        }
+        if (((flags & OFMatch.OFPFW_NW_DST_MASK) >> OFMatch.OFPFW_NW_DST_SHIFT) > 32) {
+            flags = (flags & ~OFMatch.OFPFW_NW_DST_MASK) | OFMatch.OFPFW_NW_DST_ALL;
+        }
+        return flags;
+    }
+
+    /**
+     * is this a wildcard set that has all flags set + and full (/0) nw_src and
+     * nw_dst wildcarding ?
+     */
+    public boolean isFull() {
+        return flags == OFMatch.OFPFW_ALL || flags == OFMatch.OFPFW_ALL_SANITIZED;
+    }
+
+    /** is this a wildcard of an exact match */
+    public boolean isExact() {
+        return flags == 0;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + flags;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Wildcards other = (Wildcards) obj;
+        if (flags != other.flags)
+            return false;
+        return true;
+    }
+
+    private final static Joiner pipeJoiner = Joiner.on("|");
+
+    @Override
+    public String toString() {
+        List<String> res = new ArrayList<String>();
+        for (Wildcards.Flag flag : Flag.values()) {
+            if (flag.isFullyOn(flags)) {
+                res.add(flag.name().toLowerCase());
+            }
+        }
+
+        if (Flag.NW_SRC.isPartiallyOn(flags)) {
+            res.add("nw_src(/" + getNwSrcMask() + ")");
+        }
+
+        if (Flag.NW_DST.isPartiallyOn(flags)) {
+            res.add("nw_dst(/" + getNwDstMask() + ")");
+        }
+
+        return pipeJoiner.join(res);
+    }
+
+    private final static Joiner commaJoiner = Joiner.on(", ");
+
+    /** a Java expression that constructs 'this' wildcards set */
+    public String toJava() {
+        if(isFull()) {
+            return "Wildcards.FULL";
+        } else  if (isExact()){
+            return "Wildcards.EXACT";
+        }
+
+        StringBuilder b = new StringBuilder();
+
+        EnumSet<Flag> myFlags = getWildcardedFlags();
+        if (myFlags.size() < 3) {
+            // default to start with empty
+            b.append("Wildcards.of("
+                     + commaJoiner.join(prefix("Flag.", myFlags.iterator())) + ")");
+        } else {
+            // too many - start with full
+
+            EnumSet<Flag> invFlags = inverted().getWildcardedFlags();
+            b.append("Wildcards.ofMatches("
+                     + commaJoiner.join(prefix("Flag.", invFlags.iterator())) + ")");
+        }
+        if (Flag.NW_SRC.isPartiallyOn(flags)) {
+            b.append(".setNwSrcMask(" + getNwSrcMask() + ")");
+        }
+        if (Flag.NW_DST.isPartiallyOn(flags)) {
+            b.append(".setNwDstMask(" + getNwDstMask() + ")");
+        }
+        return b.toString();
+    }
+
+    private Iterator<String> prefix(final String prefix, final Iterator<?> i) {
+        return new Iterator<String>() {
+
+            @Override
+            public boolean hasNext() {
+                return i.hasNext();
+            }
+
+            @Override
+            public String next() {
+                Object next = i.next();
+                return next == null ? null : prefix + next.toString();
+            }
+
+            @Override
+            public void remove() {
+                i.remove();
+            }
+        };
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/openflow/protocol/factory/BasicFactory.java b/src/main/java/org/openflow/protocol/factory/BasicFactory.java
index 7b15e82612326158f0eb5184518c20b11be7ae65..7b06f2c0c91a5a8a966be3430d34f4dbbb9f23cc 100644
--- a/src/main/java/org/openflow/protocol/factory/BasicFactory.java
+++ b/src/main/java/org/openflow/protocol/factory/BasicFactory.java
@@ -44,9 +44,20 @@ import org.openflow.protocol.vendor.OFVendorId;
  */
 public class BasicFactory implements OFMessageFactory, OFActionFactory,
         OFStatisticsFactory, OFVendorDataFactory {
+
+    /**
+     * create and return a new instance of a message for OFType t. Also injects
+     * factories for those message types that implement the *FactoryAware
+     * interfaces.
+     *
+     * @return a newly created instance that may be modified / used freely by
+     *         the caller
+     */
     @Override
     public OFMessage getMessage(OFType t) {
-        return t.newInstance();
+        OFMessage message = t.newInstance();
+        injectFactories(message);
+        return message;
     }
 
     @Override
@@ -92,18 +103,7 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory,
             if (ofm == null)
                 return null;
 
-            if (ofm instanceof OFActionFactoryAware) {
-                ((OFActionFactoryAware)ofm).setActionFactory(this);
-            }
-            if (ofm instanceof OFMessageFactoryAware) {
-                ((OFMessageFactoryAware)ofm).setMessageFactory(this);
-            }
-            if (ofm instanceof OFStatisticsFactoryAware) {
-                ((OFStatisticsFactoryAware)ofm).setStatisticsFactory(this);
-            }
-            if (ofm instanceof OFVendorDataFactoryAware) {
-                ((OFVendorDataFactoryAware)ofm).setVendorDataFactory(this);
-            }
+            injectFactories(ofm);
             ofm.readFrom(data);
             if (OFMessage.class.equals(ofm.getClass())) {
                 // advance the position for un-implemented messages
@@ -124,6 +124,21 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory,
         }
     }
 
+    private void injectFactories(OFMessage ofm) {
+        if (ofm instanceof OFActionFactoryAware) {
+            ((OFActionFactoryAware)ofm).setActionFactory(this);
+        }
+        if (ofm instanceof OFMessageFactoryAware) {
+            ((OFMessageFactoryAware)ofm).setMessageFactory(this);
+        }
+        if (ofm instanceof OFStatisticsFactoryAware) {
+            ((OFStatisticsFactoryAware)ofm).setStatisticsFactory(this);
+        }
+        if (ofm instanceof OFVendorDataFactoryAware) {
+            ((OFVendorDataFactoryAware)ofm).setVendorDataFactory(this);
+        }
+    }
+
     @Override
     public OFAction getAction(OFActionType t) {
         return t.newInstance();
@@ -194,7 +209,7 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory,
      *            length of statistics
      * @param limit
      *            number of statistics to grab; 0 == all
-     * 
+     *
      * @return list of statistics
      */
 
@@ -230,7 +245,7 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory,
                      * though we have a full message. Found when NOX sent
                      * agg_stats request with wrong agg statistics length (52
                      * instead of 56)
-                     * 
+                     *
                      * just throw the rest away, or we will break framing
                      */
                     data.readerIndex(start + length);
@@ -247,7 +262,7 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory,
                                       OFVendorDataType vendorDataType) {
         if (vendorDataType == null)
             return null;
-        
+
         return vendorDataType.newInstance();
     }
 
@@ -259,6 +274,7 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory,
      * @param length the length to the end of the enclosing message.
      * @return an OFVendorData instance
      */
+    @Override
     public OFVendorData parseVendorData(int vendor, ChannelBuffer data,
             int length) {
         OFVendorDataType vendorDataType = null;
@@ -268,13 +284,13 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory,
             vendorDataType = vendorId.parseVendorDataType(data, length);
             data.resetReaderIndex();
         }
-        
+
         OFVendorData vendorData = getVendorData(vendorId, vendorDataType);
         if (vendorData == null)
             vendorData = new OFByteArrayVendorData();
 
         vendorData.readFrom(data, length);
-        
+
         return vendorData;
     }
 
diff --git a/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java b/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java
index 6799fa3618e1f2303a84f4c9a8085db873261cd9..86ad782d8b56a4dff1be90e6f3af503b282adb87 100644
--- a/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java
+++ b/src/main/java/org/openflow/protocol/statistics/OFDescriptionStatistics.java
@@ -213,4 +213,13 @@ public class OFDescriptionStatistics implements OFStatistics {
         }
         return true;
     }
+
+    @Override
+    public String toString() {
+        return "Switch Desc - Vendor: " +  manufacturerDescription +
+                "  Model: " + hardwareDescription +
+                "  Make: " + datapathDescription +
+                "  Version: " + softwareDescription +
+                "  S/N: " + serialNumber;
+    }
 }
diff --git a/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorExtensions.java b/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorExtensions.java
new file mode 100644
index 0000000000000000000000000000000000000000..98f88b242f62a34a3ff4e45b9197f8da58ecc9ec
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/nicira/OFNiciraVendorExtensions.java
@@ -0,0 +1,30 @@
+package org.openflow.vendor.nicira;
+
+import org.openflow.protocol.vendor.OFBasicVendorDataType;
+import org.openflow.protocol.vendor.OFBasicVendorId;
+import org.openflow.protocol.vendor.OFVendorId;
+
+public class OFNiciraVendorExtensions {
+    private static boolean initialized = false;
+
+    public static synchronized void initialize() {
+        if (initialized)
+            return;
+
+        // Configure openflowj to be able to parse the role request/reply
+        // vendor messages.
+        OFBasicVendorId niciraVendorId =
+                new OFBasicVendorId(OFNiciraVendorData.NX_VENDOR_ID, 4);
+        OFVendorId.registerVendorId(niciraVendorId);
+        OFBasicVendorDataType roleRequestVendorData =
+                new OFBasicVendorDataType(OFRoleRequestVendorData.NXT_ROLE_REQUEST,
+                        OFRoleRequestVendorData.getInstantiable());
+        niciraVendorId.registerVendorDataType(roleRequestVendorData);
+        OFBasicVendorDataType roleReplyVendorData =
+                new OFBasicVendorDataType(OFRoleReplyVendorData.NXT_ROLE_REPLY,
+                        OFRoleReplyVendorData.getInstantiable());
+        niciraVendorId.registerVendorDataType(roleReplyVendorData);
+
+        initialized = true;
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
index 177c46dbb5bcd534d8f4426b4a24a0be012c5d44..195f1c042cfcf2f90878ae7ced4f773eb1fdb998 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -45,6 +46,7 @@ import net.floodlightcontroller.core.internal.Controller.IUpdate;
 import net.floodlightcontroller.core.internal.Controller.SwitchUpdate;
 import net.floodlightcontroller.core.internal.Controller.SwitchUpdateType;
 import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState;
+import net.floodlightcontroller.core.internal.RoleChanger.PendingRoleRequestEntry;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.test.MockFloodlightProvider;
 import net.floodlightcontroller.core.test.MockThreadPoolService;
@@ -68,7 +70,6 @@ import org.easymock.EasyMock;
 import org.jboss.netty.channel.Channel;
 import org.junit.Test;
 import org.openflow.protocol.OFError;
-import org.openflow.protocol.OFError.OFBadRequestCode;
 import org.openflow.protocol.OFError.OFErrorType;
 import org.openflow.protocol.OFFeaturesReply;
 import org.openflow.protocol.OFPacketIn;
@@ -101,6 +102,8 @@ public class ControllerTest extends FloodlightTestCase
    
     private Controller controller;
     private MockThreadPoolService tp;
+    private boolean test_bind_order = false;
+    private List<String> bind_order;
 
     @Override
     public void setUp() throws Exception {
@@ -482,6 +485,7 @@ public class ControllerTest extends FloodlightTestCase
 
         Channel channel = createMock(Channel.class);
         oldsw.setChannel(channel);
+        expect(channel.getRemoteAddress()).andReturn(null);
         expect(channel.close()).andReturn(null);
 
         IOFSwitch newsw = createMock(IOFSwitch.class);
@@ -509,6 +513,7 @@ public class ControllerTest extends FloodlightTestCase
         Channel channel = createMock(Channel.class);
         oldsw.setChannel(channel);
         expect(channel.close()).andReturn(null);
+        expect(channel.getRemoteAddress()).andReturn(null);
 
         IOFSwitch newsw = createMock(IOFSwitch.class);
         expect(newsw.getId()).andReturn(0L).anyTimes();
@@ -547,7 +552,7 @@ public class ControllerTest extends FloodlightTestCase
                 return "dummy";
             }
             @Override
-            public void switchPortChanged(Long switchId) {
+            public synchronized void switchPortChanged(Long switchId) {
                 nPortChanged++;
                 notifyAll();
             }
@@ -758,10 +763,11 @@ public class ControllerTest extends FloodlightTestCase
         assertTrue("Check that update is HARoleUpdate", 
                    upd instanceof Controller.HARoleUpdate);
         Controller.HARoleUpdate roleUpd = (Controller.HARoleUpdate)upd;
-        assertSame(null, roleUpd.oldRole);
+        assertSame(Role.MASTER, roleUpd.oldRole);
         assertSame(Role.SLAVE, roleUpd.newRole);
     }
     
+    @SuppressWarnings("unchecked")
     @Test
     public void testCheckSwitchReady() {
         OFChannelState state = new OFChannelState();
@@ -821,13 +827,13 @@ public class ControllerTest extends FloodlightTestCase
         // setupSwitchForAddSwitch(chdlr.sw, 0L);
         // chdlr.sw.clearAllFlowMods();
         desc.setManufacturerDescription("test vendor");
+        controller.roleChanger.submitRequest(
+                (List<IOFSwitch>)EasyMock.anyObject(),
+                (Role)EasyMock.anyObject());
         replay(controller.roleChanger);
         chdlr.checkSwitchReady();
         verify(controller.roleChanger);
         assertSame(OFChannelState.HandshakeState.READY, state.hsState);
-        assertSame(chdlr.sw, controller.activeSwitches.get(0L));
-        assertTrue(controller.connectedSwitches.contains(chdlr.sw));
-        assertTrue(state.firstRoleReplyReceived);
         reset(controller.roleChanger);
         controller.connectedSwitches.clear();
         controller.activeSwitches.clear();
@@ -846,7 +852,6 @@ public class ControllerTest extends FloodlightTestCase
         assertSame(OFChannelState.HandshakeState.READY, state.hsState);
         assertTrue(controller.activeSwitches.isEmpty());
         assertFalse(controller.connectedSwitches.isEmpty());
-        assertTrue(state.firstRoleReplyReceived);
         Collection<IOFSwitch> swList = swListCapture.getValue();
         assertEquals(1, swList.size());
     }
@@ -864,9 +869,6 @@ public class ControllerTest extends FloodlightTestCase
         OFChannelState state = new OFChannelState();
         Controller.OFChannelHandler chdlr =
                 controller.new OFChannelHandler(state);
-        OFSwitchImpl sw = new OFSwitchImpl();
-        sw.stringId = "1";
-        chdlr.sw = sw;
         
         // Swith should be bound of OFSwitchImpl (default)
         state.hsState = OFChannelState.HandshakeState.HELLO;
@@ -886,7 +888,6 @@ public class ControllerTest extends FloodlightTestCase
         assertTrue(!(chdlr.sw instanceof TestSwitchClass));
         
         // Switch should be bound to TestSwitchImpl
-        chdlr.sw = sw;
         state.switchBindingDone = false;
         desc.setManufacturerDescription("test1 switch");
         desc.setHardwareDescription("version 1.0");
@@ -897,7 +898,6 @@ public class ControllerTest extends FloodlightTestCase
         assertTrue(chdlr.sw instanceof TestSwitchClass);
 
         // Switch should be bound to Test11SwitchImpl
-        chdlr.sw = sw;
         state.switchBindingDone = false;
         desc.setManufacturerDescription("test11 switch");
         desc.setHardwareDescription("version 1.1");
@@ -908,12 +908,50 @@ public class ControllerTest extends FloodlightTestCase
         assertTrue(chdlr.sw instanceof Test11SwitchClass);
     }
     
+    @Test
+    public void testBindSwitchOrder() {
+        List<String> order = new ArrayList<String>(3);
+        controller.addOFSwitchDriver("", this);
+        controller.addOFSwitchDriver("test switch", this);
+        controller.addOFSwitchDriver("test", this);
+        order.add("test switch");
+        order.add("test");
+        order.add("");
+        test_bind_order = true;
+        
+        OFChannelState state = new OFChannelState();
+        Controller.OFChannelHandler chdlr =
+                controller.new OFChannelHandler(state);
+        chdlr.sw = null;
+        
+        // Swith should be bound of OFSwitchImpl (default)
+        state.hsState = OFChannelState.HandshakeState.HELLO;
+        state.hasDescription = true;
+        state.hasGetConfigReply = true;
+        state.switchBindingDone = false;
+        OFDescriptionStatistics desc = new OFDescriptionStatistics();
+        desc.setManufacturerDescription("test switch");
+        desc.setHardwareDescription("version 0.9");
+        state.description = desc;
+        OFFeaturesReply featuresReply = new OFFeaturesReply();
+        featuresReply.setPorts(new ArrayList<OFPhysicalPort>());
+        state.featuresReply = featuresReply;
+
+        chdlr.bindSwitchToDriver();
+        assertTrue(chdlr.sw instanceof OFSwitchImpl);
+        assertTrue(!(chdlr.sw instanceof TestSwitchClass));
+        // Verify bind_order is called as expected
+        assertTrue(order.equals(bind_order));
+        test_bind_order = false;
+        bind_order = null;
+   }
+    
     @Test
     public void testChannelDisconnected() throws Exception {
         OFChannelState state = new OFChannelState();
         state.hsState = OFChannelState.HandshakeState.READY;
         Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
-        chdlr.sw = createMock(OFSwitchImpl.class);
+        chdlr.sw = createMock(IOFSwitch.class);
         
         // Switch is active 
         expect(chdlr.sw.getId()).andReturn(0L).anyTimes();
@@ -982,7 +1020,7 @@ public class ControllerTest extends FloodlightTestCase
         OFChannelState state = new OFChannelState();
         state.hsState = HandshakeState.READY;
         Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
-        chdlr.sw = createMock(OFSwitchImpl.class);
+        chdlr.sw = createMock(IOFSwitch.class);
         Channel ch = createMock(Channel.class);
         
         // the error returned when role request message is not supported by sw
@@ -990,64 +1028,36 @@ public class ControllerTest extends FloodlightTestCase
         msg.setType(OFType.ERROR);
         msg.setXid(xid);
         msg.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
-        msg.setErrorCode(OFBadRequestCode.OFPBRC_BAD_VENDOR);
         
         // the switch connection should get disconnected when the controller is
         // in SLAVE mode and the switch does not support role-request messages
-        state.firstRoleReplyReceived = false;
         controller.role = Role.SLAVE;
-        expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
-        chdlr.sw.deliverRoleRequestNotSupported(xid);
-        expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes();
-        expect(chdlr.sw.getRole()).andReturn(null).anyTimes();
-        expect(ch.close()).andReturn(null);
+        setupPendingRoleRequest(chdlr.sw, xid, controller.role, 123456);                
+        expect(chdlr.sw.getHARole()).andReturn(null);
+        chdlr.sw.setHARole(Role.SLAVE, false);
+        expect(chdlr.sw.getHARole()).andReturn(Role.SLAVE);
+        chdlr.sw.disconnectOutputStream();
         
         replay(ch, chdlr.sw);
         chdlr.processOFMessage(msg);
         verify(ch, chdlr.sw);
-        assertTrue("state.firstRoleReplyReceived must be true", 
-                   state.firstRoleReplyReceived);
         assertTrue("activeSwitches must be empty",
                    controller.activeSwitches.isEmpty());
         reset(ch, chdlr.sw);
               
-        
-        // a different error message - should also reject role request
-        msg.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
-        msg.setErrorCode(OFBadRequestCode.OFPBRC_EPERM);
-        state.firstRoleReplyReceived = false;
-        controller.role = Role.SLAVE;
-        expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
-        chdlr.sw.deliverRoleRequestNotSupported(xid);
-        expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes();
-        expect(chdlr.sw.getRole()).andReturn(null).anyTimes();
-        expect(ch.close()).andReturn(null);
-        replay(ch, chdlr.sw);
-        
-        chdlr.processOFMessage(msg);
-        verify(ch, chdlr.sw);
-        assertTrue("state.firstRoleReplyReceived must be True even with EPERM",
-                   state.firstRoleReplyReceived);
-        assertTrue("activeSwitches must be empty", 
-                   controller.activeSwitches.isEmpty());
-        reset(ch, chdlr.sw);
-    
-        
         // We are MASTER, the switch should be added to the list of active
         // switches.
-        state.firstRoleReplyReceived = false;
         controller.role = Role.MASTER;
-        expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
-        chdlr.sw.deliverRoleRequestNotSupported(xid);
+        setupPendingRoleRequest(chdlr.sw, xid, controller.role, 123456);                
+        expect(chdlr.sw.getHARole()).andReturn(null);
+        chdlr.sw.setHARole(controller.role, false);
         setupSwitchForAddSwitch(chdlr.sw, 0L);
         chdlr.sw.clearAllFlowMods();
-        expect(chdlr.sw.getRole()).andReturn(null).anyTimes();
+        expect(chdlr.sw.getHARole()).andReturn(null).anyTimes();
         replay(ch, chdlr.sw);
         
         chdlr.processOFMessage(msg);
         verify(ch, chdlr.sw);
-        assertTrue("state.firstRoleReplyReceived must be true", 
-                   state.firstRoleReplyReceived);
         assertSame("activeSwitches must contain this switch",
                    chdlr.sw, controller.activeSwitches.get(0L));
         reset(ch, chdlr.sw);
@@ -1072,7 +1082,7 @@ public class ControllerTest extends FloodlightTestCase
         OFChannelState state = new OFChannelState();
         state.hsState = HandshakeState.READY;
         Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
-        chdlr.sw = createMock(OFSwitchImpl.class);
+        chdlr.sw = createMock(IOFSwitch.class);
         return chdlr;
     }
     
@@ -1087,7 +1097,18 @@ public class ControllerTest extends FloodlightTestCase
         roleReplyVendorData.setRole(nicira_role);
         return msg;
     }
-   
+    
+    // Helper function
+    protected void setupPendingRoleRequest(IOFSwitch sw, int xid, Role role,
+            long cookie) {
+        LinkedList<PendingRoleRequestEntry> pendingList =
+                new LinkedList<PendingRoleRequestEntry>();
+        controller.roleChanger.pendingRequestMap.put(sw, pendingList);
+        PendingRoleRequestEntry entry =
+                new PendingRoleRequestEntry(xid, role, cookie);
+        pendingList.add(entry);
+    }
+    
     /** invalid role in role reply */
     @Test 
     public void testNiciraRoleReplyInvalidRole() 
@@ -1095,8 +1116,7 @@ public class ControllerTest extends FloodlightTestCase
         int xid = 424242;
         Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
         Channel ch = createMock(Channel.class);
-        expect(chdlr.sw.getChannel()).andReturn(ch);
-        expect(ch.close()).andReturn(null);
+        chdlr.sw.disconnectOutputStream();
         OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, 232323);
         replay(chdlr.sw, ch);
         chdlr.processOFMessage(msg);
@@ -1111,17 +1131,15 @@ public class ControllerTest extends FloodlightTestCase
         Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
         OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
                                        OFRoleReplyVendorData.NX_ROLE_MASTER);
-        
-        chdlr.sw.deliverRoleReply(xid, Role.MASTER);
-        expect(chdlr.sw.isActive()).andReturn(true);
+
+        setupPendingRoleRequest(chdlr.sw, xid, Role.MASTER, 123456);                
+        expect(chdlr.sw.getHARole()).andReturn(null);
+        chdlr.sw.setHARole(Role.MASTER, true);
         setupSwitchForAddSwitch(chdlr.sw, 1L);
         chdlr.sw.clearAllFlowMods();
-        chdlr.state.firstRoleReplyReceived = false;
         replay(chdlr.sw);
         chdlr.processOFMessage(msg);
         verify(chdlr.sw);
-        assertTrue("state.firstRoleReplyReceived must be true", 
-                   chdlr.state.firstRoleReplyReceived);
         assertSame("activeSwitches must contain this switch",
                    chdlr.sw, controller.activeSwitches.get(1L));
     }
@@ -1135,17 +1153,15 @@ public class ControllerTest extends FloodlightTestCase
         Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
         OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
                                        OFRoleReplyVendorData.NX_ROLE_MASTER);
-        
-        chdlr.sw.deliverRoleReply(xid, Role.MASTER);
-        expect(chdlr.sw.isActive()).andReturn(true);
+
+        setupPendingRoleRequest(chdlr.sw, xid, Role.MASTER, 123456);        
+        expect(chdlr.sw.getHARole()).andReturn(Role.SLAVE);
+        chdlr.sw.setHARole(Role.MASTER, true);
         setupSwitchForAddSwitch(chdlr.sw, 1L);
-        chdlr.state.firstRoleReplyReceived = true;
         // Flow table shouldn't be wipe
         replay(chdlr.sw);
         chdlr.processOFMessage(msg);
         verify(chdlr.sw);
-        assertTrue("state.firstRoleReplyReceived must be true", 
-                   chdlr.state.firstRoleReplyReceived);
         assertSame("activeSwitches must contain this switch",
                    chdlr.sw, controller.activeSwitches.get(1L));
     }
@@ -1159,16 +1175,14 @@ public class ControllerTest extends FloodlightTestCase
         OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
                                        OFRoleReplyVendorData.NX_ROLE_OTHER);
         
-        chdlr.sw.deliverRoleReply(xid, Role.EQUAL);
-        expect(chdlr.sw.isActive()).andReturn(true);
+        setupPendingRoleRequest(chdlr.sw, xid, Role.EQUAL, 123456);                
+        expect(chdlr.sw.getHARole()).andReturn(null);
+        chdlr.sw.setHARole(Role.EQUAL, true);
         setupSwitchForAddSwitch(chdlr.sw, 1L);
         chdlr.sw.clearAllFlowMods();
-        chdlr.state.firstRoleReplyReceived = false;
         replay(chdlr.sw);
         chdlr.processOFMessage(msg);
         verify(chdlr.sw);
-        assertTrue("state.firstRoleReplyReceived must be true", 
-                   chdlr.state.firstRoleReplyReceived);
         assertSame("activeSwitches must contain this switch",
                    chdlr.sw, controller.activeSwitches.get(1L));
     };
@@ -1181,18 +1195,16 @@ public class ControllerTest extends FloodlightTestCase
         OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, 
                                        OFRoleReplyVendorData.NX_ROLE_SLAVE);
         
-        chdlr.sw.deliverRoleReply(xid, Role.SLAVE);
+        setupPendingRoleRequest(chdlr.sw, xid, Role.SLAVE, 123456);                
+        expect(chdlr.sw.getHARole()).andReturn(null);
+        chdlr.sw.setHARole(Role.SLAVE, true);
         expect(chdlr.sw.getId()).andReturn(1L).anyTimes();
         expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01")
                     .anyTimes();
-        expect(chdlr.sw.isActive()).andReturn(false);
         // don't add switch to activeSwitches ==> slave2slave
-        chdlr.state.firstRoleReplyReceived = false;
         replay(chdlr.sw);
         chdlr.processOFMessage(msg);
         verify(chdlr.sw);
-        assertTrue("state.firstRoleReplyReceived must be true", 
-                   chdlr.state.firstRoleReplyReceived);
         assertTrue("activeSwitches must be empty", 
                    controller.activeSwitches.isEmpty());
     }
@@ -1205,19 +1217,17 @@ public class ControllerTest extends FloodlightTestCase
         OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, 
                                        OFRoleReplyVendorData.NX_ROLE_MASTER);
         
-        chdlr.sw.deliverRoleReply(xid, Role.MASTER);
+        setupPendingRoleRequest(chdlr.sw, xid, Role.MASTER, 123456);                
+        expect(chdlr.sw.getHARole()).andReturn(null);
+        chdlr.sw.setHARole(Role.MASTER, true);
         expect(chdlr.sw.getId()).andReturn(1L).anyTimes();
         expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01")
                     .anyTimes();
-        expect(chdlr.sw.isActive()).andReturn(true);
         controller.activeSwitches.put(1L, chdlr.sw);
-        chdlr.state.firstRoleReplyReceived = false;
         // Must not clear flow mods
         replay(chdlr.sw);
         chdlr.processOFMessage(msg);
         verify(chdlr.sw);
-        assertTrue("state.firstRoleReplyReceived must be true", 
-                   chdlr.state.firstRoleReplyReceived);
         assertSame("activeSwitches must contain this switch",
                    chdlr.sw, controller.activeSwitches.get(1L));
     }
@@ -1230,20 +1240,19 @@ public class ControllerTest extends FloodlightTestCase
         OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, 
                                        OFRoleReplyVendorData.NX_ROLE_SLAVE);
         
-        chdlr.sw.deliverRoleReply(xid, Role.SLAVE);
+        setupPendingRoleRequest(chdlr.sw, xid, Role.SLAVE, 123456);                
+        expect(chdlr.sw.getHARole()).andReturn(null);
+        chdlr.sw.setHARole(Role.SLAVE, true);
         expect(chdlr.sw.getId()).andReturn(1L).anyTimes();
         expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01")
                     .anyTimes();
         controller.activeSwitches.put(1L, chdlr.sw);
-        expect(chdlr.sw.isActive()).andReturn(false).anyTimes();
+        expect(chdlr.sw.getHARole()).andReturn(Role.SLAVE).anyTimes();
         expect(chdlr.sw.isConnected()).andReturn(true);
         chdlr.sw.cancelAllStatisticsReplies();
-        chdlr.state.firstRoleReplyReceived = false;
         replay(chdlr.sw);
         chdlr.processOFMessage(msg);
         verify(chdlr.sw);
-        assertTrue("state.firstRoleReplyReceived must be true", 
-                   chdlr.state.firstRoleReplyReceived);
         assertTrue("activeSwitches must be empty", 
                    controller.activeSwitches.isEmpty());
     }
@@ -1321,7 +1330,16 @@ public class ControllerTest extends FloodlightTestCase
     }
 
     @Override
-    public IOFSwitch getOFSwitchImpl(OFDescriptionStatistics description) {
+    public IOFSwitch getOFSwitchImpl(String regis_desc,
+            OFDescriptionStatistics description) {
+        // If testing bind order, just record registered desc string
+        if (test_bind_order) {
+            if (bind_order == null) {
+                bind_order = new ArrayList<String>();
+            }
+            bind_order.add(regis_desc);
+            return null;
+        }
         String hw_desc = description.getHardwareDescription();
         if (hw_desc.equals("version 1.1")) {
             return new Test11SwitchClass();
@@ -1331,4 +1349,5 @@ public class ControllerTest extends FloodlightTestCase
         }
         return null;
     }
+
 }
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java
index 758cd0563588e7fa759c99ccaec95d2217fe3f21..685efdc4f4bfeeac548d695ee272cc3430c4ae83 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFSwitchImplTest.java
@@ -1,27 +1,11 @@
 package net.floodlightcontroller.core.internal;
 
-import static org.easymock.EasyMock.*;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.util.List;
-
-import net.floodlightcontroller.core.IFloodlightProviderService.Role;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.internal.OFSwitchImpl.PendingRoleRequestEntry;
-import net.floodlightcontroller.core.test.MockFloodlightProvider;
+import net.floodlightcontroller.core.IFloodlightProviderService.Role;
 import net.floodlightcontroller.test.FloodlightTestCase;
 
-import org.easymock.Capture;
-import org.jboss.netty.channel.Channel;
 import org.junit.Before;
 import org.junit.Test;
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFType;
-import org.openflow.protocol.OFVendor;
-import org.openflow.protocol.vendor.OFVendorData;
-import org.openflow.vendor.nicira.OFNiciraVendorData;
-import org.openflow.vendor.nicira.OFRoleRequestVendorData;
-import org.openflow.vendor.nicira.OFRoleVendorData;
 
 public class OFSwitchImplTest extends FloodlightTestCase {
     protected OFSwitchImpl sw;
@@ -30,207 +14,40 @@ public class OFSwitchImplTest extends FloodlightTestCase {
     @Before
     public void setUp() throws Exception {
         sw = new OFSwitchImpl();
-        Channel ch = createMock(Channel.class);
-        SocketAddress sa = new InetSocketAddress(42);
-        expect(ch.getRemoteAddress()).andReturn(sa).anyTimes();
-        sw.setChannel(ch);
-        MockFloodlightProvider floodlightProvider = new MockFloodlightProvider();
-        sw.setFloodlightProvider(floodlightProvider);
-    }
-
-    
-    public void doSendNxRoleRequest(Role role, int nx_role) throws Exception {
-        long cookie = System.nanoTime();
-        
-        // verify that the correct OFMessage is sent
-        Capture<List<OFMessage>> msgCapture = new Capture<List<OFMessage>>();
-        expect(sw.channel.write(capture(msgCapture))).andReturn(null);
-        replay(sw.channel);
-        int xid = sw.sendNxRoleRequest(role, cookie);
-        verify(sw.channel);
-        List<OFMessage> msgList = msgCapture.getValue();
-        assertEquals(1, msgList.size());
-        OFMessage msg = msgList.get(0);
-        assertEquals("Transaction Ids must match", xid, msg.getXid()); 
-        assertTrue("Message must be an OFVendor type", msg instanceof OFVendor);
-        assertEquals(OFType.VENDOR, msg.getType());
-        OFVendor vendorMsg = (OFVendor)msg;
-        assertEquals("Vendor message must be vendor Nicira",
-                     OFNiciraVendorData.NX_VENDOR_ID, vendorMsg.getVendor());
-        OFVendorData vendorData = vendorMsg.getVendorData();
-        assertTrue("Vendor Data must be an OFRoleRequestVendorData",
-                     vendorData instanceof OFRoleRequestVendorData);
-        OFRoleRequestVendorData roleRequest = (OFRoleRequestVendorData)vendorData;
-        assertEquals(nx_role, roleRequest.getRole());
-        
-        // Now verify that we've added the pending request correctly
-        // to the pending queue
-        assertEquals(1, sw.pendingRoleRequests.size());
-        PendingRoleRequestEntry pendingRoleRequest = sw.pendingRoleRequests.poll();
-        assertEquals(msg.getXid(), pendingRoleRequest.xid);
-        assertEquals(role, pendingRoleRequest.role);
-        assertEquals(cookie, pendingRoleRequest.cookie);
-        reset(sw.channel);
-    }
-    
-    @Test
-    public void testSendNxRoleRequest() throws Exception {
-        doSendNxRoleRequest(Role.MASTER, OFRoleVendorData.NX_ROLE_MASTER);
-        doSendNxRoleRequest(Role.SLAVE, OFRoleVendorData.NX_ROLE_SLAVE);
-        doSendNxRoleRequest(Role.EQUAL, OFRoleVendorData.NX_ROLE_OTHER);
-    }
-    
+    }    
     
     @Test
-    public void testDeliverRoleReplyOk() {
-        // test normal case
-        PendingRoleRequestEntry pending = new PendingRoleRequestEntry(
-                            (int)System.currentTimeMillis(),  // arbitrary xid
-                            Role.MASTER,
-                            System.nanoTime() // arbitrary cookie
-                            );
-        sw.pendingRoleRequests.add(pending);
-        replay(sw.channel);
-        sw.deliverRoleReply(pending.xid, pending.role);
-        verify(sw.channel);
+    public void testSetHARoleReplyReceived() {
+        assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+
+        sw.setHARole(Role.MASTER, true);
+        assertEquals(Role.MASTER, sw.getHARole());
         assertEquals(true, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
-        assertEquals(pending.role, sw.role);
-        assertEquals(0, sw.pendingRoleRequests.size());
-    }
-    
-    @Test
-    public void testDeliverRoleReplyOkRepeated() {
-        // test normal case. Not the first role reply
-        PendingRoleRequestEntry pending = new PendingRoleRequestEntry(
-                            (int)System.currentTimeMillis(),  // arbitrary xid
-                            Role.MASTER,
-                            System.nanoTime() // arbitrary cookie
-                            );
-        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
-        sw.pendingRoleRequests.add(pending);
-        replay(sw.channel);
-        sw.deliverRoleReply(pending.xid, pending.role);
-        verify(sw.channel);
+        
+        sw.setHARole(Role.EQUAL, true);
+        assertEquals(Role.EQUAL, sw.getHARole());
+        assertEquals(true, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+        
+        sw.setHARole(Role.SLAVE, true);
+        assertEquals(Role.SLAVE, sw.getHARole());
         assertEquals(true, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
-        assertEquals(pending.role, sw.role);
-        assertEquals(0, sw.pendingRoleRequests.size());
-    }
-    
-    @Test
-    public void testDeliverRoleReplyNonePending() {
-        // nothing pending 
-        expect(sw.channel.close()).andReturn(null);
-        replay(sw.channel);
-        sw.deliverRoleReply(1, Role.MASTER);
-        verify(sw.channel);
-        assertEquals(0, sw.pendingRoleRequests.size());
-    }
-    
-    @Test
-    public void testDeliverRoleReplyWrongXid() {
-        // wrong xid received 
-        PendingRoleRequestEntry pending = new PendingRoleRequestEntry(
-                            (int)System.currentTimeMillis(),  // arbitrary xid
-                            Role.MASTER,
-                            System.nanoTime() // arbitrary cookie
-                            );
-        sw.pendingRoleRequests.add(pending);
-        expect(sw.channel.close()).andReturn(null);
-        replay(sw.channel);
-        sw.deliverRoleReply(pending.xid+1, pending.role);
-        verify(sw.channel);
-        assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
-        assertEquals(0, sw.pendingRoleRequests.size());
     }
     
     @Test
-    public void testDeliverRoleReplyWrongRole() {
-        // correct xid but incorrect role received
-        PendingRoleRequestEntry pending = new PendingRoleRequestEntry(
-                            (int)System.currentTimeMillis(),  // arbitrary xid
-                            Role.MASTER,
-                            System.nanoTime() // arbitrary cookie
-                            );
-        sw.pendingRoleRequests.add(pending);
-        expect(sw.channel.close()).andReturn(null);
-        replay(sw.channel);
-        sw.deliverRoleReply(pending.xid, Role.SLAVE);
-        verify(sw.channel);
+    public void testSetHARoleNoReply() {
         assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
-        assertEquals(0, sw.pendingRoleRequests.size());
-    }
-    
-    @Test
-    public void testCheckFirstPendingRoleRequestXid() {
-        PendingRoleRequestEntry pending = new PendingRoleRequestEntry(
-                            54321, Role.MASTER, 232323);
-        replay(sw.channel); // we don't expect any invocations 
-        sw.pendingRoleRequests.add(pending);
-        assertEquals(true, sw.checkFirstPendingRoleRequestXid(54321));
-        assertEquals(false, sw.checkFirstPendingRoleRequestXid(0));
-        sw.pendingRoleRequests.clear();
-        assertEquals(false, sw.checkFirstPendingRoleRequestXid(54321));
-        verify(sw.channel);
-    }
-    
-    @Test
-    public void testCheckFirstPendingRoleRequestCookie() {
-        PendingRoleRequestEntry pending = new PendingRoleRequestEntry(
-                            54321, Role.MASTER, 232323);
-        replay(sw.channel); // we don't expect any invocations 
-        sw.pendingRoleRequests.add(pending);
-        assertEquals(true, sw.checkFirstPendingRoleRequestCookie(232323));
-        assertEquals(false, sw.checkFirstPendingRoleRequestCookie(0));
-        sw.pendingRoleRequests.clear();
-        assertEquals(false, sw.checkFirstPendingRoleRequestCookie(232323));
-        verify(sw.channel);
-    }
-    
-    @Test
-    public void testDeliverRoleRequestNotSupported () {
-        // normal case. xid is pending 
-        PendingRoleRequestEntry pending = new PendingRoleRequestEntry(
-                            (int)System.currentTimeMillis(),  // arbitrary xid
-                            Role.MASTER,
-                            System.nanoTime() // arbitrary cookie
-                            );
-        sw.role = Role.SLAVE;
-        sw.pendingRoleRequests.add(pending);
-        replay(sw.channel);
-        sw.deliverRoleRequestNotSupported(pending.xid);
-        verify(sw.channel);
+
+        sw.setHARole(Role.MASTER, false);
+        assertEquals(Role.MASTER, sw.getHARole());
+        assertEquals(false, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+        
+        sw.setHARole(Role.EQUAL, false);
+        assertEquals(Role.EQUAL, sw.getHARole());
+        assertEquals(false, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+        
+        sw.setHARole(Role.SLAVE, false);
+        assertEquals(Role.SLAVE, sw.getHARole());
         assertEquals(false, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
-        assertEquals(null, sw.role);
-        assertEquals(0, sw.pendingRoleRequests.size());
-    }
-    
-    @Test
-    public void testDeliverRoleRequestNotSupportedNonePending() {
-        // nothing pending 
-        sw.role = Role.SLAVE;
-        expect(sw.channel.close()).andReturn(null);
-        replay(sw.channel);
-        sw.deliverRoleRequestNotSupported(1);
-        verify(sw.channel);
-        assertEquals(null, sw.role);
-        assertEquals(0, sw.pendingRoleRequests.size());
-    }
-    
-    @Test
-    public void testDeliverRoleRequestNotSupportedWrongXid() {
-        // wrong xid received 
-        PendingRoleRequestEntry pending = new PendingRoleRequestEntry(
-                            (int)System.currentTimeMillis(),  // arbitrary xid
-                            Role.MASTER,
-                            System.nanoTime() // arbitrary cookie
-                            );
-        sw.role = Role.SLAVE;
-        sw.pendingRoleRequests.add(pending);
-        expect(sw.channel.close()).andReturn(null);
-        replay(sw.channel);
-        sw.deliverRoleRequestNotSupported(pending.xid+1);
-        verify(sw.channel);
-        assertEquals(null, sw.role);
-        assertEquals(0, sw.pendingRoleRequests.size());
     }
+
 }
diff --git a/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java b/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java
index d7d981449d95d4e934d7610232f8977c5afa025a..cb446b2a9ec19cd46d59620e8b160e5e1ef3f4a7 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/RoleChangerTest.java
@@ -1,29 +1,53 @@
 package net.floodlightcontroller.core.internal;
 
+import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
 import static org.easymock.EasyMock.verify;
 import static org.junit.Assert.*;
 
 import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
 import java.util.Collection;
 import java.util.LinkedList;
+import java.util.List;
+
+import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
+import net.floodlightcontroller.core.internal.RoleChanger.PendingRoleRequestEntry;
 import net.floodlightcontroller.core.internal.RoleChanger.RoleChangeTask;
 
+import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.jboss.netty.channel.Channel;
 import org.junit.Before;
 import org.junit.Test;
+import org.openflow.protocol.OFError;
+import org.openflow.protocol.OFError.OFErrorType;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.OFVendor;
+import org.openflow.protocol.factory.BasicFactory;
+import org.openflow.protocol.vendor.OFVendorData;
+import org.openflow.vendor.nicira.OFNiciraVendorData;
+import org.openflow.vendor.nicira.OFRoleRequestVendorData;
+import org.openflow.vendor.nicira.OFRoleVendorData;
 
 public class RoleChangerTest {
     public RoleChanger roleChanger;
+    Controller controller;
     
     @Before
     public void setUp() throws Exception {
-        roleChanger = new RoleChanger();
+        controller = createMock(Controller.class);
+        roleChanger = new RoleChanger(controller);
+        BasicFactory factory = new BasicFactory();
+        expect(controller.getOFMessageFactory()).andReturn(factory).anyTimes();
     }
     
     /**
@@ -31,22 +55,20 @@ public class RoleChangerTest {
      * The connection should be closed.
      */
     @Test
-    public void testSendRoleRequestSlaveNotSupported() {
+    public void testSendRoleRequestSlaveNotSupported() throws Exception {
         LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // a switch that doesn't support role requests
-        OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
-        Channel channel1 = createMock(Channel.class);
-        expect(sw1.getChannel()).andReturn(channel1);
+        IOFSwitch sw1 = EasyMock.createMock(IOFSwitch.class);
         // No support for NX_ROLE
         expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
-                        .andReturn(false); 
-        expect(channel1.close()).andReturn(null);
+                .andReturn(false);
+        sw1.disconnectOutputStream();
         switches.add(sw1);
         
-        replay(sw1, channel1);
+        replay(sw1);
         roleChanger.sendRoleRequest(switches, Role.SLAVE, 123456);
-        verify(sw1, channel1);
+        verify(sw1);
         
         // sendRoleRequest needs to remove the switch from the list since
         // it closed its connection
@@ -55,17 +77,18 @@ public class RoleChangerTest {
     
     /**
      * Send a role request for MASTER to a switch that doesn't support it. 
-     * The connection should be closed.
+     * The connection should stay open.
      */
     @Test
-    public void testSendRoleRequestMasterNotSupported() {
+    public void testSendRoleRequestMasterNotSupported() throws Exception {
         LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // a switch that doesn't support role requests
-        OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
+        IOFSwitch sw1 = EasyMock.createMock(IOFSwitch.class);
         // No support for NX_ROLE
         expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
-                        .andReturn(false); 
+                .andReturn(false);
+        sw1.setHARole(Role.MASTER, false);
         switches.add(sw1);
         
         replay(sw1);
@@ -76,81 +99,94 @@ public class RoleChangerTest {
     }
     
     /**
-     * Send a role request a switch that supports it and one that 
+     * Check error handling 
      * hasn't had a role request send to it yet
      */
+    @SuppressWarnings("unchecked")
     @Test
     public void testSendRoleRequestErrorHandling () throws Exception {
         LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // a switch that supports role requests
-        OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
+        IOFSwitch sw1 = EasyMock.createMock(IOFSwitch.class);
         // No support for NX_ROLE
         expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
-                        .andReturn(true); 
-        expect(sw1.sendNxRoleRequest(Role.MASTER, 123456))
-                    .andThrow(new IOException()).once();
-        Channel channel1 = createMock(Channel.class);
-        expect(sw1.getChannel()).andReturn(channel1);
-        expect(channel1.close()).andReturn(null);
+                .andReturn(true);
+        expect(sw1.getNextTransactionId()).andReturn(1);
+        sw1.write((List<OFMessage>)EasyMock.anyObject(),
+                (FloodlightContext)EasyMock.anyObject());
+        expectLastCall().andThrow(new IOException());
+        sw1.disconnectOutputStream();
         switches.add(sw1);
         
-        replay(sw1);
+        replay(sw1, controller);
         roleChanger.sendRoleRequest(switches, Role.MASTER, 123456);
-        verify(sw1);
+        verify(sw1, controller);
         
         assertTrue(switches.isEmpty());
     }
     
     /**
-     * Check error handling 
+     * Send a role request a switch that supports it and one that 
      * hasn't had a role request send to it yet
      */
+    @SuppressWarnings("unchecked")
     @Test
     public void testSendRoleRequestSupported() throws Exception {
         LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // a switch that supports role requests
-        OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
-        // No support for NX_ROLE
+        IOFSwitch sw1 = EasyMock.createMock(IOFSwitch.class);
+        // Support for NX_ROLE
         expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
-                        .andReturn(true); 
-        expect(sw1.sendNxRoleRequest(Role.MASTER, 123456)).andReturn(1).once();
+                .andReturn(true);
+        expect(sw1.getNextTransactionId()).andReturn(1);
+        sw1.write((List<OFMessage>)EasyMock.anyObject(),
+                (FloodlightContext)EasyMock.anyObject());
         switches.add(sw1);
         
-        // a switch for which we don't have SUPPORTS_NX_ROLE yet
-        OFSwitchImpl sw2 = EasyMock.createMock(OFSwitchImpl.class);
-        // No support for NX_ROLE
+        // second switch
+        IOFSwitch sw2 = EasyMock.createMock(IOFSwitch.class);
+        // No role request yet
         expect(sw2.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
-                        .andReturn(null); 
-        expect(sw2.sendNxRoleRequest(Role.MASTER, 123456)).andReturn(1).once();
-        switches.add(sw2);
+                .andReturn(null);
+        expect(sw2.getNextTransactionId()).andReturn(1);
+        sw2.write((List<OFMessage>)EasyMock.anyObject(),
+                (FloodlightContext)EasyMock.anyObject());
+        switches.add(sw2);        
         
-        
-        replay(sw1, sw2);
+        replay(sw1, sw2, controller);
         roleChanger.sendRoleRequest(switches, Role.MASTER, 123456);
-        verify(sw1, sw2);
+        verify(sw1, sw2, controller);
         
         assertEquals(2, switches.size());
     }
     
     @Test
-    public void testVerifyRoleReplyReceived() {
+    public void testVerifyRoleReplyReceived() throws Exception {
         Collection<IOFSwitch> switches = new LinkedList<IOFSwitch>();
         
         // Add a switch that has received a role reply
-        OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class);
-        expect(sw1.checkFirstPendingRoleRequestCookie(123456))
-                        .andReturn(false).once();
+        IOFSwitch sw1 = EasyMock.createMock(IOFSwitch.class);
+        LinkedList<PendingRoleRequestEntry> pendingList1 =
+                new LinkedList<PendingRoleRequestEntry>();
+        roleChanger.pendingRequestMap.put(sw1, pendingList1);
         switches.add(sw1);
         
         // Add a switch that has not yet received a role reply
-        OFSwitchImpl sw2 = EasyMock.createMock(OFSwitchImpl.class);
-        expect(sw2.checkFirstPendingRoleRequestCookie(123456))
-                        .andReturn(true).once();
-        Channel channel2 = createMock(Channel.class);
-        expect(sw2.getChannel()).andReturn(channel2);
-        expect(channel2.close()).andReturn(null);
+        IOFSwitch sw2 = EasyMock.createMock(IOFSwitch.class);
+        LinkedList<PendingRoleRequestEntry> pendingList2 =
+                new LinkedList<PendingRoleRequestEntry>();
+        roleChanger.pendingRequestMap.put(sw2, pendingList2);
+        PendingRoleRequestEntry entry =
+                new PendingRoleRequestEntry(1, Role.MASTER, 123456);
+        pendingList2.add(entry);
+        // Timed out switch should become active
+        expect(sw2.getAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA))
+                .andReturn(null);
+        expect(sw2.getHARole()).andReturn(null);
+        sw2.setHARole(Role.MASTER, false);
+        EasyMock.expectLastCall();
         switches.add(sw2);
         
         
@@ -184,50 +220,306 @@ public class RoleChangerTest {
         assertTrue( t2.compareTo(t3) > 0 );
     }
     
+    @SuppressWarnings("unchecked")
     @Test
     public void testSubmitRequest() throws Exception {
         LinkedList<IOFSwitch> switches = new LinkedList<IOFSwitch>();
-        roleChanger.timeout = 500*1000*1000; // 500 ms
+        roleChanger.timeout = 100*1000*1000; // 100 ms
         
         // a switch that supports role requests
-        OFSwitchImpl sw1 = EasyMock.createStrictMock(OFSwitchImpl.class);
-        // No support for NX_ROLE
+        IOFSwitch sw1 = EasyMock.createStrictMock(IOFSwitch.class);
+        // Support for NX_ROLE
         expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
-                        .andReturn(true); 
-        expect(sw1.sendNxRoleRequest(EasyMock.same(Role.MASTER), EasyMock.anyLong()))
-                       .andReturn(1);
+                .andReturn(true);
+        expect(sw1.getNextTransactionId()).andReturn(1);
+        sw1.write((List<OFMessage>)EasyMock.anyObject(),
+                (FloodlightContext)EasyMock.anyObject());
+        // Second request
         expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
-                        .andReturn(true); 
-        expect(sw1.sendNxRoleRequest(EasyMock.same(Role.SLAVE), EasyMock.anyLong()))
-                       .andReturn(1);
-        // The following calls happen for timeout handling:
-        expect(sw1.checkFirstPendingRoleRequestCookie(EasyMock.anyLong()))
-                        .andReturn(false);
-        expect(sw1.checkFirstPendingRoleRequestCookie(EasyMock.anyLong()))
-                        .andReturn(false);
+                .andReturn(true);
+        expect(sw1.getNextTransactionId()).andReturn(2);
+        sw1.write((List<OFMessage>)EasyMock.anyObject(),
+                (FloodlightContext)EasyMock.anyObject());
+        expect(sw1.getAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA))
+                .andReturn(null);
+        expect(sw1.getHARole()).andReturn(null);
+        sw1.setHARole(Role.MASTER, false);
+        expect(sw1.getAttribute(IOFSwitch.SWITCH_DESCRIPTION_DATA))
+                .andReturn(null);
+        expect(sw1.getHARole()).andReturn(Role.MASTER);
+        sw1.setHARole(Role.SLAVE, false);
+        // Disconnect on timing out SLAVE request
+        sw1.disconnectOutputStream();
         switches.add(sw1);
         
+        // Add to switch when timing out the MASTER request
+        controller.addSwitch(sw1, true);
         
-        replay(sw1);
+
+        replay(sw1, controller);
         roleChanger.submitRequest(switches, Role.MASTER);
         roleChanger.submitRequest(switches, Role.SLAVE);
-        // Wait until role request has been sent. 
-        // TODO: need to get rid of this sleep somehow
-        Thread.sleep(100);
-        // Now there should be exactly one timeout task pending
+        // Wait until role request has been sent.
+        synchronized (roleChanger.pendingTasks) { 
+            while (RoleChanger.RoleChangeTask.Type.TIMEOUT !=
+                     roleChanger.pendingTasks.peek().type) {
+                roleChanger.pendingTasks.wait();
+            }
+        }
+        // Now there should be exactly one timeout task pending for each request
         assertEquals(2, roleChanger.pendingTasks.size());
-        // Make sure it's indeed a timeout task
-        assertSame(RoleChanger.RoleChangeTask.Type.TIMEOUT, 
-                     roleChanger.pendingTasks.peek().type);
         // Check that RoleChanger indeed made a copy of switches collection
         assertNotSame(switches, roleChanger.pendingTasks.peek().switches);
         
         // Wait until the timeout triggers 
-        // TODO: get rid of this sleep too.
-        Thread.sleep(500);
-        assertEquals(0, roleChanger.pendingTasks.size());
-        verify(sw1);
+        synchronized (roleChanger.pendingTasks) { 
+            while (roleChanger.pendingTasks.size() != 0) {
+                roleChanger.pendingTasks.wait();
+            }
+        }
+        verify(sw1, controller);
         
     }
     
+    // Helper function
+    protected void setupPendingRoleRequest(IOFSwitch sw, int xid, Role role,
+            long cookie) {
+        LinkedList<PendingRoleRequestEntry> pendingList =
+                new LinkedList<PendingRoleRequestEntry>();
+        roleChanger.pendingRequestMap.put(sw, pendingList);
+        PendingRoleRequestEntry entry =
+                new PendingRoleRequestEntry(xid, role, cookie);
+        pendingList.add(entry);
+    }
+    
+
+    @Test
+    public void testDeliverRoleReplyOk() {
+        // test normal case
+        int xid = (int) System.currentTimeMillis();
+        long cookie = System.nanoTime();
+        Role role = Role.MASTER;
+        OFSwitchImpl sw = new OFSwitchImpl();
+        setupPendingRoleRequest(sw, xid, role, cookie);
+        roleChanger.deliverRoleReply(sw, xid, role);
+        assertEquals(true, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+        assertEquals(role, sw.getHARole());
+        assertEquals(0, roleChanger.pendingRequestMap.get(sw).size());
+    }
+    
+    @Test
+    public void testDeliverRoleReplyOkRepeated() {
+        // test normal case. Not the first role reply
+        int xid = (int) System.currentTimeMillis();
+        long cookie = System.nanoTime();
+        Role role = Role.MASTER;
+        OFSwitchImpl sw = new OFSwitchImpl();
+        setupPendingRoleRequest(sw, xid, role, cookie);
+        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
+        roleChanger.deliverRoleReply(sw, xid, role);
+        assertEquals(true, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+        assertEquals(role, sw.getHARole());
+        assertEquals(0, roleChanger.pendingRequestMap.get(sw).size());
+    }
+    
+    @Test
+    public void testDeliverRoleReplyNonePending() {
+        // nothing pending 
+        OFSwitchImpl sw = new OFSwitchImpl();
+        Channel ch = createMock(Channel.class);
+        SocketAddress sa = new InetSocketAddress(42);
+        expect(ch.getRemoteAddress()).andReturn(sa).anyTimes();
+        sw.setChannel(ch);
+        roleChanger.deliverRoleReply(sw, 1, Role.MASTER);
+        assertEquals(null, sw.getHARole());
+    }
+    
+    @Test
+    public void testDeliverRoleReplyWrongXid() {
+        // wrong xid received 
+        int xid = (int) System.currentTimeMillis();
+        long cookie = System.nanoTime();
+        Role role = Role.MASTER;
+        OFSwitchImpl sw = new OFSwitchImpl();
+        setupPendingRoleRequest(sw, xid, role, cookie);
+        Channel ch = createMock(Channel.class);
+        SocketAddress sa = new InetSocketAddress(42);
+        expect(ch.getRemoteAddress()).andReturn(sa).anyTimes();
+        sw.setChannel(ch);
+        expect(ch.close()).andReturn(null);
+        replay(ch);
+        roleChanger.deliverRoleReply(sw, xid+1, role);
+        verify(ch);
+        assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+        assertEquals(0, roleChanger.pendingRequestMap.get(sw).size());
+    }
+    
+    @Test
+    public void testDeliverRoleReplyWrongRole() {
+        // correct xid but incorrect role received
+        int xid = (int) System.currentTimeMillis();
+        long cookie = System.nanoTime();
+        Role role = Role.MASTER;
+        OFSwitchImpl sw = new OFSwitchImpl();
+        setupPendingRoleRequest(sw, xid, role, cookie);
+        Channel ch = createMock(Channel.class);
+        SocketAddress sa = new InetSocketAddress(42);
+        expect(ch.getRemoteAddress()).andReturn(sa).anyTimes();
+        sw.setChannel(ch);
+        expect(ch.close()).andReturn(null);
+        replay(ch);
+        roleChanger.deliverRoleReply(sw, xid, Role.SLAVE);
+        verify(ch);
+        assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+        assertEquals(0, roleChanger.pendingRequestMap.get(sw).size());
+    }
+    
+    @Test
+    public void testCheckFirstPendingRoleRequestXid() {
+        int xid = 54321;
+        long cookie = 232323;
+        Role role = Role.MASTER;
+        OFSwitchImpl sw = new OFSwitchImpl();
+        setupPendingRoleRequest(sw, xid, role, cookie);
+        assertEquals(true,
+                roleChanger.checkFirstPendingRoleRequestXid(sw, xid));
+        assertEquals(false,
+                roleChanger.checkFirstPendingRoleRequestXid(sw, 0));
+        roleChanger.pendingRequestMap.get(sw).clear();
+        assertEquals(false,
+                roleChanger.checkFirstPendingRoleRequestXid(sw, xid));
+    }
+    
+    @Test
+    public void testCheckFirstPendingRoleRequestCookie() {
+        int xid = 54321;
+        long cookie = 232323;
+        Role role = Role.MASTER;
+        OFSwitchImpl sw = new OFSwitchImpl();
+        setupPendingRoleRequest(sw, xid, role, cookie);
+        assertNotSame(null,
+                roleChanger.checkFirstPendingRoleRequestCookie(sw, cookie));
+        assertEquals(null,
+                roleChanger.checkFirstPendingRoleRequestCookie(sw, 0));
+        roleChanger.pendingRequestMap.get(sw).clear();
+        assertEquals(null,
+                roleChanger.checkFirstPendingRoleRequestCookie(sw, cookie));
+    }
+    
+    @Test
+    public void testDeliverRoleRequestError() {
+        // normal case. xid is pending 
+        int xid = (int) System.currentTimeMillis();
+        long cookie = System.nanoTime();
+        Role role = Role.MASTER;
+        OFSwitchImpl sw = new OFSwitchImpl();
+        Channel ch = createMock(Channel.class);
+        SocketAddress sa = new InetSocketAddress(42);
+        expect(ch.getRemoteAddress()).andReturn(sa).anyTimes();
+        sw.setChannel(ch);
+        setupPendingRoleRequest(sw, xid, role, cookie);
+        OFError error = new OFError();
+        error.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
+        error.setXid(xid);
+        replay(ch);
+        roleChanger.deliverRoleRequestError(sw, error);
+        verify(ch);
+        assertEquals(false, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+        assertEquals(role, sw.getHARole());
+        assertEquals(0, roleChanger.pendingRequestMap.get(sw).size());
+    }
+    
+    @Test
+    public void testDeliverRoleRequestErrorNonePending() {
+        // nothing pending 
+        OFSwitchImpl sw = new OFSwitchImpl();
+        Channel ch = createMock(Channel.class);
+        SocketAddress sa = new InetSocketAddress(42);
+        expect(ch.getRemoteAddress()).andReturn(sa).anyTimes();
+        sw.setChannel(ch);
+        OFError error = new OFError();
+        error.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
+        error.setXid(1);
+        replay(ch);
+        roleChanger.deliverRoleRequestError(sw, error);
+        verify(ch);
+        assertEquals(null, sw.getHARole());
+    }
+    
+    @Test
+    public void testDeliverRoleRequestErrorWrongXid() {
+        // wrong xid received 
+        // wrong xid received 
+        int xid = (int) System.currentTimeMillis();
+        long cookie = System.nanoTime();
+        Role role = Role.MASTER;
+        OFSwitchImpl sw = new OFSwitchImpl();
+        setupPendingRoleRequest(sw, xid, role, cookie);
+        Channel ch = createMock(Channel.class);
+        SocketAddress sa = new InetSocketAddress(42);
+        expect(ch.getRemoteAddress()).andReturn(sa).anyTimes();
+        expect(ch.close()).andReturn(null);
+        sw.setChannel(ch);
+        replay(ch);
+        OFError error = new OFError();
+        error.setErrorCode(OFError.OFErrorType.OFPET_BAD_REQUEST.getValue());
+        error.setXid(xid + 1);
+        roleChanger.deliverRoleRequestError(sw, error);
+        verify(ch);
+        assertEquals(null, sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE));
+        assertEquals(1, roleChanger.pendingRequestMap.get(sw).size());
+    }
+    
+    public void doSendNxRoleRequest(Role role, int nx_role) throws Exception {
+        long cookie = System.nanoTime();
+        OFSwitchImpl sw = new OFSwitchImpl();
+        Channel ch = createMock(Channel.class);
+        sw.setChannel(ch);
+        sw.setFloodlightProvider(controller);
+        
+        // verify that the correct OFMessage is sent
+        Capture<List<OFMessage>> msgCapture = new Capture<List<OFMessage>>();
+        // expect(sw.channel.getRemoteAddress()).andReturn(null);
+        controller.handleOutgoingMessage(
+                (IOFSwitch)EasyMock.anyObject(),
+                (OFMessage)EasyMock.anyObject(),
+                (FloodlightContext)EasyMock.anyObject());
+        expect(ch.write(capture(msgCapture))).andReturn(null);
+        replay(ch, controller);
+        int xid = roleChanger.sendHARoleRequest(sw, role, cookie);
+        verify(ch, controller);
+        List<OFMessage> msgList = msgCapture.getValue();
+        assertEquals(1, msgList.size());
+        OFMessage msg = msgList.get(0);
+        assertEquals("Transaction Ids must match", xid, msg.getXid()); 
+        assertTrue("Message must be an OFVendor type", msg instanceof OFVendor);
+        assertEquals(OFType.VENDOR, msg.getType());
+        OFVendor vendorMsg = (OFVendor)msg;
+        assertEquals("Vendor message must be vendor Nicira",
+                     OFNiciraVendorData.NX_VENDOR_ID, vendorMsg.getVendor());
+        OFVendorData vendorData = vendorMsg.getVendorData();
+        assertTrue("Vendor Data must be an OFRoleRequestVendorData",
+                     vendorData instanceof OFRoleRequestVendorData);
+        OFRoleRequestVendorData roleRequest = (OFRoleRequestVendorData)vendorData;
+        assertEquals(nx_role, roleRequest.getRole());
+        
+        reset(ch);
+    }
+    
+    @Test
+    public void testSendNxRoleRequestMaster() throws Exception {
+        doSendNxRoleRequest(Role.MASTER, OFRoleVendorData.NX_ROLE_MASTER);
+    }
+    
+    @Test
+    public void testSendNxRoleRequestSlave() throws Exception {
+        doSendNxRoleRequest(Role.SLAVE, OFRoleVendorData.NX_ROLE_SLAVE);
+    }
+
+    @Test
+    public void testSendNxRoleRequestEqual() throws Exception {
+        doSendNxRoleRequest(Role.EQUAL, OFRoleVendorData.NX_ROLE_OTHER);
+    }
+
+
 }
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index 430a1bdfafbbbe4bcac775af9fb0ed1a99b6cabe..91e640d9e716dbac87c9c57db9ed8d90cdf7565d 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -18,7 +18,20 @@
 package net.floodlightcontroller.devicemanager.internal;
 
 
-import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.anyLong;
+import static org.easymock.EasyMock.anyShort;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.or;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -31,18 +44,17 @@ import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
-import static org.easymock.EasyMock.expectLastCall;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.test.MockFloodlightProvider;
 import net.floodlightcontroller.core.test.MockThreadPoolService;
-import net.floodlightcontroller.devicemanager.IDeviceListener;
 import net.floodlightcontroller.devicemanager.IDevice;
+import net.floodlightcontroller.devicemanager.IDeviceListener;
+import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.devicemanager.IEntityClass;
 import net.floodlightcontroller.devicemanager.IEntityClassifierService;
 import net.floodlightcontroller.devicemanager.SwitchPort;
-import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus;
 import net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl.ClassState;
 import net.floodlightcontroller.devicemanager.test.MockEntityClassifier;
@@ -61,15 +73,14 @@ import net.floodlightcontroller.storage.memory.MemoryStorageSource;
 import net.floodlightcontroller.test.FloodlightTestCase;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.topology.ITopologyService;
-import static org.junit.Assert.*;
 
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFPacketIn.OFPacketInReason;
 import org.openflow.protocol.OFPhysicalPort;
 import org.openflow.protocol.OFType;
-import org.openflow.protocol.OFPacketIn.OFPacketInReason;
 import org.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -102,6 +113,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         return mockSwitch;
     }
 
+    @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
@@ -422,6 +434,48 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         verify(mockListener);
     }
     
+    
+    private void doTestEntityOrdering(boolean computeInsertionPoint) throws Exception {
+        Entity e = new Entity(10L, null, null, null, null, null);
+        IEntityClass ec = createNiceMock(IEntityClass.class);
+        Device d = new Device(deviceManager, 1L, e, ec);
+        
+        int expectedLength = 1;
+        Long[] macs = new Long[] {  5L,  // new first element
+                                   15L,  // new last element
+                                    7L,  // insert in middle
+                                   12L,  // insert in middle
+                                    6L,  // insert at idx 1
+                                   14L,  // insert at idx length-2
+                                    1L,
+                                   20L
+                                  };
+        
+        for (Long mac: macs) {
+            e = new Entity(mac, null, null, null, null, null);
+            int insertionPoint;
+            if (computeInsertionPoint) {
+                insertionPoint = -(Arrays.binarySearch(d.entities, e)+1);
+            } else {
+                insertionPoint = -1;
+            }
+            d = deviceManager.allocateDevice(d, e, insertionPoint);
+            expectedLength++;
+            assertEquals(expectedLength, d.entities.length);
+            for (int i = 0; i < d.entities.length-1; i++)
+                assertEquals(-1, d.entities[i].compareTo(d.entities[i+1]));
+        }
+    }
+    
+    @Test
+    public void testEntityOrderingExternal() throws Exception {
+        doTestEntityOrdering(true);
+    }
+    
+    @Test
+    public void testEntityOrderingInternal() throws Exception {
+        doTestEntityOrdering(false);
+    }
 
     @Test
     public void testAttachmentPointLearning() throws Exception {
@@ -525,11 +579,131 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         assertArrayEquals(new Integer[] { 1 }, ips);
         verify(mockListener);
     }
+    
+    private void verifyEntityArray(Entity[] expected, Device d) {
+        Arrays.sort(expected);
+        assertArrayEquals(expected, d.entities);
+    }
+    
+    @Test
+    public void testNoLearningOnInternalPorts() throws Exception {
+        IDeviceListener mockListener =
+                createMock(IDeviceListener.class);
+
+        deviceManager.addListener(mockListener);
 
+        ITopologyService mockTopology = createMock(ITopologyService.class);
+        expect(mockTopology.getL2DomainId(1L)).
+        andReturn(1L).anyTimes();
+        expect(mockTopology.getL2DomainId(2L)).
+        andReturn(1L).anyTimes();
+        expect(mockTopology.getL2DomainId(3L)).
+        andReturn(1L).anyTimes();
+        expect(mockTopology.getL2DomainId(4L)).
+        andReturn(1L).anyTimes();
+        expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort()))
+                .andReturn(false).anyTimes();
+        expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(),
+                                                    anyLong(), anyShort()))
+                .andReturn(false).anyTimes();
+
+        expect(mockTopology.isAttachmentPointPort(or(eq(1L), eq(3L)), anyShort()))
+                .andReturn(true).anyTimes();
+        // Switches 2 and 4 have only internal ports
+        expect(mockTopology.isAttachmentPointPort(or(eq(2L), eq(4L)), anyShort()))
+                .andReturn(false).anyTimes();
+        
+        expect(mockTopology.isConsistent(1L, (short)1, 3L, (short)1))
+                .andReturn(false).once();
+
+        Date topologyUpdateTime = new Date();
+        expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
+        anyTimes();
+
+        replay(mockTopology);
+
+        deviceManager.topology = mockTopology;
+
+        Calendar c = Calendar.getInstance();
+        Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime());
+        c.add(Calendar.SECOND, 1);
+        Entity entity2 = new Entity(1L, null, 2, 2L, 1, c.getTime());
+        c.add(Calendar.SECOND, 1);
+        Entity entity3 = new Entity(1L, null, 3, 3L, 1, c.getTime());
+        c.add(Calendar.SECOND, 1);
+        Entity entity4 = new Entity(1L, null, 4, 4L, 1, c.getTime());
+
+        IDevice d;
+        SwitchPort[] aps;
+        Integer[] ips;
+
+        mockListener.deviceAdded(isA(IDevice.class));
+        expectLastCall().once();
+        replay(mockListener);
+        
+        // cannot learn device internal ports
+        d = deviceManager.learnDeviceByEntity(entity2);
+        assertNull(d);
+        d = deviceManager.learnDeviceByEntity(entity4);
+        assertNull(d);
+        
+        d = deviceManager.learnDeviceByEntity(entity1);
+        assertEquals(1, deviceManager.getAllDevices().size());
+        aps = d.getAttachmentPoints();
+        assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps);
+        verifyEntityArray(new Entity[] { entity1 } , (Device)d);
+        ips = d.getIPv4Addresses();
+        assertArrayEquals(new Integer[] { 1 }, ips);
+        verify(mockListener);
+        
+        reset(mockListener);
+        replay(mockListener);
+        
+        // don't learn
+        d = deviceManager.learnDeviceByEntity(entity2);
+        assertEquals(1, deviceManager.getAllDevices().size());
+        aps = d.getAttachmentPoints();
+        assertArrayEquals(new SwitchPort[] { new SwitchPort(1L, 1) }, aps);
+        verifyEntityArray(new Entity[] { entity1 } , (Device)d);
+        ips = d.getIPv4Addresses();
+        assertArrayEquals(new Integer[] { 1 }, ips);
+        verify(mockListener);
+        
+        reset(mockListener);
+        mockListener.deviceMoved(isA(IDevice.class));
+        mockListener.deviceIPV4AddrChanged(isA(IDevice.class));
+        replay(mockListener);
+        
+        // learn
+        d = deviceManager.learnDeviceByEntity(entity3);
+        assertEquals(1, deviceManager.getAllDevices().size());
+        aps = d.getAttachmentPoints();
+        assertArrayEquals(new SwitchPort[] { new SwitchPort(3L, 1) }, aps);
+        verifyEntityArray(new Entity[] { entity1, entity3 } , (Device)d);
+        ips = d.getIPv4Addresses();
+        Arrays.sort(ips);
+        assertArrayEquals(new Integer[] { 1, 3 }, ips);
+        verify(mockListener);
+        
+        reset(mockListener);
+        replay(mockListener);
+        
+        // don't learn
+        d = deviceManager.learnDeviceByEntity(entity4);
+        assertEquals(1, deviceManager.getAllDevices().size());
+        aps = d.getAttachmentPoints();
+        assertArrayEquals(new SwitchPort[] { new SwitchPort(3L, 1) }, aps);
+        verifyEntityArray(new Entity[] { entity1, entity3 } , (Device)d);
+        ips = d.getIPv4Addresses();
+        Arrays.sort(ips);
+        assertArrayEquals(new Integer[] { 1, 3 }, ips);
+        verify(mockListener);
+    }
+    
     @Test
     public void testAttachmentPointSuppression() throws Exception {
         IDeviceListener mockListener =
-                createStrictMock(IDeviceListener.class);
+                createMock(IDeviceListener.class);
 
         deviceManager.addListener(mockListener);
 
@@ -542,15 +716,16 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         andReturn(10L).anyTimes();
         expect(mockTopology.getL2DomainId(50L)).
         andReturn(10L).anyTimes();
-        expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())).
-        andReturn(false).anyTimes();
+        expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort()))
+                .andReturn(false).anyTimes();
         expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(),
-                                                    anyLong(), anyShort())).andReturn(false).anyTimes();
+                                                    anyLong(), anyShort()))
+                .andReturn(false).anyTimes();
 
-        expect(mockTopology.isAttachmentPointPort(anyLong(),
-                                                  anyShort())).andReturn(true).anyTimes();
-        expect(mockTopology.isConsistent(5L, (short)1, 50L, (short)1)).
-        andReturn(false).anyTimes();
+        expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort()))
+                .andReturn(true).anyTimes();
+        expect(mockTopology.isConsistent(5L, (short)1, 50L, (short)1))
+                .andReturn(false).anyTimes();
 
         Date topologyUpdateTime = new Date();
         expect(mockTopology.getLastUpdateTime()).andReturn(topologyUpdateTime).
@@ -564,10 +739,10 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         deviceManager.addSuppressAPs(10L, (short)1);
 
         Calendar c = Calendar.getInstance();
-        Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime());
         Entity entity0 = new Entity(1L, null, null, null, null, c.getTime());
+        Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime());
         c.add(Calendar.SECOND, 1);
-        Entity entity2 = new Entity(1L, null, null, 5L, 1, c.getTime());
+        Entity entity2 = new Entity(1L, null, 1, 5L, 1, c.getTime());
         c.add(Calendar.SECOND, 1);
         Entity entity3 = new Entity(1L, null, null, 10L, 1, c.getTime());
         c.add(Calendar.SECOND, 1);
@@ -578,40 +753,49 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         Integer[] ips;
 
         mockListener.deviceAdded(isA(IDevice.class));
+        mockListener.deviceIPV4AddrChanged((isA(IDevice.class)));
         replay(mockListener);
+        
+        // TODO: we currently do learn entities on suppressed APs
+        // // cannot learn device on suppressed AP
+        // d = deviceManager.learnDeviceByEntity(entity1);
+        // assertNull(d);
 
-        deviceManager.learnDeviceByEntity(entity1);
-        d = deviceManager.learnDeviceByEntity(entity0);
+        deviceManager.learnDeviceByEntity(entity0);
+        d = deviceManager.learnDeviceByEntity(entity1);
         assertEquals(1, deviceManager.getAllDevices().size());
         aps = d.getAttachmentPoints();
         assertEquals(aps.length, 0);
+        verifyEntityArray(new Entity[] { entity0, entity1} , (Device)d);
         ips = d.getIPv4Addresses();
         assertArrayEquals(new Integer[] { 1 }, ips);
         verify(mockListener);
 
         reset(mockListener);
         mockListener.deviceMoved((isA(IDevice.class)));
+        //mockListener.deviceIPV4AddrChanged((isA(IDevice.class)));
         replay(mockListener);
 
         d = deviceManager.learnDeviceByEntity(entity2);
         assertEquals(1, deviceManager.getAllDevices().size());
         aps = d.getAttachmentPoints();
         assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps);
+        verifyEntityArray(new Entity[] { entity0, entity1, entity2 } , (Device)d);
         ips = d.getIPv4Addresses();
         assertArrayEquals(new Integer[] { 1 }, ips);
         verify(mockListener);
 
         reset(mockListener);
-        mockListener.deviceMoved((isA(IDevice.class)));
         replay(mockListener);
 
         d = deviceManager.learnDeviceByEntity(entity3);
         assertEquals(1, deviceManager.getAllDevices().size());
         aps = d.getAttachmentPoints();
         assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1) }, aps);
+        verifyEntityArray(new Entity[] { entity0, entity1, entity2, entity3 } , (Device)d);
         ips = d.getIPv4Addresses();
         assertArrayEquals(new Integer[] { 1 }, ips);
-        //verify(mockListener);  // There is no device movement here; no not needed.
+        verify(mockListener);
 
         reset(mockListener);
         mockListener.deviceMoved((isA(IDevice.class)));
@@ -622,6 +806,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         aps = d.getAttachmentPoints();
         assertArrayEquals(new SwitchPort[] { new SwitchPort(5L, 1),
                                              new SwitchPort(50L, 1) }, aps);
+        verifyEntityArray(new Entity[] { entity0, entity1, entity2, entity3, entity4} , (Device)d);
         ips = d.getIPv4Addresses();
         assertArrayEquals(new Integer[] { 1 }, ips);
         verify(mockListener);
@@ -754,7 +939,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
                                       ipaddr,
                                       5L,
                                       2,
-                                      currentDate));
+                                      currentDate),
+                                      -1);
 
         reset(mockTopology);
         expect(mockTopology.isAttachmentPointPort(anyLong(),
@@ -837,7 +1023,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
                                                 null, null, 1, null, null);
         assertTrue(diter.hasNext());
         assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
-        diter = deviceManager.queryClassDevices(d.getEntityClass(), 
+        diter = deviceManager.queryClassDevices(d.getEntityClass(),
                                                 null, null, 2, null, null);
         assertTrue(diter.hasNext());
         assertEquals(d.getDeviceKey(), diter.next().getDeviceKey());
@@ -924,12 +1110,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
     }
     
     /*
-     * A ConcurrentHashMap for devices (deviceMap) that can be used to test 
+     * A ConcurrentHashMap for devices (deviceMap) that can be used to test
      * code that specially handles concurrent modification situations. In
      * particular, we overwrite values() and will replace / remove all the
-     * elements returned by values. 
+     * elements returned by values.
      * 
-     * The remove flag in the constructor specifies if devices returned by 
+     * The remove flag in the constructor specifies if devices returned by
      * values() should be removed or replaced.
      */
     protected static class ConcurrentlyModifiedDeviceMap
@@ -948,15 +1134,15 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
             Collection<Device> devs = new ArrayList<Device>(super.values());
             for (Device d: devs) {
                 if (remove) {
-                    // We remove the device from the underlying map 
+                    // We remove the device from the underlying map
                     super.remove(d.getDeviceKey());
                 } else {
                     super.remove(d.getDeviceKey());
                     // We add a different Device instance with the same
                     // key to the map. We'll do some hackery so the device
-                    // is different enough to compare differently in equals 
+                    // is different enough to compare differently in equals
                     // but otherwise looks the same.
-                    // It's ugly but it works. 
+                    // It's ugly but it works.
                     Entity[] curEntities = new Entity[d.getEntities().length];
                     int i = 0;
                     // clone entities
@@ -967,19 +1153,19 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
                                                      e.switchDPID,
                                                      e.switchPort,
                                                      e.lastSeenTimestamp);
-                        if (e.vlan == null) 
+                        if (e.vlan == null)
                             curEntities[i].vlan = (short)1;
-                        else 
+                        else
                             curEntities[i].vlan = (short)((e.vlan + 1 % 4095)+1);
                         i++;
                     }
-                    Device newDevice = new Device(d, curEntities[0]);
+                    Device newDevice = new Device(d, curEntities[0], -1);
                     newDevice.entities = curEntities;
                     assertEquals(false, newDevice.equals(d));
                     super.put(newDevice.getDeviceKey(), newDevice);
                 }
             }
-            return devs; 
+            return devs;
         }
     }
    
@@ -994,7 +1180,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
     }
     
     /* Test correct entity cleanup behavior when a concurrent modification
-     * occurs. 
+     * occurs.
      */
     @Test
     public void testEntityExpirationConcurrentModification() throws Exception {
@@ -1003,7 +1189,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
     }
     
     /* Test correct entity cleanup behavior when a concurrent remove
-     * occurs. 
+     * occurs.
      */
     @Test
     public void testDeviceExpirationConcurrentRemove() throws Exception {
@@ -1012,7 +1198,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
     }
     
     /* Test correct entity cleanup behavior when a concurrent modification
-     * occurs. 
+     * occurs.
      */
     @Test
     public void testDeviceExpirationConcurrentModification() throws Exception {
@@ -1415,31 +1601,31 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         
         // Look up the device using findDevice() which uses only the primary
         // index
-        assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(), 
+        assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(),
                                                   entity1.getVlan(),
                                                   entity1.getIpv4Address(),
                                                   entity1.getSwitchDPID(),
                                                   entity1.getSwitchPort()));
         // port changed. Device will be found through class index
-        assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(), 
+        assertEquals(d1, deviceManager.findDevice(entity1.getMacAddress(),
                                                   entity1.getVlan(),
                                                   entity1.getIpv4Address(),
                                                   entity1.getSwitchDPID(),
                                                   entity1.getSwitchPort()+1));
         // VLAN changed. No device matches
-        assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(), 
+        assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(),
                                                   (short)42,
                                                   entity1.getIpv4Address(),
                                                   entity1.getSwitchDPID(),
                                                   entity1.getSwitchPort()));
-        assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(), 
+        assertEquals(null, deviceManager.findDevice(entity1.getMacAddress(),
                                                   null,
                                                   entity1.getIpv4Address(),
                                                   entity1.getSwitchDPID(),
                                                   entity1.getSwitchPort()));
         assertEquals(d2, deviceManager.findDeviceByEntity(entity2));
         assertEquals(null, deviceManager.findDeviceByEntity(entity2b));
-        assertEquals(d3, deviceManager.findDevice(entity3.getMacAddress(), 
+        assertEquals(d3, deviceManager.findDevice(entity3.getMacAddress(),
                                                   entity3.getVlan(),
                                                   entity3.getIpv4Address(),
                                                   entity3.getSwitchDPID(),
@@ -1447,33 +1633,33 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         // switch and port not set. throws exception
         exceptionCaught = false;
         try {
-            assertEquals(null, deviceManager.findDevice(entity3.getMacAddress(), 
+            assertEquals(null, deviceManager.findDevice(entity3.getMacAddress(),
                                                         entity3.getVlan(),
                                                         entity3.getIpv4Address(),
                                                         null,
                                                         null));
-        } 
+        }
         catch (IllegalArgumentException e) {
             exceptionCaught = true;
         }
         if (!exceptionCaught)
             fail("findDevice() did not throw IllegalArgumentException");
         assertEquals(d4, deviceManager.findDeviceByEntity(entity4));
-        assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(), 
+        assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(),
                                                   entity5.getVlan(),
                                                   entity5.getIpv4Address(),
                                                   entity5.getSwitchDPID(),
                                                   entity5.getSwitchPort()));
-        // switch and port not set. throws exception (swith/port are key 
+        // switch and port not set. throws exception (swith/port are key
         // fields of IEntityClassifier but not d5.entityClass
         exceptionCaught = false;
         try {
-            assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(), 
+            assertEquals(d5, deviceManager.findDevice(entity5.getMacAddress(),
                                                       entity5.getVlan(),
                                                       entity5.getIpv4Address(),
                                                       null,
                                                       null));
-        } 
+        }
         catch (IllegalArgumentException e) {
             exceptionCaught = true;
         }
@@ -1486,16 +1672,16 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         
         
         // Now look up destination devices
-        assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), 
-                                                  entity1.getMacAddress(), 
+        assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(),
+                                                  entity1.getMacAddress(),
                                                   entity1.getVlan(),
                                                   entity1.getIpv4Address()));
-        assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(), 
-                                                  entity1.getMacAddress(), 
+        assertEquals(d1, deviceManager.findClassDevice(d2.getEntityClass(),
+                                                  entity1.getMacAddress(),
                                                   entity1.getVlan(),
                                                   null));
-        assertEquals(null, deviceManager.findClassDevice(d2.getEntityClass(), 
-                                                  entity1.getMacAddress(), 
+        assertEquals(null, deviceManager.findClassDevice(d2.getEntityClass(),
+                                                  entity1.getMacAddress(),
                                                   (short) -1,
                                                   0));
     }
@@ -1620,7 +1806,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
             Entity entity2 = new Entity(1L, null, null, 10L, 1, new Date());
             Entity entity3 = new Entity(1L, (short)3, null,  1L, 1, new Date());
             Entity entity4 = new Entity(1L, (short)42, null,  1L, 1, new Date());
-            Entity[] entities = new Entity[] { entity1, entity2, 
+            Entity[] entities = new Entity[] { entity1, entity2,
                                                entity3, entity4
                                              };
             Device d = new Device(null,1L, null, null, Arrays.asList(entities), null);
@@ -1628,9 +1814,9 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
             SwitchPort swp1x2 = new SwitchPort(1L, 2);
             SwitchPort swp2x1 = new SwitchPort(2L, 1);
             SwitchPort swp10x1 = new SwitchPort(10L, 1);
-            assertArrayEquals(new Short[] { -1, 1}, 
+            assertArrayEquals(new Short[] { -1, 1},
                               d.getSwitchPortVlanIds(swp10x1));
-            assertArrayEquals(new Short[] { 3, 42}, 
+            assertArrayEquals(new Short[] { 3, 42},
                               d.getSwitchPortVlanIds(swp1x1));
             assertArrayEquals(new Short[0],
                               d.getSwitchPortVlanIds(swp1x2));
@@ -1640,8 +1826,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
     
     @Test
     public void testReclassifyDevice() {
-    	MockFlexEntityClassifier flexClassifier = 
-    			new MockFlexEntityClassifier();
+        MockFlexEntityClassifier flexClassifier =
+                new MockFlexEntityClassifier();
         deviceManager.entityClassifier= flexClassifier;
         deviceManager.startUp(null);
 
@@ -1676,22 +1862,22 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         Device d1b = deviceManager.learnDeviceByEntity(entity1b);
         Device d2b = deviceManager.learnDeviceByEntity(entity2b);
         
-        d1 = deviceManager.getDeviceIteratorForQuery(entity1.getMacAddress(), 
-        				entity1.getVlan(), entity1.getIpv4Address(), 
-        				entity1.getSwitchDPID(), entity1.getSwitchPort())
-        				.next();
-        d1b = deviceManager.getDeviceIteratorForQuery(entity1b.getMacAddress(), 
-				entity1b.getVlan(), entity1b.getIpv4Address(), 
-				entity1b.getSwitchDPID(), entity1b.getSwitchPort()).next();
+        d1 = deviceManager.getDeviceIteratorForQuery(entity1.getMacAddress(),
+                        entity1.getVlan(), entity1.getIpv4Address(),
+                        entity1.getSwitchDPID(), entity1.getSwitchPort())
+                        .next();
+        d1b = deviceManager.getDeviceIteratorForQuery(entity1b.getMacAddress(),
+                entity1b.getVlan(), entity1b.getIpv4Address(),
+                entity1b.getSwitchDPID(), entity1b.getSwitchPort()).next();
         
         assertEquals(d1, d1b);
         
-        d2 = deviceManager.getDeviceIteratorForQuery(entity2.getMacAddress(), 
-				entity2.getVlan(), entity2.getIpv4Address(), 
-				entity2.getSwitchDPID(), entity2.getSwitchPort()).next();
-        d2b = deviceManager.getDeviceIteratorForQuery(entity2b.getMacAddress(), 
-				entity2b.getVlan(), entity2b.getIpv4Address(), 
-				entity2b.getSwitchDPID(), entity2b.getSwitchPort()).next();
+        d2 = deviceManager.getDeviceIteratorForQuery(entity2.getMacAddress(),
+                entity2.getVlan(), entity2.getIpv4Address(),
+                entity2.getSwitchDPID(), entity2.getSwitchPort()).next();
+        d2b = deviceManager.getDeviceIteratorForQuery(entity2b.getMacAddress(),
+                entity2b.getVlan(), entity2b.getIpv4Address(),
+                entity2b.getSwitchDPID(), entity2b.getSwitchPort()).next();
         assertEquals(d2, d2b);
         
         IEntityClass eC1 = flexClassifier.createTestEntityClass("C1");
@@ -1704,31 +1890,31 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         deviceManager.reclassifyDevice(d2);
         
         d1 = deviceManager.deviceMap.get(
-        		deviceManager.primaryIndex.findByEntity(entity1));
+                deviceManager.primaryIndex.findByEntity(entity1));
         d1b = deviceManager.deviceMap.get(
-        		deviceManager.primaryIndex.findByEntity(entity1b));
+                deviceManager.primaryIndex.findByEntity(entity1b));
         
         assertEquals(d1, d1b);
         
         d2 = deviceManager.deviceMap.get(
-        		deviceManager.primaryIndex.findByEntity(entity2));
+                deviceManager.primaryIndex.findByEntity(entity2));
         d2b = deviceManager.deviceMap.get(
-        		deviceManager.primaryIndex.findByEntity(entity2b));
+                deviceManager.primaryIndex.findByEntity(entity2b));
         
         assertEquals(d2, d2b);
-        				
+                        
         flexClassifier.addVlanEntities((short)1, eC2);
         
         deviceManager.reclassifyDevice(d1);
         deviceManager.reclassifyDevice(d2);
         d1 = deviceManager.deviceMap.get(
-        		deviceManager.primaryIndex.findByEntity(entity1));
+                deviceManager.primaryIndex.findByEntity(entity1));
         d1b = deviceManager.deviceMap.get(
-        		deviceManager.primaryIndex.findByEntity(entity1b));
+                deviceManager.primaryIndex.findByEntity(entity1b));
         d2 = deviceManager.deviceMap.get(
-        		deviceManager.primaryIndex.findByEntity(entity2));
+                deviceManager.primaryIndex.findByEntity(entity2));
         d2b = deviceManager.deviceMap.get(
-        		deviceManager.primaryIndex.findByEntity(entity2b));
+                deviceManager.primaryIndex.findByEntity(entity2b));
         
         assertNotSame(d1, d1b);
        
@@ -1745,13 +1931,13 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         Long deviceKey2b = null;
 
         deviceKey1 =
-        		classState.classIndex.findByEntity(entity1);
+                classState.classIndex.findByEntity(entity1);
         deviceKey1b =
-        		classState.classIndex.findByEntity(entity1b);
+                classState.classIndex.findByEntity(entity1b);
         deviceKey2 =
-        		classState.classIndex.findByEntity(entity2);
+                classState.classIndex.findByEntity(entity2);
         deviceKey2b =
-        		classState.classIndex.findByEntity(entity2b);
+                classState.classIndex.findByEntity(entity2b);
 
         assertEquals(deviceKey1, deviceKey1b);
         
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java
index 5460ea3a91f42c22065ecaca793ba8b23ece87f8..1c2f7d1b492558f1cff859e6a75e228eff891ce1 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDevice.java
@@ -42,8 +42,8 @@ public class MockDevice extends Device {
         super(deviceManager, deviceKey, entity, entityClass);
     }
 
-    public MockDevice(Device device, Entity newEntity) {
-        super(device, newEntity);
+    public MockDevice(Device device, Entity newEntity, int insertionpoint) {
+        super(device, newEntity, insertionpoint);
     }
     
     public MockDevice(DeviceManagerImpl deviceManager, Long deviceKey,
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java
index 8b539f664f17e1da2cbc8e099be109fb78d10069..d99dda36e40fba33fa8dbd2fd2bc01b63336ac0c 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/test/MockDeviceManager.java
@@ -97,7 +97,8 @@ public class MockDeviceManager extends DeviceManagerImpl {
     
     @Override
     protected Device allocateDevice(Device device,
-                                    Entity entity) {
-        return new MockDevice(device, entity);
+                                    Entity entity,
+                                    int insertionpoint) {
+        return new MockDevice(device, entity, insertionpoint);
     }
 }
diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
index d1bcf2b16e89a55bff0469271a74e6c53894c0b2..e52829b60acaffedbf0780d8b0197956bf30674a 100644
--- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
+++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
@@ -2,6 +2,7 @@ package net.floodlightcontroller.util;
 
 import static org.junit.Assert.*;
 import java.io.IOException;
+import java.net.SocketAddress;
 
 import java.util.Collection;
 import java.util.Date;
@@ -99,12 +100,6 @@ public class OFMessageDamperMockSwitch implements IOFSwitch {
         assertTrue("Unexpected method call", false);
     }
     
-    @Override
-    public Channel getChannel() {
-        assertTrue("Unexpected method call", false);
-        return null;
-    }
-    
     @Override
     public void setFeaturesReply(OFFeaturesReply featuresReply) {
         assertTrue("Unexpected method call", false);
@@ -228,17 +223,11 @@ public class OFMessageDamperMockSwitch implements IOFSwitch {
     }
     
     @Override
-    public Role getRole() {
+    public Role getHARole() {
         assertTrue("Unexpected method call", false);
         return null;
     }
     
-    @Override
-    public boolean isActive() {
-        assertTrue("Unexpected method call", false);
-        return false;
-    }
-    
     @Override
     public void deliverStatisticsReply(OFMessage reply) {
         assertTrue("Unexpected method call", false);
@@ -350,61 +339,61 @@ public class OFMessageDamperMockSwitch implements IOFSwitch {
     }
 
     @Override
-    public int sendNxRoleRequest(Role role, long cookie) {
+    public void setChannel(Channel channel) {
         // TODO Auto-generated method stub
-        return 0;
+        
     }
 
     @Override
-    public boolean checkFirstPendingRoleRequestCookie(long cookie) {
+    public void setFloodlightProvider(Controller controller) {
         // TODO Auto-generated method stub
-        return false;
+        
     }
 
     @Override
-    public void setChannel(Channel channel) {
+    public void setThreadPoolService(IThreadPoolService threadPool) {
         // TODO Auto-generated method stub
         
     }
 
     @Override
-    public void setFloodlightProvider(Controller controller) {
+    public Lock getListenerReadLock() {
         // TODO Auto-generated method stub
-        
+        return null;
     }
 
     @Override
-    public void setThreadPoolService(IThreadPoolService threadPool) {
+    public Lock getListenerWriteLock() {
         // TODO Auto-generated method stub
-        
+        return null;
     }
 
     @Override
-    public void deliverRoleReply(int xid, Role role) {
+    public void setHARole(Role role, boolean haRoleReplyReceived) {
         // TODO Auto-generated method stub
         
     }
 
     @Override
-    public void deliverRoleRequestNotSupported(int xid) {
+    public SocketAddress getInetAddress() {
         // TODO Auto-generated method stub
-        
+        return null;
     }
 
     @Override
-    public Lock getListenerReadLock() {
+    public OFPortType getPortType(short port_num) {
         // TODO Auto-generated method stub
         return null;
     }
 
     @Override
-    public boolean checkFirstPendingRoleRequestXid(int xid) {
+    public boolean isFastPort(short port_num) {
         // TODO Auto-generated method stub
         return false;
     }
 
     @Override
-    public Lock getListenerWriteLock() {
+    public List<Short> getUplinkPorts() {
         // TODO Auto-generated method stub
         return null;
     }
diff --git a/src/test/java/org/openflow/protocol/WildcardsTest.java b/src/test/java/org/openflow/protocol/WildcardsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bf8d12314a070bc301a8ffda6a36ad02ff7d6a0
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/WildcardsTest.java
@@ -0,0 +1,162 @@
+package org.openflow.protocol;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.EnumSet;
+
+import org.junit.Test;
+import org.openflow.protocol.Wildcards.Flag;
+
+public class WildcardsTest {
+
+    @Test
+    public void testBasic() {
+        int[] intMasks = { 0, 0x3820e0, OFMatch.OFPFW_ALL_SANITIZED };
+        for (int i : intMasks) {
+            Wildcards w = Wildcards.of(i);
+            assertEquals(i, w.getInt());
+        }
+    }
+
+    @Test
+    public void testAllSanitize() {
+        Wildcards w = Wildcards.of(OFMatch.OFPFW_ALL);
+        assertEquals(OFMatch.OFPFW_ALL_SANITIZED, w.getInt());
+        assertTrue(w.isFull());
+        assertFalse(w.isExact());
+    }
+
+    @Test
+    public void testAll() {
+        Wildcards all = Wildcards.FULL;
+        assertTrue(all.isFull());
+        assertFalse(all.isExact());
+        assertEquals(0, all.getNwDstMask());
+        assertEquals(0, all.getNwSrcMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards stillAll = all.wildcard(Flag.IN_PORT);
+        assertTrue(stillAll.isFull());
+        assertEquals(all, stillAll);
+
+        // so is setting a >= 32 netmask
+
+        stillAll = all.withNwSrcMask(0);
+        assertTrue(stillAll.isFull());
+        assertEquals(all, stillAll);
+
+        stillAll = all.withNwDstMask(0);
+        assertTrue(stillAll.isFull());
+        assertEquals(all, stillAll);
+    }
+
+    @Test
+    public void testNone() {
+        Wildcards none = Wildcards.EXACT;
+        assertTrue(none.isExact());
+        assertEquals(32, none.getNwDstMask());
+        assertEquals(32, none.getNwSrcMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards stillNone = none.matchOn(Flag.IN_PORT);
+        assertTrue(stillNone.isExact());
+        assertEquals(none, stillNone);
+
+        // so is setting a >= 32 netmask
+        stillNone = none.withNwSrcMask(32);
+        assertTrue(stillNone.isExact());
+        assertEquals(none, stillNone);
+
+        stillNone = none.withNwDstMask(32);
+        assertTrue(stillNone.isExact());
+        assertEquals(none, stillNone);
+    }
+
+    @Test
+    public void testSetOneFlag() {
+        Wildcards none = Wildcards.EXACT;
+        assertTrue(none.isExact());
+        assertFalse(none.isWildcarded(Flag.DL_SRC));
+        Wildcards one = none.wildcard(Flag.DL_SRC);
+        assertFalse(one.isExact());
+        assertTrue(one.isWildcarded(Flag.DL_SRC));
+        assertEquals(OFMatch.OFPFW_DL_SRC, one.getInt());
+        assertEquals(EnumSet.of(Flag.DL_SRC), one.getWildcardedFlags());
+    }
+
+    @Test
+    public void testSetTwoFlags() {
+        Wildcards none = Wildcards.EXACT;
+
+        // set two flags
+        Wildcards two = none.wildcard(Flag.DL_SRC, Flag.DL_DST);
+        assertFalse(two.isExact());
+        assertTrue(two.isWildcarded(Flag.DL_SRC));
+        assertTrue(two.isWildcarded(Flag.DL_DST));
+        assertEquals(OFMatch.OFPFW_DL_SRC | OFMatch.OFPFW_DL_DST, two.getInt());
+        assertEquals(EnumSet.of(Flag.DL_SRC, Flag.DL_DST), two.getWildcardedFlags());
+
+        // unset dl_dst
+        Wildcards gone = two.matchOn(Flag.DL_DST);
+        assertFalse(gone.isExact());
+        assertTrue(gone.isWildcarded(Flag.DL_SRC));
+        assertFalse(gone.isWildcarded(Flag.DL_DST));
+        assertEquals(OFMatch.OFPFW_DL_SRC, gone.getInt());
+        assertEquals(EnumSet.of(Flag.DL_SRC), gone.getWildcardedFlags());
+    }
+
+    @Test
+    public void testSetNwSrc() {
+        Wildcards none = Wildcards.EXACT;
+        assertEquals(32, none.getNwSrcMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards nwSet = none.withNwSrcMask(8);
+        assertFalse(nwSet.isExact());
+        assertEquals(EnumSet.noneOf(Flag.class), nwSet.getWildcardedFlags());
+        assertEquals(8, nwSet.getNwSrcMask());
+        assertEquals((32 - 8) << OFMatch.OFPFW_NW_SRC_SHIFT, nwSet.getInt());
+    }
+
+    @Test
+    public void testSetNwDst() {
+        Wildcards none = Wildcards.EXACT;
+        assertEquals(32, none.getNwDstMask());
+
+        // unsetting flags from NONE is a no-op
+        Wildcards nwSet = none.withNwDstMask(8);
+        assertFalse(nwSet.isExact());
+        assertEquals(EnumSet.noneOf(Flag.class), nwSet.getWildcardedFlags());
+        assertEquals(8, nwSet.getNwDstMask());
+        assertEquals((32 - 8) << OFMatch.OFPFW_NW_DST_SHIFT, nwSet.getInt());
+    }
+
+    @Test
+    public void testToString() {
+        String s = Wildcards.FULL.toString();
+        assertNotNull(s);
+        assertTrue(s.length() > 0);
+    }
+
+    @Test
+    public void testInvert() {
+        assertEquals(Wildcards.FULL, Wildcards.EXACT.inverted());
+
+        Wildcards some = Wildcards.of(Flag.DL_VLAN, Flag.DL_VLAN_PCP);
+        Wildcards inv = some.inverted();
+
+        for(Flag f : Flag.values()) {
+            boolean shouldBeSet = (f == Flag.DL_VLAN || f == Flag.DL_VLAN_PCP);
+
+            assertEquals("Flag " + f + " "
+                         + (shouldBeSet ? "should be set " : "should not be set"),
+                    shouldBeSet, some.isWildcarded(f));
+            assertEquals(!(f == Flag.DL_VLAN || f == Flag.DL_VLAN_PCP), inv.isWildcarded(f));
+        }
+        assertEquals(0, inv.getNwDstMask());
+        assertEquals(0, inv.getNwSrcMask());
+    }
+}