Change from EQUAL role to SLAVE role as many switches do not support
ASYNC set messages

Change-Id: I207ca52eee2f2518d6b6916667ec1c638da28019
diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
index 4447b75..5ad8227 100644
--- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
+++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java
@@ -193,7 +193,7 @@
 
     /**
      * Record a switch event in in-memory debug-event
-     * 
+     *
      * @param switchDPID
      * @param reason Reason for this event
      * @param flushNow see debug-event flushing in IDebugEventService
@@ -202,11 +202,11 @@
 
     Set<Long> getAllMasterSwitchDpids();
 
-    Set<Long> getAllEqualSwitchDpids();
+    Set<Long> getAllSlaveSwitchDpids();
 
     IOFSwitch getMasterSwitch(long dpid);
 
-    IOFSwitch getEqualSwitch(long dpid);
+    IOFSwitch getSlaveSwitch(long dpid);
 
     void setAlwaysClearFlowsOnSwActivate(boolean value);
 
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java b/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
index caeb95f..ca4ae06 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitchListener.java
@@ -58,26 +58,29 @@
      */
 	public void switchActivatedMaster(long swId);
 
-	/**
+	    /**
      * Fired when switch becomes active on the controller cluster and this
-     * controller instance has acquired EQUAL role for this switch
+     * controller instance has acquired SLAVE role for this switch
+     * 
      * @param switchId the datapath Id of the new switch
      */
-	public void switchActivatedEqual(long swId);
+    public void switchActivatedSlave(long swId);
 
-	/**
-     * Fired when the role of this controller for this switch, transitions
-     * from MASTER role to EQUAL role
+	    /**
+     * Fired when the role of this controller for this switch, transitions from
+     * MASTER role to SLAVE role
+     * 
      * @param switchId the datapath Id of the new switch
      */
-	public void switchMasterToEqual(long swId);
+    public void switchMasterToSlave(long swId);
 
-	/**
-     * Fired when the role of this controller for this switch, transitions
-     * from EQUAL role to MASTER role
+	    /**
+     * Fired when the role of this controller for this switch, transitions from
+     * SLAVE role to MASTER role
+     * 
      * @param switchId the datapath Id of the new switch
      */
-	public void switchEqualToMaster(long swId);
+    public void switchSlaveToMaster(long swId);
 
 	/**
 	 * Fired when this switch has disconnected at this controller. It does NOT
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 55908db..eceb906 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -117,7 +117,7 @@
     protected ConcurrentHashMap<Long, OFChannelHandler> connectedSwitches;
     // These caches contains only those switches that are active
     protected ConcurrentHashMap<Long, IOFSwitch> activeMasterSwitches;
-    protected ConcurrentHashMap<Long, IOFSwitch> activeEqualSwitches;
+    protected ConcurrentHashMap<Long, IOFSwitch> activeSlaveSwitches;
     // lock to synchronize on, when manipulating multiple caches above
     private Object multiCacheLock;
 
@@ -178,13 +178,11 @@
      * available for updates.
      *
      * In ONOS, each controller instance can simultaneously serve in a MASTER
-     * role for some connected switches, and in a EQUAL role for other connected
-     * switches. The EQUAL role can be treated as a SLAVE role, by ensuring that
-     * the controller instance never sends packets or commands out to the
-     * switch. Activated switches, either with Controller Role MASTER or EQUAL
-     * are announced as updates. We also support announcements of controller
-     * role transitions from MASTER --> EQUAL, and EQUAL --> MASTER, for an
-     * individual switch.
+     * role for some connected switches, and in a SLAVE role for other connected
+     * switches. It does not support role EQUAL. Activated switches, either with
+     * Controller Role MASTER or SLAVE are announced as updates. We also support
+     * announcements of controller role transitions from MASTER --> SLAVE, and
+     * SLAVE --> MASTER, for an individual switch.
      *
      * Disconnection of only activated switches are announced. Finally, changes
      * to switch ports are announced with a portChangeType (see @IOFSwitch)
@@ -195,15 +193,14 @@
         /** switch activated with this controller's role as MASTER */
         ACTIVATED_MASTER,
         /**
-         * switch activated with this controller's role as EQUAL. listener can
-         * treat this controller's role as SLAVE by not sending packets or
-         * commands to the switch
+         * switch activated with this controller's role as SLAVE. listener
+         * cannot send packets or commands to the switch
          */
-        ACTIVATED_EQUAL,
-        /** this controller's role for this switch changed from Master to Equal */
-        MASTER_TO_EQUAL,
-        /** this controller's role for this switch changed form Equal to Master */
-        EQUAL_TO_MASTER,
+        ACTIVATED_SLAVE,
+        /** this controller's role for this switch changed from Master to Slave */
+        MASTER_TO_SLAVE,
+        /** this controller's role for this switch changed form Slave to Master */
+        SLAVE_TO_MASTER,
         /** A previously activated switch disconnected */
         DISCONNECTED,
         /** Port changed on a previously activated switch */
@@ -276,16 +273,16 @@
                         // counters before the update is created
                         listener.switchActivatedMaster(swId);
                         break;
-                    case ACTIVATED_EQUAL:
+                    case ACTIVATED_SLAVE:
                         // don't count here. We have more specific
                         // counters before the update is created
-                        listener.switchActivatedEqual(swId);
+                        listener.switchActivatedSlave(swId);
                         break;
-                    case MASTER_TO_EQUAL:
-                        listener.switchMasterToEqual(swId);
+                    case MASTER_TO_SLAVE:
+                        listener.switchMasterToSlave(swId);
                         break;
-                    case EQUAL_TO_MASTER:
-                        listener.switchEqualToMaster(swId);
+                    case SLAVE_TO_MASTER:
+                        listener.switchSlaveToMaster(swId);
                         break;
                     case DISCONNECTED:
                         // don't count here. We have more specific
@@ -333,13 +330,13 @@
             return false;
         }
         if (activeMasterSwitches.get(dpid) != null ||
-                activeEqualSwitches.get(dpid) != null) {
+                activeSlaveSwitches.get(dpid) != null) {
             log.error("Trying to activate switch but it is already "
                     + "activated: dpid {}. Found in activeMaster: {} "
                     + "Found in activeEqual: {}. Aborting ..", new Object[] {
                     HexString.toHexString(dpid),
                     (activeMasterSwitches.get(dpid) == null) ? 'Y' : 'N',
-                    (activeEqualSwitches.get(dpid) == null) ? 'Y' : 'N'});
+                    (activeSlaveSwitches.get(dpid) == null) ? 'Y' : 'N'});
             counters.switchWithSameDpidActivated.updateCounterWithFlush();
             return false;
         }
@@ -365,30 +362,29 @@
     }
 
     /**
-     * Called when a switch is activated, with this controller's role as EQUAL
+     * Called when a switch is activated, with this controller's role as SLAVE
      */
-    protected boolean addActivatedEqualSwitch(long dpid, IOFSwitch sw) {
+    protected boolean addActivatedSlaveSwitch(long dpid, IOFSwitch sw) {
         synchronized (multiCacheLock) {
             if (!validActivation(dpid))
                 return false;
-            activeEqualSwitches.put(dpid, sw);
+            activeSlaveSwitches.put(dpid, sw);
         }
         // update counters and events
         counters.switchActivated.updateCounterWithFlush();
         evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "activeEqual"));
         addUpdateToQueue(new SwitchUpdate(dpid,
-                SwitchUpdateType.ACTIVATED_EQUAL));
+                SwitchUpdateType.ACTIVATED_SLAVE));
         return true;
     }
 
     /**
-     * Called when this controller's role for a switch transitions from equal to
-     * master. For 1.0 switches, we internally refer to the role 'slave' as
-     * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
+     * Called when this controller's role for a switch transitions from slave to
+     * master.
      */
     protected void transitionToMasterSwitch(long dpid) {
         synchronized (multiCacheLock) {
-            IOFSwitch sw = activeEqualSwitches.remove(dpid);
+            IOFSwitch sw = activeSlaveSwitches.remove(dpid);
             if (sw == null) {
                 log.error("Transition to master called on sw {}, but switch "
                         + "was not found in controller-cache", dpid);
@@ -397,25 +393,24 @@
             activeMasterSwitches.put(dpid, sw);
         }
         addUpdateToQueue(new SwitchUpdate(dpid,
-                SwitchUpdateType.EQUAL_TO_MASTER));
+                SwitchUpdateType.SLAVE_TO_MASTER));
     }
 
     /**
-     * Called when this controller's role for a switch transitions to equal. For
-     * 1.0 switches, we internally refer to the role 'slave' as 'equal'.
+     * Called when this controller's role for a switch transitions to slave.
      */
-    protected void transitionToEqualSwitch(long dpid) {
+    protected void transitionToSlaveSwitch(long dpid) {
         synchronized (multiCacheLock) {
             IOFSwitch sw = activeMasterSwitches.remove(dpid);
             if (sw == null) {
-                log.error("Transition to equal called on sw {}, but switch "
+                log.error("Transition to slave called on sw {}, but switch "
                         + "was not found in controller-cache", dpid);
                 return;
             }
-            activeEqualSwitches.put(dpid, sw);
+            activeSlaveSwitches.put(dpid, sw);
         }
         addUpdateToQueue(new SwitchUpdate(dpid,
-                SwitchUpdateType.MASTER_TO_EQUAL));
+                SwitchUpdateType.MASTER_TO_SLAVE));
     }
 
     /**
@@ -428,7 +423,7 @@
         OFChannelHandler ch = connectedSwitches.remove(dpid);
         IOFSwitch sw = activeMasterSwitches.remove(dpid);
         if (sw == null) {
-            sw = activeEqualSwitches.remove(dpid);
+            sw = activeSlaveSwitches.remove(dpid);
         }
         if (sw != null) {
             sw.cancelAllStatisticsReplies();
@@ -527,7 +522,7 @@
             if (hasControl) {
                 role = Role.MASTER;
             } else {
-                role = Role.EQUAL; // treat the same as Role.SLAVE
+                role = Role.SLAVE;
             }
 
             OFChannelHandler swCh = connectedSwitches.get(dpid.value());
@@ -536,7 +531,6 @@
                 return;
             }
 
-            log.debug("Sending role request {} msg to {}", role, dpid);
             swCh.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
         }
     }
@@ -749,7 +743,7 @@
     public Set<Long> getAllSwitchDpids() {
         Set<Long> dpids = new HashSet<Long>();
         dpids.addAll(activeMasterSwitches.keySet());
-        dpids.addAll(activeEqualSwitches.keySet());
+        dpids.addAll(activeSlaveSwitches.keySet());
         return dpids;
     }
 
@@ -761,9 +755,9 @@
     }
 
     @Override
-    public Set<Long> getAllEqualSwitchDpids() {
+    public Set<Long> getAllSlaveSwitchDpids() {
         Set<Long> dpids = new HashSet<Long>();
-        dpids.addAll(activeEqualSwitches.keySet());
+        dpids.addAll(activeSlaveSwitches.keySet());
         return dpids;
     }
 
@@ -772,7 +766,7 @@
         IOFSwitch sw = null;
         if ((sw = activeMasterSwitches.get(dpid)) != null)
             return sw;
-        if ((sw = activeEqualSwitches.get(dpid)) != null)
+        if ((sw = activeSlaveSwitches.get(dpid)) != null)
             return sw;
         return sw;
     }
@@ -783,8 +777,8 @@
     }
 
     @Override
-    public IOFSwitch getEqualSwitch(long dpid) {
-        return activeEqualSwitches.get(dpid);
+    public IOFSwitch getSlaveSwitch(long dpid) {
+        return activeSlaveSwitches.get(dpid);
     }
 
     @Override
@@ -1202,7 +1196,7 @@
                 IOFMessageListener>>();
         this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
         this.activeMasterSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
-        this.activeEqualSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
+        this.activeSlaveSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
         this.connectedSwitches = new ConcurrentHashMap<Long, OFChannelHandler>();
         this.controllerNodeIPsCache = new HashMap<String, String>();
         this.updates = new LinkedBlockingQueue<IUpdate>();
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
index 9a8f21b..e1d175c 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
@@ -1033,16 +1033,16 @@
                         h.setState(MASTER);
                     } else {
                         log.info("Switch-driver sub-handshake complete. "
-                                + "Activating switch {} with Role: EQUAL",
+                                + "Activating switch {} with Role: SLAVE",
                                 h.getSwitchInfoString());
                         handlePendingPortStatusMessages(h); // before activation
-                        boolean success = h.controller.addActivatedEqualSwitch(
+                        boolean success = h.controller.addActivatedSlaveSwitch(
                                 h.sw.getId(), h.sw);
                         if (!success) {
                             disconnectDuplicate(h);
                             return;
                         }
-                        h.setState(EQUAL);
+                        h.setState(SLAVE);
                     }
                 } else {
                     h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
@@ -1053,9 +1053,9 @@
             public void handleTimedOutHandshake(OFChannelHandler h,
                     ChannelHandlerContext ctx) throws IOException {
                 log.info("Handshake timed out waiting to hear back from registry "
-                        + "service. Moving to Role EQUAL for switch {}",
+                        + "service. Moving to Role SLAVE for switch {}",
                         h.getSwitchInfoString());
-                setRoleAndStartDriverHandshake(h, Role.EQUAL);
+                setRoleAndStartDriverHandshake(h, Role.SLAVE);
             }
 
             @Override
@@ -1084,7 +1084,7 @@
          * main switch-controller handshake. But we do consider it as a step
          * that comes before we declare the switch as available to the
          * controller. Next State: depends on the role of this controller for
-         * this switch - either MASTER or EQUAL.
+         * this switch - either MASTER or SLAVE.
          */
         WAIT_SWITCH_DRIVER_SUB_HANDSHAKE(false) {
 
@@ -1120,17 +1120,17 @@
                             h.setState(MASTER);
                         } else {
                             log.info("Switch-driver sub-handshake complete. "
-                                    + "Activating switch {} with Role: EQUAL",
+                                    + "Activating switch {} with Role: SLAVE",
                                     h.getSwitchInfoString());
                             handlePendingPortStatusMessages(h); // before
                                                                 // activation
-                            boolean success = h.controller.addActivatedEqualSwitch(
+                            boolean success = h.controller.addActivatedSlaveSwitch(
                                     h.sw.getId(), h.sw);
                             if (!success) {
                                 disconnectDuplicate(h);
                                 return;
                             }
-                            h.setState(EQUAL);
+                            h.setState(SLAVE);
                         }
                     }
                 }
@@ -1265,23 +1265,20 @@
         },
 
         /**
-         * This controller is in EQUAL role for this switch. We enter this state
+         * This controller is in SLAVE 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.
+         * switch.
          *
-         * 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.
+         * A note about role EQUAL: can be considered the same as the SLAVE role
+         * if this controller does NOT send commands or packets to the switch.
+         * However an EQUAL controller will also get packet-in and flow-removed
+         * messages just like a MASTER controller. And so if one wishes to avoid
+         * such messages in this role, then we need to configure OFPT_ASYNC
+         * messages on the switch. ONOS does not currently implement the role
+         * EQUAL.
+         *
          */
-        EQUAL(true) {
+        SLAVE(true) {
             @Override
             void processOFError(OFChannelHandler h, OFErrorMsg m)
                     throws IOException, SwitchStateException {
@@ -1588,12 +1585,12 @@
 
         /**
          * Handles all pending port status messages before a switch is declared
-         * activated in MASTER or EQUAL role. Note that since this handling
+         * activated in MASTER or SLAVE role. Note that since this handling
          * precedes the activation (and therefore notification to
          * IOFSwitchListerners) the changes to ports will already be visible
          * once the switch is activated. As a result, no notifications are sent
          * out for these pending portStatus messages.
-         *
+         * 
          * @param h
          * @throws SwitchStateException
          */
@@ -1679,23 +1676,18 @@
             // possible that the role of this controller instance for
             // this switch has changed:
             // for 1.0 switch: from MASTER to SLAVE
-            // for 1.3 switch: from MASTER to EQUAL
+            // for 1.3 switch: from MASTER to EQUAL/SLAVE
             if ((h.sw.getRole() == Role.MASTER && role == Role.SLAVE) ||
                     (h.sw.getRole() == Role.MASTER && role == Role.EQUAL)) {
                 // the mastership has changed
-                if (role == Role.SLAVE) {
-                    role = Role.EQUAL;
-                }
                 h.sw.setRole(role);
-                h.setState(EQUAL);
-                h.controller.transitionToEqualSwitch(h.sw.getId());
+                h.setState(SLAVE);
+                h.controller.transitionToSlaveSwitch(h.sw.getId());
                 return;
             }
 
-            // or for both 1.0 and 1.3 switches from EQUAL to MASTER.
-            // note that for 1.0, even though we mean SLAVE,
-            // internally we call the role EQUAL.
-            if (h.sw.getRole() == Role.EQUAL && role == Role.MASTER) {
+            // or for both 1.0 and 1.3 switches from EQUAL/SLAVE to MASTER.
+            if (h.sw.getRole() == Role.SLAVE && role == Role.MASTER) {
                 // the mastership has changed
                 h.sw.setRole(role);
                 h.setState(MASTER);
@@ -1945,15 +1937,15 @@
          * If the switch is in WAIT_INITIAL_ROLE state, when the handshake
          * timeout is triggered, then it's because we have not heard back from
          * the registry service regarding switch mastership. In this case, we
-         * move to EQUAL (or SLAVE) state. See override for this method in
+         * move to SLAVE state. See override for this method in
          * WAIT_INITIAL_ROLE state.
          * <p>
          * XXX: This is required today as the registry service does not reply
          * with role.slave to a mastership request, i.e it only replies to the
          * controller that wins mastership. Once the registry API changes to
          * reply to every request, we would not need to wait for a timeout to
-         * move to Role.EQUAL (or SLAVE).
-         *
+         * move to Role.SLAVE.
+         * 
          * @param h the channel handler for this switch
          * @param ctx the netty channel handler context for the channel 'h'
          * @throws IOException
diff --git a/src/main/java/net/onrc/onos/apps/defaultrules/DefaultRules.java b/src/main/java/net/onrc/onos/apps/defaultrules/DefaultRules.java
index ff2ef9b..0b3ce0a 100644
--- a/src/main/java/net/onrc/onos/apps/defaultrules/DefaultRules.java
+++ b/src/main/java/net/onrc/onos/apps/defaultrules/DefaultRules.java
@@ -148,15 +148,15 @@
     }
 
     @Override
-    public void switchActivatedEqual(long swId) {
+    public void switchActivatedSlave(long swId) {
     }
 
     @Override
-    public void switchMasterToEqual(long swId) {
+    public void switchMasterToSlave(long swId) {
     }
 
     @Override
-    public void switchEqualToMaster(long swId) {
+    public void switchSlaveToMaster(long swId) {
     }
 
     @Override
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java
index 321fcef..1b0d9ef 100644
--- a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplSpringOpenTTP.java
@@ -291,6 +291,11 @@
         }
         switch (currentState) {
         case INIT:
+            if (getRole() == Role.SLAVE) {
+                driverState = DriverState.AUDIT_GROUPS;
+                verifyGroups();
+                break;
+            }
             driverState = DriverState.SET_TABLE_MISS_ENTRIES;
             setTableMissEntries();
             sendHandshakeBarrier();
@@ -303,6 +308,7 @@
             }
             populateTableVlan();
             populateTableTMac();
+            // testDifferentLabelStacks();
             sendHandshakeBarrier();
             break;
         case SET_TABLE_VLAN_TMAC:
@@ -310,6 +316,11 @@
             verifyGroups();
             break;
         case AUDIT_GROUPS:
+            if (getRole() == Role.SLAVE) {
+                driverState = DriverState.EXIT;
+                driverHandshakeComplete.set(true);
+                break;
+            }
             driverState = DriverState.SET_GROUPS;
             createGroups();
             sendHandshakeBarrier();
@@ -2623,6 +2634,211 @@
         }
     }
 
+    @SuppressWarnings("unused")
+    private void testDifferentLabelStacks() {
+        if (getId() == 281483173139394L) { // 106
+            List<OFMessage> msglist = new ArrayList<OFMessage>();
+
+            // first all the indirect groups
+
+            // the group to switch 105 with outer label
+            OFGroup g1 = OFGroup.of(201);
+            OFAction push1 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
+            OFOxmMplsLabel lid1 = factory.oxms()
+                    .mplsLabel(U32.of(102)); // outer label
+            OFAction setMpls1 = factory.actions().buildSetField()
+                    .setField(lid1).build();
+            OFOxmMplsBos bos1 = factory.oxms()
+                    .mplsBos(OFBooleanValue.FALSE);
+            OFAction setB1 = factory.actions().buildSetField()
+                    .setField(bos1).build();
+            OFAction outp1 = factory.actions().buildOutput()
+                    .setPort(OFPort.of(7))
+                    .build();
+            List<OFAction> a1 = new ArrayList<OFAction>();
+            a1.add(push1);
+            a1.add(setMpls1);
+            a1.add(setB1);
+            a1.add(outp1);
+            OFBucket b1 = factory.buildBucket()
+                    .setActions(a1)
+                    .build();
+            OFMessage gm1 = factory.buildGroupAdd()
+                    .setGroup(g1)
+                    .setBuckets(Collections.singletonList(b1))
+                    .setGroupType(OFGroupType.INDIRECT)
+                    .setXid(getNextTransactionId())
+                    .build();
+            msglist.add(gm1);
+
+            // the group to switch 104 with outer label
+            OFGroup g2 = OFGroup.of(301);
+            OFAction push2 = factory.actions().pushMpls(EthType.MPLS_UNICAST);
+            OFOxmMplsLabel lid2 = factory.oxms()
+                    .mplsLabel(U32.of(103)); // outer label
+            OFAction setMpls2 = factory.actions().buildSetField()
+                    .setField(lid2).build();
+            OFOxmMplsBos bos2 = factory.oxms()
+                    .mplsBos(OFBooleanValue.FALSE);
+            OFAction setB2 = factory.actions().buildSetField()
+                    .setField(bos2).build();
+            OFAction outp2 = factory.actions().buildOutput()
+                    .setPort(OFPort.of(4))
+                    .build();
+            List<OFAction> a2 = new ArrayList<OFAction>();
+            a2.add(push2);
+            a2.add(setMpls2);
+            a2.add(setB2);
+            a2.add(outp2);
+            OFBucket b2 = factory.buildBucket()
+                    .setActions(a2)
+                    .build();
+            OFMessage gm2 = factory.buildGroupAdd()
+                    .setGroup(g2)
+                    .setBuckets(Collections.singletonList(b2))
+                    .setGroupType(OFGroupType.INDIRECT)
+                    .setXid(getNextTransactionId())
+                    .build();
+            msglist.add(gm2);
+
+            // now add main ECMP group with inner labels
+            OFGroup group = OFGroup.of(786);
+            List<OFBucket> buckets = new ArrayList<OFBucket>();
+            for (int i = 0; i < 2; i++) { // 2 buckets
+
+                List<OFAction> actions = new ArrayList<OFAction>();
+                OFOxmEthSrc smac = factory.oxms()
+                        .ethSrc(MacAddress.of("00:01:e8:8b:93:c5"));
+                OFAction setSA = factory.actions().buildSetField()
+                        .setField(smac).build();
+                actions.add(setSA);
+
+                if (i == 0) {
+                    // send to switch 105
+                    OFAction pushX = factory.actions().pushMpls(EthType.MPLS_UNICAST);
+                    OFOxmMplsLabel lidX = factory.oxms()
+                            .mplsLabel(U32.of(101)); // inner label
+                    OFAction setX = factory.actions().buildSetField()
+                            .setField(lidX).build();
+                    OFOxmMplsBos bosX = factory.oxms()
+                            .mplsBos(OFBooleanValue.TRUE);
+                    OFAction setBX = factory.actions().buildSetField()
+                            .setField(bosX).build();
+                    OFAction ogX = factory.actions().buildGroup()
+                            .setGroup(g1).build();
+                    OFOxmEthDst dmac1 = factory.oxms().ethDst(
+                            MacAddress.of("00:01:e8:8b:93:bf"));
+                    OFAction setDA1 = factory.actions().buildSetField()
+                            .setField(dmac1).build();
+                    actions.add(setDA1);
+                    actions.add(pushX);
+                    actions.add(setX);
+                    actions.add(setBX);
+                    actions.add(ogX);
+
+
+                } else {
+                    // send to switch 104
+                    OFOxmEthDst dmac2 = factory.oxms().ethDst(
+                            MacAddress.of("00:01:e8:8b:93:b0"));
+                    OFAction setDA2 = factory.actions().buildSetField()
+                            .setField(dmac2).build();
+                    OFAction pushY = factory.actions().pushMpls(EthType.MPLS_UNICAST);
+                    OFOxmMplsLabel lidY = factory.oxms()
+                            .mplsLabel(U32.of(101)); // inner label
+                    OFAction setY = factory.actions().buildSetField()
+                            .setField(lidY).build();
+                    OFOxmMplsBos bosY = factory.oxms()
+                            .mplsBos(OFBooleanValue.TRUE);
+                    OFAction setBY = factory.actions().buildSetField()
+                            .setField(bosY).build();
+                    OFAction ogY = factory.actions().buildGroup()
+                            .setGroup(g2).build();
+                    actions.add(setDA2);
+                    actions.add(pushY);
+                    actions.add(setY);
+                    actions.add(setBY);
+                    actions.add(ogY);
+                }
+
+                OFBucket ofb = factory.buildBucket()
+                        .setWeight(1)
+                        .setActions(actions)
+                        .build();
+                buckets.add(ofb);
+            }
+
+            OFMessage gm = factory.buildGroupAdd()
+                    .setGroup(group)
+                    .setBuckets(buckets)
+                    .setGroupType(OFGroupType.SELECT)
+                    .setXid(getNextTransactionId())
+                    .build();
+            msglist.add(gm);
+
+            // create two ACL entries to use this ecmp group
+            Builder matchBuilder1 = factory.buildMatch();
+            matchBuilder1.setExact(MatchField.ETH_TYPE, EthType.of(0x800));
+            matchBuilder1.setMasked(MatchField.IPV4_DST,
+                    IPv4Address.of("10.200.1.0")
+                            .withMaskOfLength(24));
+
+            Builder matchBuilder2 = factory.buildMatch();
+            matchBuilder2.setExact(MatchField.ETH_TYPE, EthType.of(0x800));
+            matchBuilder2.setMasked(MatchField.IPV4_DST,
+                    IPv4Address.of("10.200.3.0")
+                            .withMaskOfLength(24));
+
+            OFAction grp = factory.actions().buildGroup()
+                    .setGroup(OFGroup.of(786))
+                    .build();
+            List<OFAction> writeActions = Collections.singletonList(grp);
+
+            OFInstruction clearInstr = factory.instructions().clearActions();
+            OFInstruction writeInstr = factory.instructions().buildWriteActions()
+                    .setActions(writeActions).build();
+            List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+            instructions.add(clearInstr);
+            instructions.add(writeInstr);
+
+            OFFlowMod.Builder fmBuilder = factory.buildFlowAdd();
+
+            OFMessage aclFlow1 = fmBuilder
+                    .setTableId(TableId.of(aclTableId))
+                    .setMatch(matchBuilder1.build())
+                    .setInstructions(instructions)
+                    .setPriority(1000) // TODO: wrong - should be MA
+                                     // priority
+                    .setBufferId(OFBufferId.NO_BUFFER)
+                    .setIdleTimeout(0)
+                    .setHardTimeout(0)
+                    .setXid(getNextTransactionId())
+                    .build();
+            msglist.add(aclFlow1);
+
+            OFFlowMod.Builder fmBuilder2 = factory.buildFlowAdd();
+            OFMessage aclFlow2 = fmBuilder2
+                    .setTableId(TableId.of(aclTableId))
+                    .setMatch(matchBuilder2.build())
+                    .setInstructions(instructions)
+                    .setPriority(33333) // TODO: wrong - should be MA
+                                       // priority
+                    .setBufferId(OFBufferId.NO_BUFFER)
+                    .setIdleTimeout(0)
+                    .setHardTimeout(0)
+                    .setXid(getNextTransactionId())
+                    .build();
+            msglist.add(aclFlow2);
+
+            try {
+                write(msglist);
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+    }
+
     protected int getVlanTableId() {
         return vlanTableId;
     }
diff --git a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowProgrammer.java b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowProgrammer.java
index 0b89107..35fc5ce 100644
--- a/src/main/java/net/onrc/onos/core/flowprogrammer/FlowProgrammer.java
+++ b/src/main/java/net/onrc/onos/core/flowprogrammer/FlowProgrammer.java
@@ -131,19 +131,19 @@
     }
 
     @Override
-    public void switchActivatedEqual(long swId) {
+    public void switchActivatedSlave(long swId) {
         // TODO Auto-generated method stub
 
     }
 
     @Override
-    public void switchMasterToEqual(long swId) {
+    public void switchMasterToSlave(long swId) {
         // TODO Auto-generated method stub
 
     }
 
     @Override
-    public void switchEqualToMaster(long swId) {
+    public void switchSlaveToMaster(long swId) {
         // for now treat as switchActivatedMaster
         switchActivatedMaster(swId);
     }
diff --git a/src/main/java/net/onrc/onos/core/linkdiscovery/LinkDiscoveryManager.java b/src/main/java/net/onrc/onos/core/linkdiscovery/LinkDiscoveryManager.java
index 42c2942..ce146f1 100644
--- a/src/main/java/net/onrc/onos/core/linkdiscovery/LinkDiscoveryManager.java
+++ b/src/main/java/net/onrc/onos/core/linkdiscovery/LinkDiscoveryManager.java
@@ -817,19 +817,19 @@
     }
 
     @Override
-    public void switchActivatedEqual(long swId) {
+    public void switchActivatedSlave(long swId) {
         // TODO Auto-generated method stub
 
     }
 
     @Override
-    public void switchMasterToEqual(long swId) {
+    public void switchMasterToSlave(long swId) {
         // TODO Auto-generated method stub
 
     }
 
     @Override
-    public void switchEqualToMaster(long swId) {
+    public void switchSlaveToMaster(long swId) {
         // for now treat as switchActivatedMaster
         switchActivatedMaster(swId);
     }
diff --git a/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java b/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
index 538224d..3ed55e9 100644
--- a/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
@@ -445,19 +445,19 @@
     }
 
     @Override
-    public void switchActivatedEqual(long swId) {
+    public void switchActivatedSlave(long swId) {
         final Dpid dpid = new Dpid(swId);
-        controllerRoleChanged(dpid, Role.EQUAL);
+        controllerRoleChanged(dpid, Role.SLAVE);
     }
 
     @Override
-    public void switchMasterToEqual(long swId) {
+    public void switchMasterToSlave(long swId) {
         final Dpid dpid = new Dpid(swId);
-        controllerRoleChanged(dpid, Role.EQUAL);
+        controllerRoleChanged(dpid, Role.SLAVE);
     }
 
     @Override
-    public void switchEqualToMaster(long swId) {
+    public void switchSlaveToMaster(long swId) {
         // for now treat as switchActivatedMaster
         switchActivatedMaster(swId);
     }
diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
index 54321e5..8514f65 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java
@@ -523,10 +523,10 @@
         IOFSwitchListener listener = createStrictMock(IOFSwitchListener.class);
         controller.addOFSwitchListener(listener);
 
-        listener.switchActivatedEqual(dpid);
+        listener.switchActivatedSlave(dpid);
         replay(sw, listener); // nothing recorded
         controller.addConnectedSwitch(dpid, new OFChannelHandler(controller));
-        controller.addActivatedEqualSwitch(dpid, sw);
+        controller.addActivatedSlaveSwitch(dpid, sw);
         verify(sw);
         controller.processUpdateQueueForTesting();
         verify(listener);
@@ -594,10 +594,10 @@
 
         // Add switch to controller as EQUAL
         controller.addConnectedSwitch(dpid, new OFChannelHandler(controller));
-        controller.addActivatedEqualSwitch(dpid, sw);
+        controller.addActivatedSlaveSwitch(dpid, sw);
 
         // Check the switch is in the controller's lists
-        assertEquals(sw, controller.getEqualSwitch(dpid));
+        assertEquals(sw, controller.getSlaveSwitch(dpid));
 
         IOFSwitchListener listener = createStrictMock(IOFSwitchListener.class);
         listener.switchDisconnected(dpid);
@@ -618,7 +618,7 @@
         // Disconnect switch
         controller.removeConnectedSwitch(dpid);
 
-        assertNull(controller.getEqualSwitch(dpid));
+        assertNull(controller.getSlaveSwitch(dpid));
 
         controller.processUpdateQueueForTesting();
         verify(listener, sw);
@@ -739,20 +739,20 @@
         }
 
         @Override
-        public synchronized void switchActivatedEqual(long swId) {
-            updateCount.add(SwitchUpdateType.ACTIVATED_EQUAL);
+        public synchronized void switchActivatedSlave(long swId) {
+            updateCount.add(SwitchUpdateType.ACTIVATED_SLAVE);
             notifyAll();
         }
 
         @Override
-        public synchronized void switchMasterToEqual(long swId) {
-            updateCount.add(SwitchUpdateType.MASTER_TO_EQUAL);
+        public synchronized void switchMasterToSlave(long swId) {
+            updateCount.add(SwitchUpdateType.MASTER_TO_SLAVE);
             notifyAll();
         }
 
         @Override
-        public synchronized void switchEqualToMaster(long swId) {
-            updateCount.add(SwitchUpdateType.EQUAL_TO_MASTER);
+        public synchronized void switchSlaveToMaster(long swId) {
+            updateCount.add(SwitchUpdateType.SLAVE_TO_MASTER);
             notifyAll();
         }
 
@@ -795,11 +795,11 @@
         // Switch updates
         doTestUpdateQueueWithUpdate(dpid, SwitchUpdateType.ACTIVATED_MASTER,
                 switchListener);
-        doTestUpdateQueueWithUpdate(dpid, SwitchUpdateType.ACTIVATED_EQUAL,
+        doTestUpdateQueueWithUpdate(dpid, SwitchUpdateType.ACTIVATED_SLAVE,
                 switchListener);
-        doTestUpdateQueueWithUpdate(dpid, SwitchUpdateType.EQUAL_TO_MASTER,
+        doTestUpdateQueueWithUpdate(dpid, SwitchUpdateType.SLAVE_TO_MASTER,
                 switchListener);
-        doTestUpdateQueueWithUpdate(dpid, SwitchUpdateType.MASTER_TO_EQUAL,
+        doTestUpdateQueueWithUpdate(dpid, SwitchUpdateType.MASTER_TO_SLAVE,
                 switchListener);
         doTestUpdateQueueWithUpdate(dpid, SwitchUpdateType.DISCONNECTED,
                 switchListener);
diff --git a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java
index 6c52f15..37a8a2b 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/OFChannelHandlerTest.java
@@ -584,8 +584,8 @@
         ExceptionEvent eeMock = createMock(ExceptionEvent.class);
         expect(eeMock.getCause()).andReturn(new HandshakeTimeoutException())
                 .atLeastOnce();
-        // controller should move to role EQUAL via the driver handshake
-        swImplBase.setRole(Role.EQUAL);
+        // controller should move to role SLAVE via the driver handshake
+        swImplBase.setRole(Role.SLAVE);
         expectLastCall().once();
         swImplBase.startDriverHandshake();
         expectLastCall().once();
@@ -593,10 +593,10 @@
         // immediately
         expect(swImplBase.isDriverHandshakeComplete())
                 .andReturn(true).once();
-        expect(swImplBase.getRole()).andReturn(Role.EQUAL).once();
+        expect(swImplBase.getRole()).andReturn(Role.SLAVE).once();
         expect(swImplBase.getId())
                 .andReturn(1L).anyTimes();
-        expect(controller.addActivatedEqualSwitch(1L, swImplBase))
+        expect(controller.addActivatedSlaveSwitch(1L, swImplBase))
                 .andReturn(true).once();
 
         replay(channel);
@@ -604,7 +604,7 @@
         replay(swImplBase);
         replay(eeMock);
         handler.exceptionCaught(ctx, eeMock);
-        assertEquals(OFChannelHandler.ChannelState.EQUAL,
+        assertEquals(OFChannelHandler.ChannelState.SLAVE,
                 handler.getStateForTesting());
     }
 
@@ -653,7 +653,7 @@
 
         controller.flushAll();
         expectLastCall().once();
-        expect(controller.addActivatedEqualSwitch(1000, swImplBase))
+        expect(controller.addActivatedSlaveSwitch(1000, swImplBase))
         .andReturn(true).once();
         replay(controller);
 
@@ -686,7 +686,7 @@
         // send the description stats reply
         handler.messageReceived(ctx, messageEvent);
 
-        assertEquals(OFChannelHandler.ChannelState.EQUAL,
+        assertEquals(OFChannelHandler.ChannelState.SLAVE,
                 handler.getStateForTesting());
     }
 
@@ -795,7 +795,7 @@
 
         controller.flushAll();
         expectLastCall().once();
-        expect(controller.addActivatedEqualSwitch(1000, swImplBase))
+        expect(controller.addActivatedSlaveSwitch(1000, swImplBase))
         .andReturn(true).once();
         replay(controller);
 
@@ -817,7 +817,7 @@
         // send the description stats reply
         handler.messageReceived(ctx, messageEvent);
 
-        assertEquals(OFChannelHandler.ChannelState.EQUAL,
+        assertEquals(OFChannelHandler.ChannelState.SLAVE,
                 handler.getStateForTesting());
     }
 
@@ -1306,7 +1306,7 @@
 
         expect(swImplBase.getStringId())
         .andReturn(null).anyTimes();
-        expect(swImplBase.getRole()).andReturn(Role.EQUAL).atLeastOnce();
+        expect(swImplBase.getRole()).andReturn(Role.SLAVE).atLeastOnce();
         expect(swImplBase.getNextTransactionId())
         .andReturn(xid).anyTimes();
         expect(swImplBase.getId())
@@ -1371,7 +1371,7 @@
         reset(controller);
         reset(swImplBase);
 
-        controller.transitionToEqualSwitch(1000);
+        controller.transitionToSlaveSwitch(1000);
         expectLastCall().once();
         expect(controller.getOFSwitchInstance((OFDescStatsReply)sr, ofVersion))
         .andReturn(swImplBase).anyTimes();
@@ -1391,7 +1391,7 @@
         .andReturn(xid).anyTimes();
 
         // prepare mocks and inject the role reply message
-        swImplBase.setRole(Role.EQUAL);
+        swImplBase.setRole(Role.SLAVE);
         expectLastCall().once();
         expect(swImplBase.getId())
         .andReturn(1000L).once();
@@ -1399,7 +1399,7 @@
 
         handler.messageReceived(ctx, messageEvent);
 
-        assertEquals(OFChannelHandler.ChannelState.EQUAL,
+        assertEquals(OFChannelHandler.ChannelState.SLAVE,
                 handler.getStateForTesting());
     }
 
diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
index 1691759..8ae2e2c 100644
--- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
+++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
@@ -356,7 +356,7 @@
     }
 
     @Override
-    public Set<Long> getAllEqualSwitchDpids() {
+    public Set<Long> getAllSlaveSwitchDpids() {
         return this.activeEqualSwitches.keySet();
     }
 
@@ -366,7 +366,7 @@
     }
 
     @Override
-    public IOFSwitch getEqualSwitch(long dpid) {
+    public IOFSwitch getSlaveSwitch(long dpid) {
         return this.activeEqualSwitches.get(dpid);
     }