Improved LinkInfo handling for ONOS

 * LinkInfo class is now immutable and uses primitive types
 * Removed logic to check STP state of ports. ONOS will not operate in
   networks using STP.
 * Cleaned up LinkInfo port state update logic to be clearer. We still
   maintain the port states in LinkInfo, though they are not used right now.
 * Removed the port updates that were sent by the link discovery module.
   ONOS does not use these, port updates are sent directly from the switch
   manager.


Change-Id: Icd2995de404948fa85b9e6852652bd4389d7cab8
diff --git a/src/test/java/net/onrc/onos/core/linkdiscovery/internal/LinkDiscoveryManagerTest.java b/src/test/java/net/onrc/onos/core/linkdiscovery/internal/LinkDiscoveryManagerTest.java
index dd748ac..22ec42e 100644
--- a/src/test/java/net/onrc/onos/core/linkdiscovery/internal/LinkDiscoveryManagerTest.java
+++ b/src/test/java/net/onrc/onos/core/linkdiscovery/internal/LinkDiscoveryManagerTest.java
@@ -42,12 +42,15 @@
 import net.onrc.onos.core.linkdiscovery.Link;
 import net.onrc.onos.core.linkdiscovery.LinkInfo;
 import net.onrc.onos.core.linkdiscovery.NodePortTuple;
+import net.onrc.onos.core.registry.IControllerRegistryService;
 
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.protocol.OFPortStatus;
+import org.openflow.protocol.OFPortStatus.OFPortReason;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -95,6 +98,11 @@
         ldm.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
         MockThreadPoolService tp = new MockThreadPoolService();
         RestApiServer restApi = new RestApiServer();
+        IControllerRegistryService registry =
+                EasyMock.createMock(IControllerRegistryService.class);
+        expect(registry.hasControl(EasyMock.anyLong())).andReturn(true).anyTimes();
+        replay(registry);
+        cntx.addService(IControllerRegistryService.class, registry);
         cntx.addService(IRestApiService.class, restApi);
         cntx.addService(IThreadPoolService.class, tp);
         cntx.addService(ILinkDiscoveryService.class, ldm);
@@ -120,7 +128,8 @@
         LinkDiscoveryManager topology = getTopology();
 
         Link lt = new Link(1L, 2, 2L, 1);
-        LinkInfo info = new LinkInfo(System.currentTimeMillis(),
+        long firstSeenTime = System.currentTimeMillis();
+        LinkInfo info = new LinkInfo(firstSeenTime,
                 System.currentTimeMillis(), 0, 0);
         topology.addOrUpdateLink(lt, info);
 
@@ -136,6 +145,29 @@
         assertNotNull(topology.portLinks.get(dstNpt));
         assertTrue(topology.portLinks.get(dstNpt).contains(lt));
         assertTrue(topology.links.containsKey(lt));
+
+        LinkInfo infoToVerify = topology.links.get(lt);
+        assertEquals(firstSeenTime, infoToVerify.getFirstSeenTime());
+        assertEquals(0, infoToVerify.getSrcPortState());
+        assertEquals(0, infoToVerify.getDstPortState());
+
+        // Arbitrary new port states to verify that the port state is updated
+        final int newSrcPortState = 1;
+        final int newDstPortState = 2;
+
+        // Update the last received probe timestamp and the port states
+        LinkInfo infoWithStateChange = new LinkInfo(System.currentTimeMillis(),
+                System.currentTimeMillis(), newSrcPortState, newDstPortState);
+
+        topology.addOrUpdateLink(lt, infoWithStateChange);
+
+        assertNotNull(topology.links.get(lt));
+        infoToVerify = topology.links.get(lt);
+        // First seen time should be the original time, not the second update time
+        assertEquals(firstSeenTime, infoToVerify.getFirstSeenTime());
+        // Both port states should have been updated
+        assertEquals(newSrcPortState, infoToVerify.getSrcPortState());
+        assertEquals(newDstPortState, infoToVerify.getDstPortState());
     }
 
     @Test
@@ -270,24 +302,14 @@
 
         topology.timeoutLinks();
 
-
-        info = new LinkInfo(System.currentTimeMillis(), /* firstseen */
-                null, /* unicast */0, 0);
-        topology.addOrUpdateLink(lt, info);
-        assertTrue(topology.links.get(lt).getUnicastValidTime() == null);
-
-
         // Add a link info based on info that would be obtained from unicast LLDP
         // Setting the unicast LLDP reception time to be 40 seconds old, so we can use
-        // this to test timeout after this test.  Although the info is initialized
-        // with LT_OPENFLOW_LINK, the link property should be changed to LT_NON_OPENFLOW
-        // by the addOrUpdateLink method.
+        // this to test timeout after this test.
         info = new LinkInfo(System.currentTimeMillis() - 40000,
                 System.currentTimeMillis() - 40000, 0, 0);
         topology.addOrUpdateLink(lt, info);
 
-        // Expect to timeout the unicast Valid Time, but not the multicast Valid time
-        // So the link type should go back to non-openflow link.
+        // Expect to timeout the unicast Valid Time, so the link should disappear
         topology.timeoutLinks();
         assertTrue(topology.links.get(lt) == null);
     }
@@ -331,4 +353,87 @@
 
         verify(swTest);
     }
+
+    @Test
+    public void testHandlePortStatusForNewPort() throws IOException {
+        byte[] macAddress = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x1};
+
+        LinkDiscoveryManager linkDiscovery = getTopology();
+
+        long dpid = 3L;
+        IOFSwitch sw = createMockSwitch(dpid);
+        getMockFloodlightProvider().getSwitches().put(dpid, sw);
+
+        short portNum = 1;
+        OFPhysicalPort ofpPort = new OFPhysicalPort();
+        ofpPort.setPortNumber(portNum);
+        ofpPort.setHardwareAddress(macAddress);
+
+        OFPortStatus portStatus = new OFPortStatus();
+        portStatus.setDesc(ofpPort);
+        portStatus.setReason((byte) OFPortReason.OFPPR_ADD.ordinal());
+
+        expect(sw.getPort(portNum)).andReturn(ofpPort).anyTimes();
+        sw.write(EasyMock.anyObject(OFMessage.class),
+                EasyMock.anyObject(FloodlightContext.class));
+        sw.flush();
+
+        replay(sw);
+
+        linkDiscovery.handlePortStatus(sw, portStatus);
+
+        verify(sw);
+    }
+
+    @Test
+    public void testHandlePortStatusForExistingPort() {
+        byte[] macAddress = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x1};
+
+        LinkDiscoveryManager linkDiscovery = getTopology();
+
+        // Add a link that we can update later during the test
+        Link lt = new Link(1L, 1, 2L, 1);
+        LinkInfo info = new LinkInfo(System.currentTimeMillis(),
+                System.currentTimeMillis(), 0, 0);
+        linkDiscovery.addOrUpdateLink(lt, info);
+
+        short portNum = 1;
+        // src port
+        int srcPortState = 2;
+        OFPhysicalPort srcPort = new OFPhysicalPort();
+        srcPort.setPortNumber(portNum);
+        srcPort.setHardwareAddress(macAddress);
+        srcPort.setState(srcPortState);
+
+        // dst port
+        int dstPortState = 4;
+        OFPhysicalPort dstPort = new OFPhysicalPort();
+        dstPort.setPortNumber(portNum);
+        dstPort.setHardwareAddress(macAddress);
+        dstPort.setState(dstPortState);
+
+        OFPortStatus srcPortStatus = new OFPortStatus();
+        srcPortStatus.setDesc(srcPort);
+        srcPortStatus.setReason((byte) OFPortReason.OFPPR_MODIFY.ordinal());
+
+        OFPortStatus dstPortStatus = new OFPortStatus();
+        dstPortStatus.setDesc(dstPort);
+        dstPortStatus.setReason((byte) OFPortReason.OFPPR_MODIFY.ordinal());
+
+        linkDiscovery.handlePortStatus(
+                getMockFloodlightProvider().getSwitches().get(1L), srcPortStatus);
+
+
+        LinkInfo newInfo = linkDiscovery.links.get(lt);
+        assertEquals(srcPortState, newInfo.getSrcPortState());
+        assertEquals(0, newInfo.getDstPortState());
+
+
+        linkDiscovery.handlePortStatus(
+                getMockFloodlightProvider().getSwitches().get(2L), dstPortStatus);
+
+        newInfo = linkDiscovery.links.get(lt);
+        assertEquals(srcPortState, newInfo.getSrcPortState());
+        assertEquals(dstPortState, newInfo.getDstPortState());
+    }
 }