| /** |
| * Copyright 2011, Big Switch Networks, Inc. |
| * Originally created by David Erickson, Stanford University |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may |
| * not use this file except in compliance with the License. You may obtain |
| * a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| **/ |
| |
| package net.floodlightcontroller.linkdiscovery.internal; |
| |
| import static org.easymock.EasyMock.*; |
| |
| import java.util.Collections; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import net.floodlightcontroller.core.IFloodlightProviderService; |
| import net.floodlightcontroller.core.IFloodlightProviderService.Role; |
| import net.floodlightcontroller.core.IOFSwitch; |
| import net.floodlightcontroller.core.module.FloodlightModuleContext; |
| import net.floodlightcontroller.core.test.MockThreadPoolService; |
| import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener; |
| import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; |
| import net.floodlightcontroller.linkdiscovery.LinkInfo; |
| import net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager; |
| import net.floodlightcontroller.restserver.IRestApiService; |
| import net.floodlightcontroller.restserver.RestApiServer; |
| import net.floodlightcontroller.routing.IRoutingService; |
| import net.floodlightcontroller.routing.Link; |
| import net.floodlightcontroller.storage.IStorageSourceService; |
| import net.floodlightcontroller.storage.memory.MemoryStorageSource; |
| import net.floodlightcontroller.test.FloodlightTestCase; |
| import net.floodlightcontroller.threadpool.IThreadPoolService; |
| import net.floodlightcontroller.topology.ITopologyService; |
| import net.floodlightcontroller.topology.NodePortTuple; |
| import net.floodlightcontroller.topology.TopologyManager; |
| |
| /** |
| * |
| * @author David Erickson (daviderickson@cs.stanford.edu) |
| */ |
| public class LinkDiscoveryManagerTest extends FloodlightTestCase { |
| |
| private TestLinkDiscoveryManager ldm; |
| protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManagerTest.class); |
| |
| public class TestLinkDiscoveryManager extends LinkDiscoveryManager { |
| public boolean isSendLLDPsCalled = false; |
| public boolean isClearLinksCalled = false; |
| |
| @Override |
| protected void discoverOnAllPorts() { |
| isSendLLDPsCalled = true; |
| super.discoverOnAllPorts(); |
| } |
| |
| public void reset() { |
| isSendLLDPsCalled = false; |
| isClearLinksCalled = false; |
| } |
| |
| @Override |
| protected void clearAllLinks() { |
| isClearLinksCalled = true; |
| super.clearAllLinks(); |
| } |
| } |
| |
| public LinkDiscoveryManager getTopology() { |
| return ldm; |
| } |
| |
| public IOFSwitch createMockSwitch(Long id) { |
| IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class); |
| expect(mockSwitch.getId()).andReturn(id).anyTimes(); |
| return mockSwitch; |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| super.setUp(); |
| FloodlightModuleContext cntx = new FloodlightModuleContext(); |
| ldm = new TestLinkDiscoveryManager(); |
| TopologyManager routingEngine = new TopologyManager(); |
| ldm.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>(); |
| MockThreadPoolService tp = new MockThreadPoolService(); |
| RestApiServer restApi = new RestApiServer(); |
| cntx.addService(IRestApiService.class, restApi); |
| cntx.addService(IThreadPoolService.class, tp); |
| cntx.addService(IRoutingService.class, routingEngine); |
| cntx.addService(ILinkDiscoveryService.class, ldm); |
| cntx.addService(ITopologyService.class, ldm); |
| cntx.addService(IStorageSourceService.class, new MemoryStorageSource()); |
| cntx.addService(IFloodlightProviderService.class, getMockFloodlightProvider()); |
| restApi.init(cntx); |
| tp.init(cntx); |
| routingEngine.init(cntx); |
| ldm.init(cntx); |
| restApi.startUp(cntx); |
| tp.startUp(cntx); |
| routingEngine.startUp(cntx); |
| ldm.startUp(cntx); |
| |
| IOFSwitch sw1 = createMockSwitch(1L); |
| IOFSwitch sw2 = createMockSwitch(2L); |
| Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); |
| switches.put(1L, sw1); |
| switches.put(2L, sw2); |
| getMockFloodlightProvider().setSwitches(switches); |
| replay(sw1, sw2); |
| } |
| |
| @Test |
| public void testAddOrUpdateLink() throws Exception { |
| LinkDiscoveryManager topology = getTopology(); |
| |
| Link lt = new Link(1L, 2, 2L, 1); |
| LinkInfo info = new LinkInfo(System.currentTimeMillis(), |
| System.currentTimeMillis(), null, |
| 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| |
| |
| NodePortTuple srcNpt = new NodePortTuple(1L, 2); |
| NodePortTuple dstNpt = new NodePortTuple(2L, 1); |
| |
| // check invariants hold |
| assertNotNull(topology.switchLinks.get(lt.getSrc())); |
| assertTrue(topology.switchLinks.get(lt.getSrc()).contains(lt)); |
| assertNotNull(topology.portLinks.get(srcNpt)); |
| assertTrue(topology.portLinks.get(srcNpt).contains(lt)); |
| assertNotNull(topology.portLinks.get(dstNpt)); |
| assertTrue(topology.portLinks.get(dstNpt).contains(lt)); |
| assertTrue(topology.links.containsKey(lt)); |
| } |
| |
| @Test |
| public void testDeleteLink() throws Exception { |
| LinkDiscoveryManager topology = getTopology(); |
| |
| Link lt = new Link(1L, 2, 2L, 1); |
| LinkInfo info = new LinkInfo(System.currentTimeMillis(), |
| System.currentTimeMillis(), null, |
| 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| topology.deleteLinks(Collections.singletonList(lt), "Test"); |
| |
| // check invariants hold |
| assertNull(topology.switchLinks.get(lt.getSrc())); |
| assertNull(topology.switchLinks.get(lt.getDst())); |
| assertNull(topology.portLinks.get(lt.getSrc())); |
| assertNull(topology.portLinks.get(lt.getDst())); |
| assertTrue(topology.links.isEmpty()); |
| } |
| |
| @Test |
| public void testAddOrUpdateLinkToSelf() throws Exception { |
| LinkDiscoveryManager topology = getTopology(); |
| |
| Link lt = new Link(1L, 2, 2L, 3); |
| NodePortTuple srcNpt = new NodePortTuple(1L, 2); |
| NodePortTuple dstNpt = new NodePortTuple(2L, 3); |
| |
| LinkInfo info = new LinkInfo(System.currentTimeMillis(), |
| System.currentTimeMillis(), null, |
| 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| |
| // check invariants hold |
| assertNotNull(topology.switchLinks.get(lt.getSrc())); |
| assertTrue(topology.switchLinks.get(lt.getSrc()).contains(lt)); |
| assertNotNull(topology.portLinks.get(srcNpt)); |
| assertTrue(topology.portLinks.get(srcNpt).contains(lt)); |
| assertNotNull(topology.portLinks.get(dstNpt)); |
| assertTrue(topology.portLinks.get(dstNpt).contains(lt)); |
| assertTrue(topology.links.containsKey(lt)); |
| } |
| |
| @Test |
| public void testDeleteLinkToSelf() throws Exception { |
| LinkDiscoveryManager topology = getTopology(); |
| |
| Link lt = new Link(1L, 2, 1L, 3); |
| NodePortTuple srcNpt = new NodePortTuple(1L, 2); |
| NodePortTuple dstNpt = new NodePortTuple(2L, 3); |
| |
| LinkInfo info = new LinkInfo(System.currentTimeMillis(), |
| System.currentTimeMillis(), null, |
| 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| topology.deleteLinks(Collections.singletonList(lt), "Test to self"); |
| |
| // check invariants hold |
| assertNull(topology.switchLinks.get(lt.getSrc())); |
| assertNull(topology.switchLinks.get(lt.getDst())); |
| assertNull(topology.portLinks.get(srcNpt)); |
| assertNull(topology.portLinks.get(dstNpt)); |
| assertTrue(topology.links.isEmpty()); |
| } |
| |
| @Test |
| public void testRemovedSwitch() { |
| LinkDiscoveryManager topology = getTopology(); |
| |
| Link lt = new Link(1L, 2, 2L, 1); |
| NodePortTuple srcNpt = new NodePortTuple(1L, 2); |
| NodePortTuple dstNpt = new NodePortTuple(2L, 1); |
| LinkInfo info = new LinkInfo(System.currentTimeMillis(), |
| System.currentTimeMillis(), null, |
| 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| |
| IOFSwitch sw1 = getMockFloodlightProvider().getSwitches().get(1L); |
| IOFSwitch sw2 = getMockFloodlightProvider().getSwitches().get(2L); |
| // Mock up our expected behavior |
| topology.removedSwitch(sw1); |
| verify(sw1, sw2); |
| |
| // check invariants hold |
| assertNull(topology.switchLinks.get(lt.getSrc())); |
| assertNull(topology.switchLinks.get(lt.getDst())); |
| assertNull(topology.portLinks.get(srcNpt)); |
| assertNull(topology.portLinks.get(dstNpt)); |
| assertTrue(topology.links.isEmpty()); |
| } |
| |
| @Test |
| public void testRemovedSwitchSelf() { |
| LinkDiscoveryManager topology = getTopology(); |
| IOFSwitch sw1 = createMockSwitch(1L); |
| replay(sw1); |
| Link lt = new Link(1L, 2, 1L, 3); |
| LinkInfo info = new LinkInfo(System.currentTimeMillis(), |
| System.currentTimeMillis(), null, |
| 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| |
| // Mock up our expected behavior |
| topology.removedSwitch(sw1); |
| |
| verify(sw1); |
| // check invariants hold |
| assertNull(topology.switchLinks.get(lt.getSrc())); |
| assertNull(topology.portLinks.get(lt.getSrc())); |
| assertNull(topology.portLinks.get(lt.getDst())); |
| assertTrue(topology.links.isEmpty()); |
| } |
| |
| @Test |
| public void testAddUpdateLinks() throws Exception { |
| LinkDiscoveryManager topology = getTopology(); |
| |
| Link lt = new Link(1L, 1, 2L, 1); |
| NodePortTuple srcNpt = new NodePortTuple(1L, 1); |
| NodePortTuple dstNpt = new NodePortTuple(2L, 1); |
| |
| LinkInfo info; |
| |
| info = new LinkInfo(System.currentTimeMillis() - 40000, |
| System.currentTimeMillis() - 40000, null, |
| 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| |
| // check invariants hold |
| assertNotNull(topology.switchLinks.get(lt.getSrc())); |
| assertTrue(topology.switchLinks.get(lt.getSrc()).contains(lt)); |
| assertNotNull(topology.portLinks.get(srcNpt)); |
| assertTrue(topology.portLinks.get(srcNpt).contains(lt)); |
| assertNotNull(topology.portLinks.get(dstNpt)); |
| assertTrue(topology.portLinks.get(dstNpt).contains(lt)); |
| assertTrue(topology.links.containsKey(lt)); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt) == null || |
| topology.portBroadcastDomainLinks.get(srcNpt).contains(lt) == false); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt) == null || |
| topology.portBroadcastDomainLinks.get(dstNpt).contains(lt) == false); |
| |
| topology.timeoutLinks(); |
| |
| |
| info = new LinkInfo(System.currentTimeMillis(),/* firstseen */ |
| null,/* unicast */ |
| System.currentTimeMillis(), 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| assertTrue(topology.links.get(lt).getUnicastValidTime() == null); |
| assertTrue(topology.links.get(lt).getMulticastValidTime() != null); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); |
| |
| |
| // Add a link info based on info that woudld 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. |
| info = new LinkInfo(System.currentTimeMillis() - 40000, |
| System.currentTimeMillis() - 40000, null, 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt) == null || |
| topology.portBroadcastDomainLinks.get(srcNpt).contains(lt) == false); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt) == null || |
| topology.portBroadcastDomainLinks.get(dstNpt).contains(lt) == false); |
| |
| // Expect to timeout the unicast Valid Time, but not the multicast Valid time |
| // So the link type should go back to non-openflow link. |
| topology.timeoutLinks(); |
| assertTrue(topology.links.get(lt).getUnicastValidTime() == null); |
| assertTrue(topology.links.get(lt).getMulticastValidTime() != null); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); |
| |
| // Set the multicastValidTime to be old and see if that also times out. |
| info = new LinkInfo(System.currentTimeMillis() - 40000, |
| null, System.currentTimeMillis() - 40000, 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| topology.timeoutLinks(); |
| assertTrue(topology.links.get(lt) == null); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt) == null || |
| topology.portBroadcastDomainLinks.get(srcNpt).contains(lt) == false); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt) == null || |
| topology.portBroadcastDomainLinks.get(dstNpt).contains(lt) == false); |
| |
| |
| // Test again only with multicast LLDP |
| info = new LinkInfo(System.currentTimeMillis() - 40000, |
| null, System.currentTimeMillis() - 40000, 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| assertTrue(topology.links.get(lt).getUnicastValidTime() == null); |
| assertTrue(topology.links.get(lt).getMulticastValidTime() != null); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); |
| |
| // Call timeout and check if link is no longer present. |
| topology.timeoutLinks(); |
| assertTrue(topology.links.get(lt) == null); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt) == null || |
| topology.portBroadcastDomainLinks.get(srcNpt).contains(lt) == false); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt) == null || |
| topology.portBroadcastDomainLinks.get(dstNpt).contains(lt) == false); |
| |
| // Start clean and see if loops are also added. |
| lt = new Link(1L, 1, 1L, 2); |
| srcNpt = new NodePortTuple(1L, 1); |
| dstNpt = new NodePortTuple(1L, 2); |
| info = new LinkInfo(System.currentTimeMillis() - 40000, |
| null, System.currentTimeMillis() - 40000, 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); |
| |
| |
| // Start clean and see if loops are also added. |
| lt = new Link(1L, 1, 1L, 3); |
| srcNpt = new NodePortTuple(1L, 1); |
| dstNpt = new NodePortTuple(1L, 3); |
| info = new LinkInfo(System.currentTimeMillis() - 40000, |
| null, System.currentTimeMillis() - 40000, 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); |
| |
| |
| // Start clean and see if loops are also added. |
| lt = new Link(1L, 4, 1L, 5); |
| srcNpt = new NodePortTuple(1L, 4); |
| dstNpt = new NodePortTuple(1L, 5); |
| info = new LinkInfo(System.currentTimeMillis() - 40000, |
| null, System.currentTimeMillis() - 40000, 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); |
| |
| |
| // Start clean and see if loops are also added. |
| lt = new Link(1L, 3, 1L, 5); |
| srcNpt = new NodePortTuple(1L, 3); |
| dstNpt = new NodePortTuple(1L, 5); |
| info = new LinkInfo(System.currentTimeMillis() - 40000, |
| null, System.currentTimeMillis() - 40000, 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| assertTrue(topology.portBroadcastDomainLinks.get(srcNpt).contains(lt)); |
| assertTrue(topology.portBroadcastDomainLinks.get(dstNpt).contains(lt)); |
| } |
| |
| @Test |
| public void testHARoleChange() throws Exception { |
| LinkDiscoveryManager topology = getTopology(); |
| IOFSwitch sw1 = createMockSwitch(1L); |
| IOFSwitch sw2 = createMockSwitch(2L); |
| replay(sw1, sw2); |
| Link lt = new Link(1L, 2, 2L, 1); |
| NodePortTuple srcNpt = new NodePortTuple(1L, 2); |
| NodePortTuple dstNpt = new NodePortTuple(2L, 1); |
| LinkInfo info = new LinkInfo(System.currentTimeMillis(), |
| System.currentTimeMillis(), null, |
| 0, 0); |
| topology.addOrUpdateLink(lt, info); |
| |
| // check invariants hold |
| assertNotNull(topology.switchLinks.get(lt.getSrc())); |
| assertTrue(topology.switchLinks.get(lt.getSrc()).contains(lt)); |
| assertNotNull(topology.portLinks.get(srcNpt)); |
| assertTrue(topology.portLinks.get(srcNpt).contains(lt)); |
| assertNotNull(topology.portLinks.get(dstNpt)); |
| assertTrue(topology.portLinks.get(dstNpt).contains(lt)); |
| assertTrue(topology.links.containsKey(lt)); |
| |
| // check that it clears from memory |
| getMockFloodlightProvider().dispatchRoleChanged(null, Role.SLAVE); |
| assertTrue(topology.switchLinks.isEmpty()); |
| getMockFloodlightProvider().dispatchRoleChanged(Role.SLAVE, Role.MASTER); |
| // check that lldps were sent |
| assertTrue(ldm.isSendLLDPsCalled); |
| assertTrue(ldm.isClearLinksCalled); |
| ldm.reset(); |
| } |
| } |