splitting roles from IO loop and providing a abstract of switch
diff --git a/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java
new file mode 100644
index 0000000..f31487a
--- /dev/null
+++ b/of/ctl/src/main/java/org/onlab/onos/of/controller/impl/internal/RoleManager.java
@@ -0,0 +1,708 @@
+package org.onlab.onos.of.controller.impl.internal;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onlab.onos.of.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFControllerRole;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFErrorType;
+import org.projectfloodlight.openflow.protocol.OFExperimenter;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
+import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
+import org.projectfloodlight.openflow.protocol.OFRoleReply;
+import org.projectfloodlight.openflow.protocol.OFRoleRequest;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
+import org.projectfloodlight.openflow.protocol.errormsg.OFRoleRequestFailedErrorMsg;
+import org.projectfloodlight.openflow.types.U64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A utility class to handle role requests and replies for this channel.
+ * After a role request is submitted the role changer keeps track of the
+ * pending request, collects the reply (if any) and times out the request
+ * if necessary.
+ *
+ * To simplify role handling we only keep track of the /last/ pending
+ * role reply send to the switch. If multiple requests are pending and
+ * we receive replies for earlier requests we ignore them. However, this
+ * way of handling pending requests implies that we could wait forever if
+ * a new request is submitted before the timeout triggers. If necessary
+ * we could work around that though.
+ */
+class RoleManager {
+    protected static final long NICIRA_EXPERIMENTER = 0x2320;
+
+    private static Logger log = LoggerFactory.getLogger(RoleManager.class);
+    // indicates that a request is currently pending
+    // needs to be volatile to allow correct double-check idiom
+    private volatile boolean requestPending;
+    // the transaction Id of the pending request
+    private int pendingXid;
+    // the role that's pending
+    private RoleState pendingRole;
+
+    // the expectation set by the caller for the returned role
+    private RoleRecvStatus expectation;
+    private AtomicInteger xidCounter;
+    private AbstractOpenFlowSwitch sw;
+
+
+    public RoleManager(AbstractOpenFlowSwitch sw) {
+        this.requestPending = false;
+        this.pendingXid = -1;
+        this.pendingRole = null;
+        this.xidCounter = new AtomicInteger(0);
+        this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
+        this.sw = sw;
+    }
+
+    /**
+     * Send NX role request message to the switch requesting the specified
+     * role.
+     *
+     * @param sw switch to send the role request message to
+     * @param role role to request
+     */
+    private int sendNxRoleRequest(RoleState role) throws IOException {
+        // Convert the role enum to the appropriate role to send
+        OFNiciraControllerRole roleToSend = OFNiciraControllerRole.ROLE_OTHER;
+        switch (role) {
+        case MASTER:
+            roleToSend = OFNiciraControllerRole.ROLE_MASTER;
+            break;
+        case SLAVE:
+        case EQUAL:
+        default:
+            // ensuring that the only two roles sent to 1.0 switches with
+            // Nicira role support, are MASTER and SLAVE
+            roleToSend = OFNiciraControllerRole.ROLE_SLAVE;
+            log.warn("Sending Nx Role.SLAVE to switch {}.", sw);
+        }
+        int xid = xidCounter.getAndIncrement();
+        OFExperimenter roleRequest = OFFactories.getFactory(OFVersion.OF_10)
+                .buildNiciraControllerRoleRequest()
+                .setXid(xid)
+                .setRole(roleToSend)
+                .build();
+        sw.write(Collections.<OFMessage>singletonList(roleRequest));
+        return xid;
+    }
+
+    private int sendOF13RoleRequest(RoleState role) throws IOException {
+        // Convert the role enum to the appropriate role to send
+        OFControllerRole roleToSend = OFControllerRole.ROLE_NOCHANGE;
+        switch (role) {
+        case EQUAL:
+            roleToSend = OFControllerRole.ROLE_EQUAL;
+            break;
+        case MASTER:
+            roleToSend = OFControllerRole.ROLE_MASTER;
+            break;
+        case SLAVE:
+            roleToSend = OFControllerRole.ROLE_SLAVE;
+            break;
+        default:
+            log.warn("Sending default role.noChange to switch {}."
+                    + " Should only be used for queries.", sw);
+        }
+
+        int xid = xidCounter.getAndIncrement();
+        OFRoleRequest rrm = OFFactories.getFactory(OFVersion.OF_13)
+                .buildRoleRequest()
+                .setRole(roleToSend)
+                .setXid(xid)
+                //FIXME fix below when we actually use generation ids
+                .setGenerationId(U64.ZERO)
+                .build();
+        sw.write(rrm);
+        return xid;
+    }
+
+    /**
+     * Send a role request with the given role to the switch and update
+     * the pending request and timestamp.
+     * Sends an OFPT_ROLE_REQUEST to an OF1.3 switch, OR
+     * Sends an NX_ROLE_REQUEST to an OF1.0 switch if configured to support it
+     * in the IOFSwitch driver. If not supported, this method sends nothing
+     * and returns 'false'. The caller should take appropriate action.
+     *
+     * One other optimization we do here is that for OF1.0 switches with
+     * Nicira role message support, we force the Role.EQUAL to become
+     * Role.SLAVE, as there is no defined behavior for the Nicira role OTHER.
+     * We cannot expect it to behave like SLAVE. We don't have this problem with
+     * OF1.3 switches, because Role.EQUAL is well defined and we can simulate
+     * SLAVE behavior by using ASYNC messages.
+     *
+     * @param role
+     * @throws IOException
+     * @returns false if and only if the switch does not support role-request
+     * messages, according to the switch driver; true otherwise.
+     */
+    synchronized boolean sendRoleRequest(RoleState role, RoleRecvStatus exp)
+            throws IOException {
+        this.expectation = exp;
+
+        if (sw.factory().getVersion() == OFVersion.OF_10) {
+            Boolean supportsNxRole = (Boolean)
+                    sw.supportNxRole();
+            if (!supportsNxRole) {
+                log.debug("Switch driver indicates no support for Nicira "
+                        + "role request messages. Not sending ...");
+                handleUnsentRoleMessage(role,
+                        expectation);
+                return false;
+            }
+            // OF1.0 switch with support for NX_ROLE_REQUEST vendor extn.
+            // make Role.EQUAL become Role.SLAVE
+            role = (role == RoleState.EQUAL) ? RoleState.SLAVE : role;
+            pendingXid = sendNxRoleRequest(role);
+            pendingRole = role;
+            requestPending = true;
+        } else {
+            // OF1.3 switch, use OFPT_ROLE_REQUEST message
+            pendingXid = sendOF13RoleRequest(role);
+            pendingRole = role;
+            requestPending = true;
+        }
+        return true;
+    }
+
+    private void handleUnsentRoleMessage(RoleState role,
+            RoleRecvStatus exp) throws IOException {
+        // typically this is triggered for a switch where role messages
+        // are not supported - we confirm that the role being set is
+        // master
+        if (exp != RoleRecvStatus.MATCHED_SET_ROLE) {
+
+            log.error("Expected MASTER role from registry for switch "
+                    + "which has no support for role-messages."
+                    + "Received {}. It is possible that this switch "
+                    + "is connected to other controllers, in which "
+                    + "case it should support role messages - not "
+                    + "moving forward.", role);
+
+        }
+
+    }
+
+    /**
+     * Deliver a received role reply.
+     *
+     * Check if a request is pending and if the received reply matches the
+     * the expected pending reply (we check both role and xid) we set
+     * the role for the switch/channel.
+     *
+     * If a request is pending but doesn't match the reply we ignore it, and
+     * return
+     *
+     * If no request is pending we disconnect with a SwitchStateException
+     *
+     * @param RoleReplyInfo information about role-reply in format that
+     *                      controller can understand.
+     * @throws SwitchStateException if no request is pending
+     */
+    synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
+            throws SwitchStateException {
+        if (!requestPending) {
+            RoleState currentRole = (sw != null) ? sw.getRole() : null;
+            if (currentRole != null) {
+                if (currentRole == rri.getRole()) {
+                    // Don't disconnect if the role reply we received is
+                    // for the same role we are already in.
+                    log.debug("Received unexpected RoleReply from "
+                            + "Switch: {}. "
+                            + "Role in reply is same as current role of this "
+                            + "controller for this sw. Ignoring ...",
+                            sw.getStringId());
+                    return RoleRecvStatus.OTHER_EXPECTATION;
+                } else {
+                    String msg = String.format("Switch: [%s], "
+                            + "received unexpected RoleReply[%s]. "
+                            + "No roles are pending, and this controller's "
+                            + "current role:[%s] does not match reply. "
+                            + "Disconnecting switch ... ",
+                            sw.getStringId(),
+                            rri, currentRole);
+                    throw new SwitchStateException(msg);
+                }
+            }
+            log.debug("Received unexpected RoleReply {} from "
+                    + "Switch: {}. "
+                    + "This controller has no current role for this sw. "
+                    + "Ignoring ...", new Object[] {rri,
+                            sw.getStringId(), });
+            return RoleRecvStatus.OTHER_EXPECTATION;
+        }
+
+        int xid = (int) rri.getXid();
+        RoleState role = rri.getRole();
+        // XXX S should check generation id meaningfully and other cases of expectations
+        // U64 genId = rri.getGenId();
+
+        if (pendingXid != xid) {
+            log.debug("Received older role reply from " +
+                    "switch {} ({}). Ignoring. " +
+                    "Waiting for {}, xid={}",
+                    new Object[] {sw.getStringId(), rri,
+                    pendingRole, pendingXid });
+            return RoleRecvStatus.OLD_REPLY;
+        }
+
+        if (pendingRole == role) {
+            log.debug("Received role reply message from {} that matched "
+                    + "expected role-reply {} with expectations {}",
+                    new Object[] {sw.getStringId(), role, expectation});
+
+            //setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY); dont want to set state here
+            if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
+                    expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
+                return expectation;
+            } else {
+                return RoleRecvStatus.OTHER_EXPECTATION;
+            }
+        }
+
+        // if xids match but role's don't, perhaps its a query (OF1.3)
+        if (expectation == RoleRecvStatus.REPLY_QUERY) {
+            return expectation;
+        }
+
+        return RoleRecvStatus.OTHER_EXPECTATION;
+    }
+
+    /**
+     * Called if we receive an  error message. If the xid matches the
+     * pending request we handle it otherwise we ignore it.
+     *
+     * Note: since we only keep the last pending request we might get
+     * error messages for earlier role requests that we won't be able
+     * to handle
+     */
+    synchronized RoleRecvStatus deliverError(OFErrorMsg error)
+            throws SwitchStateException {
+        if (!requestPending) {
+            log.debug("Received an error msg from sw {}, but no pending "
+                    + "requests in role-changer; not handling ...",
+                   sw.getStringId());
+            return RoleRecvStatus.OTHER_EXPECTATION;
+        }
+        if (pendingXid != error.getXid()) {
+            if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
+                log.debug("Received an error msg from sw {} for a role request,"
+                        + " but not for pending request in role-changer; "
+                        + " ignoring error {} ...",
+                        sw.getStringId(), error);
+            }
+            return RoleRecvStatus.OTHER_EXPECTATION;
+        }
+        // it is an error related to a currently pending role request message
+        if (error.getErrType() == OFErrorType.BAD_REQUEST) {
+            log.error("Received a error msg {} from sw {} for "
+                    + "pending role request {}. Switch driver indicates "
+                    + "role-messaging is supported. Possible issues in "
+                    + "switch driver configuration?", new Object[] {
+                            ((OFBadRequestErrorMsg) error).toString(),
+                            sw.getStringId(), pendingRole
+                    });
+            return RoleRecvStatus.UNSUPPORTED;
+        }
+
+        if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
+            OFRoleRequestFailedErrorMsg rrerr =
+                    (OFRoleRequestFailedErrorMsg) error;
+            switch (rrerr.getCode()) {
+            case BAD_ROLE:
+                // switch says that current-role-req has bad role?
+                // for now we disconnect
+                // fall-thru
+            case STALE:
+                // switch says that current-role-req has stale gen-id?
+                // for now we disconnect
+                // fall-thru
+            case UNSUP:
+                // switch says that current-role-req has role that
+                // cannot be supported? for now we disconnect
+                String msgx = String.format("Switch: [%s], "
+                        + "received Error to for pending role request [%s]. "
+                        + "Error:[%s]. Disconnecting switch ... ",
+                        sw.getStringId(),
+                        pendingRole, rrerr);
+                throw new SwitchStateException(msgx);
+            default:
+                break;
+            }
+        }
+
+        // This error message was for a role request message but we dont know
+        // how to handle errors for nicira role request messages
+        return RoleRecvStatus.OTHER_EXPECTATION;
+    }
+
+    /**
+     * Extract the role from an OFVendor message.
+     *
+     * Extract the role from an OFVendor message if the message is a
+     * Nicira role reply. Otherwise return null.
+     *
+     * @param h The channel handler receiving the message
+     * @param vendorMessage The vendor message to parse.
+     * @return The role in the message if the message is a Nicira role
+     * reply, null otherwise.
+     * @throws SwitchStateException If the message is a Nicira role reply
+     * but the numeric role value is unknown.
+     */
+    protected RoleState extractNiciraRoleReply(OFExperimenter experimenterMsg)
+            throws SwitchStateException {
+        int vendor = (int) experimenterMsg.getExperimenter();
+        if (vendor != 0x2320) {
+            return null;
+        }
+        OFNiciraControllerRoleReply nrr =
+                (OFNiciraControllerRoleReply) experimenterMsg;
+
+        RoleState role = null;
+        OFNiciraControllerRole ncr = nrr.getRole();
+        switch(ncr) {
+        case ROLE_MASTER:
+            role = RoleState.MASTER;
+            break;
+        case ROLE_OTHER:
+            role = RoleState.EQUAL;
+            break;
+        case ROLE_SLAVE:
+            role = RoleState.SLAVE;
+            break;
+        default: //handled below
+        }
+
+        if (role == null) {
+            String msg = String.format("Switch: [%s], "
+                    + "received NX_ROLE_REPLY with invalid role "
+                    + "value %s",
+                    sw.getStringId(),
+                    nrr.getRole());
+            throw new SwitchStateException(msg);
+        }
+        return role;
+    }
+
+    /**
+     * When we remove a pending role request we use this enum to indicate how we
+     * arrived at the decision. When we send a role request to the switch, we
+     * also use  this enum to indicate what we expect back from the switch, so the
+     * role changer can match the reply to our expectation.
+     */
+    public enum RoleRecvStatus {
+        /** The switch returned an error indicating that roles are not.
+         * supported*/
+        UNSUPPORTED,
+        /** The request timed out. */
+        NO_REPLY,
+        /** The reply was old, there is a newer request pending. */
+        OLD_REPLY,
+        /**
+         *  The reply's role matched the role that this controller set in the
+         *  request message - invoked either initially at startup or to reassert
+         *  current role.
+         */
+        MATCHED_CURRENT_ROLE,
+        /**
+         *  The reply's role matched the role that this controller set in the
+         *  request message - this is the result of a callback from the
+         *  global registry, followed by a role request sent to the switch.
+         */
+        MATCHED_SET_ROLE,
+        /**
+         * The reply's role was a response to the query made by this controller.
+         */
+        REPLY_QUERY,
+        /** We received a role reply message from the switch
+         *  but the expectation was unclear, or there was no expectation.
+         */
+        OTHER_EXPECTATION,
+    }
+
+    /**
+     * Helper class returns role reply information in the format understood
+     * by the controller.
+     */
+    protected static class RoleReplyInfo {
+        private RoleState role;
+        private U64 genId;
+        private long xid;
+
+        RoleReplyInfo(RoleState role, U64 genId, long xid) {
+            this.role = role;
+            this.genId = genId;
+            this.xid = xid;
+        }
+        public RoleState getRole() { return role; }
+        public U64 getGenId() { return genId; }
+        public long getXid() { return xid; }
+        @Override
+        public String toString() {
+            return "[Role:" + role + " GenId:" + genId + " Xid:" + xid + "]";
+        }
+    }
+
+    /**
+     * Extract the role information from an OF1.3 Role Reply Message.
+     * @param h
+     * @param rrmsg
+     * @return RoleReplyInfo object
+     * @throws SwitchStateException
+     */
+    protected RoleReplyInfo extractOFRoleReply(OFRoleReply rrmsg)
+            throws SwitchStateException {
+        OFControllerRole cr = rrmsg.getRole();
+        RoleState role = null;
+        switch(cr) {
+        case ROLE_EQUAL:
+            role = RoleState.EQUAL;
+            break;
+        case ROLE_MASTER:
+            role = RoleState.MASTER;
+            break;
+        case ROLE_SLAVE:
+            role = RoleState.SLAVE;
+            break;
+        case ROLE_NOCHANGE: // switch should send current role
+        default:
+            String msg = String.format("Unknown controller role %s "
+                    + "received from switch %s", cr, sw);
+            throw new SwitchStateException(msg);
+        }
+
+        return new RoleReplyInfo(role, rrmsg.getGenerationId(), rrmsg.getXid());
+    }
+
+}
+
+
+///**
+// * We are waiting for a role reply message in response to a role request
+// * sent after hearing back from the registry service -- OR -- we are
+// * just waiting to hear back from the registry service in the case that
+// * the switch does not support role messages. If completed successfully,
+// * the controller's role for this switch will be set here.
+// * Before we move to the state corresponding to the role, we allow the
+// * switch specific driver to complete its configuration. This configuration
+// * typically depends on the role the controller is playing for this switch.
+// * And so we set the switch role (for 'this' controller) before we start
+// * the driver-sub-handshake.
+// * Next State: WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
+// */
+//WAIT_INITIAL_ROLE(false) {
+//    @Override
+//    void processOFError(OFChannelHandler h, OFErrorMsg m)
+//            throws SwitchStateException {
+//        // role changer will ignore the error if it isn't for it
+//        RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
+//        if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
+//            logError(h, m);
+//        }
+//    }
+//
+//    @Override
+//    void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
+//            throws IOException, SwitchStateException {
+//        Role role = extractNiciraRoleReply(h, m);
+//        // If role == null it means the vendor (experimenter) message
+//        // wasn't really a Nicira role reply. We ignore this case.
+//        if (role != null) {
+//            RoleReplyInfo rri = new RoleReplyInfo(role, null, m.getXid());
+//            RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+//            if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+//                setRoleAndStartDriverHandshake(h, rri.getRole());
+//            } // else do nothing - wait for the correct expected reply
+//        } else {
+//            unhandledMessageReceived(h, m);
+//        }
+//    }
+//
+//    @Override
+//    void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
+//            throws SwitchStateException, IOException {
+//        RoleReplyInfo rri = extractOFRoleReply(h, m);
+//        RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+//        if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+//            setRoleAndStartDriverHandshake(h, rri.getRole());
+//        } // else do nothing - wait for the correct expected reply
+//    }
+//
+//    @Override
+//    void handleUnsentRoleMessage(OFChannelHandler h, Role role,
+//            RoleRecvStatus expectation) throws IOException {
+//        // typically this is triggered for a switch where role messages
+//        // are not supported - we confirm that the role being set is
+//        // master and move to the next state
+//        if (expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
+//            if (role == Role.MASTER) {
+//                setRoleAndStartDriverHandshake(h, role);
+//            } else {
+//                log.error("Expected MASTER role from registry for switch "
+//                        + "which has no support for role-messages."
+//                        + "Received {}. It is possible that this switch "
+//                        + "is connected to other controllers, in which "
+//                        + "case it should support role messages - not "
+//                        + "moving forward.", role);
+//            }
+//        } // else do nothing - wait to hear back from registry
+//
+//    }
+//
+//    private void setRoleAndStartDriverHandshake(OFChannelHandler h,
+//            Role role) throws IOException {
+//        h.setSwitchRole(role);
+//        h.sw.startDriverHandshake();
+//        if (h.sw.isDriverHandshakeComplete()) {
+//            Role mySwitchRole = h.sw.getRole();
+//            if (mySwitchRole == Role.MASTER) {
+//                log.info("Switch-driver sub-handshake complete. "
+//                        + "Activating switch {} with Role: MASTER",
+//                        h.sw.getStringId());
+//                handlePendingPortStatusMessages(h); //before activation
+//                boolean success = h.sw.addActivatedMasterSwitch();
+//                if (!success) {
+//                    disconnectDuplicate(h);
+//                    return;
+//                }
+//                h.setState(MASTER);
+//            } else {
+//                log.info("Switch-driver sub-handshake complete. "
+//                        + "Activating switch {} with Role: EQUAL",
+//                        h.sw.getStringId());
+//                handlePendingPortStatusMessages(h); //before activation
+//                boolean success = h.sw.addActivatedEqualSwitch();
+//                if (!success) {
+//                    disconnectDuplicate(h);
+//                    return;
+//                }
+//                h.setState(EQUAL);
+//            }
+//        } else {
+//            h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
+//        }
+//    }
+//
+//    @Override
+//    void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m)
+//            throws IOException, SwitchStateException {
+//        illegalMessageReceived(h, m);
+//    }
+//
+//    @Override
+//    void processOFStatisticsReply(OFChannelHandler h, OFStatsReply m)
+//            throws SwitchStateException {
+//        illegalMessageReceived(h, m);
+//    }
+//
+//    @Override
+//    void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+//            throws IOException, SwitchStateException {
+//        h.pendingPortStatusMsg.add(m);
+//
+//    }
+//},
+
+
+
+
+
+
+
+///**
+// * This controller is in EQUAL role for this switch. We enter this state
+// * after some /other/ controller instance wins mastership-role over this
+// * switch. The EQUAL role can be considered the same as the SLAVE role
+// * if this controller does NOT send commands or packets to the switch.
+// * This should always be true for OF1.0 switches. XXX S need to enforce.
+// *
+// * For OF1.3 switches, choosing this state as EQUAL instead of SLAVE,
+// * gives us the flexibility that if an app wants to send commands/packets
+// * to switches, it can, even thought it is running on a controller instance
+// * that is not in a MASTER role for this switch. Of course, it is the job
+// * of the app to ensure that commands/packets sent by this (EQUAL) controller
+// * instance does not clash/conflict with commands/packets sent by the MASTER
+// * controller for this switch. Neither the controller instances, nor the
+// * switch provides any kind of resolution mechanism should conflicts occur.
+// */
+//EQUAL(true) {
+//    @Override
+//    void processOFError(OFChannelHandler h, OFErrorMsg m)
+//            throws IOException, SwitchStateException {
+//        // role changer will ignore the error if it isn't for it
+//        RoleRecvStatus rrstatus = h.roleChanger.deliverError(m);
+//        if (rrstatus == RoleRecvStatus.OTHER_EXPECTATION) {
+//            logError(h, m);
+//            h.dispatchMessage(m);
+//        }
+//    }
+//
+//    @Override
+//    void processOFStatisticsReply(OFChannelHandler h,
+//            OFStatsReply m) {
+//        h.sw.handleMessage(m);
+//    }
+//
+//    @Override
+//    void processOFExperimenter(OFChannelHandler h, OFExperimenter m)
+//            throws IOException, SwitchStateException {
+//        Role role = extractNiciraRoleReply(h, m);
+//        // If role == null it means the message wasn't really a
+//        // Nicira role reply. We ignore it in this state.
+//        if (role != null) {
+//            RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(
+//                    new RoleReplyInfo(role, null, m.getXid()));
+//            if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+//                checkAndSetRoleTransition(h, role);
+//            }
+//        } else {
+//            unhandledMessageReceived(h, m);
+//        }
+//    }
+//
+//    @Override
+//    void processOFRoleReply(OFChannelHandler h, OFRoleReply m)
+//            throws SwitchStateException, IOException {
+//        RoleReplyInfo rri = extractOFRoleReply(h, m);
+//        RoleRecvStatus rrs = h.roleChanger.deliverRoleReply(rri);
+//        if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
+//            checkAndSetRoleTransition(h, rri.getRole());
+//        }
+//    }
+//
+//    // XXX S needs more handlers for 1.3 switches in equal role
+//
+//    @Override
+//    void processOFPortStatus(OFChannelHandler h, OFPortStatus m)
+//            throws IOException, SwitchStateException {
+//        handlePortStatusMessage(h, m, true);
+//    }
+//
+//    @Override
+//    @LogMessageDoc(level = "WARN",
+//    message = "Received PacketIn from switch {} while "
+//            + "being slave. Reasserting slave role.",
+//            explanation = "The switch has receive a PacketIn despite being "
+//                    + "in slave role indicating inconsistent controller roles",
+//                    recommendation = "This situation can occurs transiently during role"
+//                            + " changes. If, however, the condition persists or happens"
+//                            + " frequently this indicates a role inconsistency. "
+//                            + LogMessageDoc.CHECK_CONTROLLER)
+//    void processOFPacketIn(OFChannelHandler h, OFPacketIn m) throws IOException {
+//        // we don't expect packetIn while slave, reassert we are slave
+//        h.counters.packetInWhileSwitchIsSlave.updateCounterNoFlush();
+//        log.warn("Received PacketIn from switch {} while" +
+//                "being slave. Reasserting slave role.", h.sw);
+//        //h.controller.reassertRole(h, Role.SLAVE);
+//        // XXX reassert in role changer
+//    }
+//};