blob: d6c00438e47fc822a1fda9c66867123edd7d00db [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.onrc.onos.core.linkdiscovery;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.test.MockThreadPoolService;
import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.restserver.RestApiServer;
import net.floodlightcontroller.test.FloodlightTestCase;
import net.floodlightcontroller.threadpool.IThreadPoolService;
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;
// CHECKSTYLE IGNORE WriteTag FOR NEXT 2 LINES
/**
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public class LinkDiscoveryManagerTest extends FloodlightTestCase {
private TestLinkDiscoveryManager ldm;
protected static final 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;
}
}
public LinkDiscoveryManager getTopology() {
return ldm;
}
public IOFSwitch createMockSwitch(Long id) {
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(id).anyTimes();
return mockSwitch;
}
@Override
@Before
public void setUp() throws Exception {
super.setUp();
FloodlightModuleContext cntx = new FloodlightModuleContext();
ldm = new TestLinkDiscoveryManager();
//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);
cntx.addService(IFloodlightProviderService.class, getMockFloodlightProvider());
restApi.init(cntx);
tp.init(cntx);
ldm.init(cntx);
restApi.startUp(cntx);
tp.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);
long firstSeenTime = System.currentTimeMillis();
LinkInfo info = new LinkInfo(firstSeenTime,
System.currentTimeMillis(), 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));
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
public void testDeleteLink() throws Exception {
LinkDiscoveryManager topology = getTopology();
Link lt = new Link(1L, 2, 2L, 1);
LinkInfo info = new LinkInfo(System.currentTimeMillis(),
System.currentTimeMillis(), 0, 0);
topology.addOrUpdateLink(lt, info);
topology.deleteLinks(Collections.singletonList(lt));
// 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(), 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(), 0, 0);
topology.addOrUpdateLink(lt, info);
topology.deleteLinks(Collections.singletonList(lt));
// 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(), 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(), 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, 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));
topology.timeOutLinks();
// 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.
info = new LinkInfo(System.currentTimeMillis() - 40000,
System.currentTimeMillis() - 40000, 0, 0);
topology.addOrUpdateLink(lt, info);
// Expect to timeout the unicast Valid Time, so the link should disappear
topology.timeOutLinks();
assertTrue(topology.links.get(lt) == null);
}
/**
* This test case verifies that LinkDiscoveryManager.sendDiscoveryMessage()
* performs "write" operation on the specified IOFSwitch object
* with a LLDP packet.
*
* @throws IOException
*/
@Test
public void testSendDiscoveryMessage() throws IOException {
byte[] macAddress = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x1};
LinkDiscoveryManager topology = getTopology();
// Mock up our expected behavior
IOFSwitch swTest = createMockSwitch(3L);
getMockFloodlightProvider().getSwitches().put(3L, swTest);
short portNum = 1;
OFPhysicalPort ofpPort = new OFPhysicalPort();
ofpPort.setPortNumber(portNum);
ofpPort.setHardwareAddress(macAddress);
/* sendDiscoverMessage() should perform the following actions on
* IOFSwitch object
* - getPort() with argument as "1"
* - write() with OFPacketOut
* - flush()
*/
expect(swTest.getPort(portNum)).andReturn(ofpPort).atLeastOnce();
swTest.write(EasyMock.anyObject(OFMessage.class), EasyMock.anyObject(FloodlightContext.class));
EasyMock.expectLastCall().times(1);
swTest.flush();
EasyMock.expectLastCall().once();
replay(swTest);
topology.sendDiscoveryMessage(3L, portNum, false);
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());
}
}