Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
index 3dfce00..80b9b18 100644
--- a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
@@ -233,6 +233,8 @@
         @Override
         public void unableToAssertRole(DeviceId deviceId, MastershipRole role) {
             // FIXME: implement response to this notification
+            log.warn("Failed to assert role [{}] onto Device {}",
+                    role, deviceId);
         }
     }
 
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
index ae3bc5a..15dba06 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
@@ -11,7 +11,6 @@
 import org.onlab.onos.net.DefaultPort;
 import org.onlab.onos.net.Device;
 import org.onlab.onos.net.DeviceId;
-import org.onlab.onos.net.MastershipRole;
 import org.onlab.onos.net.Port;
 import org.onlab.onos.net.PortNumber;
 import org.onlab.onos.net.device.DeviceDescription;
@@ -54,7 +53,6 @@
     public static final String DEVICE_NOT_FOUND = "Device with ID %s not found";
 
     private final Map<DeviceId, DefaultDevice> devices = new ConcurrentHashMap<>();
-    private final Map<DeviceId, MastershipRole> roles = new ConcurrentHashMap<>();
     private final Set<DeviceId> availableDevices = new HashSet<>();
     private final Map<DeviceId, Map<PortNumber, Port>> devicePorts = new HashMap<>();
 
@@ -257,7 +255,6 @@
     @Override
     public DeviceEvent removeDevice(DeviceId deviceId) {
         synchronized (this) {
-            roles.remove(deviceId);
             Device device = devices.remove(deviceId);
             return device == null ? null :
                     new DeviceEvent(DEVICE_REMOVED, device, null);
diff --git a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java
index 424e63c..24e119c 100644
--- a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java
+++ b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java
@@ -105,4 +105,11 @@
      */
     public void disconnectSwitch();
 
+    /**
+     * Notifies the controller that role assertion has failed.
+     *
+     * @param role the failed role
+     */
+    void returnRoleAssertFailure(RoleState role);
+
 }
diff --git a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitchListener.java b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitchListener.java
index c7cc287..53217da 100644
--- a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitchListener.java
+++ b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitchListener.java
@@ -25,4 +25,12 @@
      * @param status the new state of the port.
      */
     public void portChanged(Dpid dpid, OFPortStatus status);
+
+    /**
+     * Notify that a role imposed on a switch failed to take hold.
+     *
+     * @param dpid the switch that failed role assertion
+     * @param role the role imposed by the controller
+     */
+    public void roleAssertFailed(Dpid dpid, RoleState role);
 }
diff --git a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/driver/AbstractOpenFlowSwitch.java b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/driver/AbstractOpenFlowSwitch.java
index ae36381..393246b 100644
--- a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/driver/AbstractOpenFlowSwitch.java
+++ b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/driver/AbstractOpenFlowSwitch.java
@@ -213,6 +213,11 @@
     }
 
     @Override
+    public void returnRoleAssertFailure(RoleState role) {
+        this.agent.returnRoleAssertFailed(dpid, role);
+    }
+
+    @Override
     public abstract void startDriverHandshake();
 
     @Override
diff --git a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/driver/OpenFlowAgent.java b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/driver/OpenFlowAgent.java
index 1261715..870f10a 100644
--- a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/driver/OpenFlowAgent.java
+++ b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/driver/OpenFlowAgent.java
@@ -2,6 +2,7 @@
 
 import org.onlab.onos.openflow.controller.Dpid;
 import org.onlab.onos.openflow.controller.OpenFlowSwitch;
+import org.onlab.onos.openflow.controller.RoleState;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 
 /**
@@ -74,4 +75,12 @@
      * @param m the message to process
      */
     public void processMessage(Dpid dpid, OFMessage m);
+
+    /**
+     * Notifies the controller that role assertion has failed.
+     *
+     * @param dpid the switch that failed role assertion
+     * @param role the failed role
+     */
+    public void returnRoleAssertFailed(Dpid dpid, RoleState role);
 }
diff --git a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java
index d74c497..eb12286 100644
--- a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java
+++ b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java
@@ -313,6 +313,13 @@
         public void processMessage(Dpid dpid, OFMessage m) {
             processPacket(dpid, m);
         }
+
+        @Override
+        public void returnRoleAssertFailed(Dpid dpid, RoleState role) {
+            for (OpenFlowSwitchListener l : ofSwitchListener) {
+                l.roleAssertFailed(dpid, role);
+            }
+        }
     }
 
     private final class OFMessageHandler implements Runnable {
diff --git a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/RoleManager.java b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/RoleManager.java
index 5d9013e..7eb2445 100644
--- a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/RoleManager.java
+++ b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/RoleManager.java
@@ -232,6 +232,8 @@
             } else {
                 return RoleRecvStatus.OTHER_EXPECTATION;
             }
+        } else {
+            sw.returnRoleAssertFailure(pendingRole);
         }
 
         // if xids match but role's don't, perhaps its a query (OF1.3)
diff --git a/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
index 1271bc8..8958fb6 100644
--- a/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -142,6 +142,26 @@
             providerService.portStatusChanged(deviceId(uri(dpid)), portDescription);
         }
 
+        @Override
+        public void roleAssertFailed(Dpid dpid, RoleState role) {
+            MastershipRole failed;
+            switch (role) {
+                case MASTER:
+                    failed = MastershipRole.MASTER;
+                    break;
+                case EQUAL:
+                    failed = MastershipRole.STANDBY;
+                    break;
+                case SLAVE:
+                    failed = MastershipRole.NONE;
+                    break;
+                default:
+                    LOG.warn("unknown role {}", role);
+                    return;
+            }
+            providerService.unableToAssertRole(deviceId(uri(dpid)), failed);
+        }
+
         /**
          * Builds a list of port descriptions for a given list of ports.
          *
@@ -169,6 +189,7 @@
                     !port.getConfig().contains(OFPortConfig.PORT_DOWN);
             return new DefaultPortDescription(portNo, enabled);
         }
+
     }
 
 }
diff --git a/providers/openflow/device/src/test/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProviderTest.java b/providers/openflow/device/src/test/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProviderTest.java
index cd55ded..8196cb8 100644
--- a/providers/openflow/device/src/test/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProviderTest.java
+++ b/providers/openflow/device/src/test/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProviderTest.java
@@ -120,6 +120,16 @@
         assertEquals("port status unhandled", 3, registry.ports.get(DID1).size());
     }
 
+    @Test
+    public void roleAssertFailed() {
+        controller.listener.roleAssertFailed(DPID1, RoleState.MASTER);
+        assertEquals("wrong role reported", DPID1, registry.roles.get(MASTER));
+        controller.listener.roleAssertFailed(DPID1, RoleState.EQUAL);
+        assertEquals("wrong role reported", DPID1, registry.roles.get(STANDBY));
+        controller.listener.roleAssertFailed(DPID1, RoleState.SLAVE);
+        assertEquals("wrong role reported", DPID1, registry.roles.get(NONE));
+    }
+
     private static OFPortDesc portDesc(int port) {
         OFPortDesc.Builder builder = OFFactoryVer10.INSTANCE.buildPortDesc();
         builder.setPortNo(OFPort.of(port));
@@ -129,9 +139,11 @@
 
     private class TestDeviceRegistry implements DeviceProviderRegistry {
         DeviceProvider provider;
-        Set<DeviceId> connected = new HashSet<DeviceId>();
+
+        Set<DeviceId> connected = new HashSet<>();
         Multimap<DeviceId, PortDescription> ports = HashMultimap.create();
         PortDescription descr = null;
+        Map<MastershipRole, Dpid> roles = new HashMap<>();
 
         @Override
         public DeviceProviderService register(DeviceProvider provider) {
@@ -184,7 +196,7 @@
 
             @Override
             public void unableToAssertRole(DeviceId deviceId, MastershipRole role) {
-                // FIXME: add fixture core when tests are done on this
+                roles.put(role, Dpid.dpid(deviceId.uri()));
             }
 
         }
@@ -344,6 +356,10 @@
         public void disconnectSwitch() {
         }
 
+        @Override
+        public void returnRoleAssertFailure(RoleState role) {
+        }
+
     }
 
 }
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
index 4ab2a8b..c8d9c25 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -23,6 +23,7 @@
 import org.onlab.onos.openflow.controller.OpenFlowEventListener;
 import org.onlab.onos.openflow.controller.OpenFlowSwitch;
 import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
+import org.onlab.onos.openflow.controller.RoleState;
 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
 import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
@@ -162,6 +163,12 @@
 
         }
 
+        @Override
+        public void roleAssertFailed(Dpid dpid, RoleState role) {
+            // TODO Auto-generated method stub
+
+        }
+
         private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
             if (stats.getStatsType() != OFStatsType.FLOW) {
                 return;
diff --git a/providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java b/providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
index 0571922..f448a44 100644
--- a/providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
+++ b/providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
@@ -22,6 +22,7 @@
 import org.onlab.onos.openflow.controller.OpenFlowSwitch;
 import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
 import org.onlab.onos.openflow.controller.PacketListener;
+import org.onlab.onos.openflow.controller.RoleState;
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortState;
@@ -135,6 +136,11 @@
 
         }
 
+        @Override
+        public void roleAssertFailed(Dpid dpid, RoleState role) {
+            // TODO Auto-generated method stub
+        }
+
     }
 
 }
diff --git a/providers/openflow/packet/src/test/java/org/onlab/onos/provider/of/packet/impl/OpenFlowPacketProviderTest.java b/providers/openflow/packet/src/test/java/org/onlab/onos/provider/of/packet/impl/OpenFlowPacketProviderTest.java
index 101856e..d5cccc4 100644
--- a/providers/openflow/packet/src/test/java/org/onlab/onos/provider/of/packet/impl/OpenFlowPacketProviderTest.java
+++ b/providers/openflow/packet/src/test/java/org/onlab/onos/provider/of/packet/impl/OpenFlowPacketProviderTest.java
@@ -394,6 +394,10 @@
         public void disconnectSwitch() {
         }
 
+        @Override
+        public void returnRoleAssertFailure(RoleState role) {
+        }
+
     }
 
 }