blob: 6e99acdd14d4a70a2143a66becc0e4b9a7dba8fc [file] [log] [blame]
/**
* 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();
}
}