/**
* 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.capture;
import static org.easymock.EasyMock.createMock;
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 static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IListener.Command;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.internal.IOFSwitchService;
import net.floodlightcontroller.core.internal.MockOFConnection;
import net.floodlightcontroller.core.internal.MockOFSwitchImpl;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.test.MockThreadPoolService;
import net.floodlightcontroller.core.types.NodePortTuple;
import net.floodlightcontroller.debugcounter.IDebugCounterService;
import net.floodlightcontroller.debugcounter.MockDebugCounterService;
import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener;
import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
import net.floodlightcontroller.linkdiscovery.Link;
import net.floodlightcontroller.packet.Data;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPacket;
import net.floodlightcontroller.packet.IPv4;
import net.floodlightcontroller.packet.UDP;
import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.restserver.RestApiServer;
import net.floodlightcontroller.routing.IRoutingService;
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.TopologyManager;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.projectfloodlight.openflow.protocol.OFControllerRole;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPacketInReason;
import org.projectfloodlight.openflow.protocol.OFPortConfig;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFPortFeatures;
import org.projectfloodlight.openflow.protocol.OFPortState;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.MacAddress;
import org.projectfloodlight.openflow.types.OFAuxId;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.U64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @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 getLinkDiscoveryManager() {
return ldm;
}
private IOFSwitch createMockSwitch(Long id) {
IOFSwitch mockSwitch = createNiceMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(DatapathId.of(id)).anyTimes();
return mockSwitch;
}
@Override
@Before
public void setUp() throws Exception {
super.setUp();
FloodlightModuleContext cntx = new FloodlightModuleContext();
ldm = new TestLinkDiscoveryManager();
TopologyManager routingEngine = new TopologyManager();
ldm.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
IDebugCounterService debugCounterService = new MockDebugCounterService();
MockThreadPoolService tp = new MockThreadPoolService();
RestApiServer restApi = new RestApiServer();
MemoryStorageSource storageService = new MemoryStorageSource();
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, storageService);
cntx.addService(IFloodlightProviderService.class, getMockFloodlightProvider());
cntx.addService(IDebugCounterService.class, debugCounterService);
cntx.addService(IOFSwitchService.class, getMockSwitchService());
restApi.init(cntx);
tp.init(cntx);
routingEngine.init(cntx);
storageService.init(cntx);
storageService.startUp(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<DatapathId, IOFSwitch> switches = new HashMap<DatapathId, IOFSwitch>();
switches.put(DatapathId.of(1L), sw1);
switches.put(DatapathId.of(2L), sw2);
getMockSwitchService().setSwitches(switches);
replay(sw1, sw2);
}
@Test
public void testLinkLatency() throws Exception {
LinkDiscoveryManager.LATENCY_HISTORY_SIZE = 5;
LinkDiscoveryManager.LATENCY_UPDATE_THRESHOLD = 0.25;
LinkInfo info = new LinkInfo(new Date(), new Date(), null);
/*
* Should retain initial latency until LATENCY_HISTORY_SIZE
* data points are accumulated.
*/
assertEquals(U64.of(0), info.addObservedLatency(U64.of(0)));
assertEquals(U64.of(0), info.addObservedLatency(U64.of(10)));
assertEquals(U64.of(0), info.addObservedLatency(U64.of(20)));
assertEquals(U64.of(0), info.addObservedLatency(U64.of(30)));
assertEquals(U64.of(20), info.addObservedLatency(U64.of(40)));
/*
* LATENCY_HISTORY_SIZE is maintained. Oldest value is evicted
* per new value added. New average should be computed each
* addition, but latency should not change until current latency
* versus historical average latency differential threshold is
* exceeded again.
*/
assertEquals(U64.of(20), info.addObservedLatency(U64.of(20))); /* avg = 24; diff = 4; 4/24 = 1/6 = 17% !>= 25% --> no update */
assertEquals(U64.of(26), info.addObservedLatency(U64.of(20))); /* avg = 26; diff = 6; 6/20 = 3/10 = 33% >= 25% --> update */
assertEquals(U64.of(26), info.addObservedLatency(U64.of(20))); /* avg = 26; diff = 0; 0/20 = 0/10 = 0% !>= 25% --> no update */
}
@Test
public void testAddOrUpdateLink() throws Exception {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
U64 latency = U64.of(100);
Link lt = new Link(DatapathId.of(1L), OFPort.of(2), DatapathId.of(2L), OFPort.of(1), latency);
LinkInfo info = new LinkInfo(new Date(),
new Date(), null);
linkDiscovery.addOrUpdateLink(lt, info);
NodePortTuple srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(2));
NodePortTuple dstNpt = new NodePortTuple(DatapathId.of(2L), OFPort.of(1));
// check invariants hold
assertNotNull(linkDiscovery.switchLinks.get(lt.getSrc()));
assertTrue(linkDiscovery.switchLinks.get(lt.getSrc()).contains(lt));
assertNotNull(linkDiscovery.getPortLinks().get(srcNpt));
assertTrue(linkDiscovery.getPortLinks().get(srcNpt).contains(lt));
assertNotNull(linkDiscovery.portLinks.get(dstNpt));
assertTrue(linkDiscovery.portLinks.get(dstNpt).contains(lt));
assertTrue(linkDiscovery.links.containsKey(lt));
assertTrue(linkDiscovery.switchLinks.get(lt.getSrc()).iterator().next().getLatency().equals(latency));
}
@Test
public void testDeleteLink() throws Exception {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
Link lt = new Link(DatapathId.of(1L), OFPort.of(2), DatapathId.of(2L), OFPort.of(1), U64.ZERO);
LinkInfo info = new LinkInfo(new Date(),
new Date(), null);
linkDiscovery.addOrUpdateLink(lt, info);
linkDiscovery.deleteLinks(Collections.singletonList(lt), "Test");
// check invariants hold
assertNull(linkDiscovery.switchLinks.get(lt.getSrc()));
assertNull(linkDiscovery.switchLinks.get(lt.getDst()));
assertNull(linkDiscovery.portLinks.get(lt.getSrc()));
assertNull(linkDiscovery.portLinks.get(lt.getDst()));
assertTrue(linkDiscovery.links.isEmpty());
}
@Test
public void testAddOrUpdateLinkToSelf() throws Exception {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
Link lt = new Link(DatapathId.of(1L), OFPort.of(2), DatapathId.of(2L), OFPort.of(3), U64.ZERO);
NodePortTuple srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(2));
NodePortTuple dstNpt = new NodePortTuple(DatapathId.of(2L), OFPort.of(3));
LinkInfo info = new LinkInfo(new Date(),
new Date(), null);
linkDiscovery.addOrUpdateLink(lt, info);
// check invariants hold
assertNotNull(linkDiscovery.switchLinks.get(lt.getSrc()));
assertTrue(linkDiscovery.switchLinks.get(lt.getSrc()).contains(lt));
assertNotNull(linkDiscovery.portLinks.get(srcNpt));
assertTrue(linkDiscovery.portLinks.get(srcNpt).contains(lt));
assertNotNull(linkDiscovery.portLinks.get(dstNpt));
assertTrue(linkDiscovery.portLinks.get(dstNpt).contains(lt));
assertTrue(linkDiscovery.links.containsKey(lt));
}
@Test
public void testDeleteLinkToSelf() throws Exception {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
Link lt = new Link(DatapathId.of(1L), OFPort.of(2), DatapathId.of(1L), OFPort.of(3), U64.ZERO);
NodePortTuple srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(2));
NodePortTuple dstNpt = new NodePortTuple(DatapathId.of(2L), OFPort.of(3));
LinkInfo info = new LinkInfo(new Date(),
new Date(), null);
linkDiscovery.addOrUpdateLink(lt, info);
linkDiscovery.deleteLinks(Collections.singletonList(lt), "Test to self");
// check invariants hold
assertNull(linkDiscovery.switchLinks.get(lt.getSrc()));
assertNull(linkDiscovery.switchLinks.get(lt.getDst()));
assertNull(linkDiscovery.portLinks.get(srcNpt));
assertNull(linkDiscovery.portLinks.get(dstNpt));
assertTrue(linkDiscovery.links.isEmpty());
}
@Test
public void testRemovedSwitch() {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
Link lt = new Link(DatapathId.of(1L), OFPort.of(2), DatapathId.of(2L), OFPort.of(1), U64.ZERO);
NodePortTuple srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(2));
NodePortTuple dstNpt = new NodePortTuple(DatapathId.of(2L), OFPort.of(1));
LinkInfo info = new LinkInfo(new Date(),
new Date(), null);
linkDiscovery.addOrUpdateLink(lt, info);
IOFSwitch sw1 = getMockSwitchService().getSwitch(DatapathId.of(1L));
IOFSwitch sw2 = getMockSwitchService().getSwitch(DatapathId.of(2L));
// Mock up our expected behavior
linkDiscovery.switchRemoved(sw1.getId());
verify(sw1, sw2);
// check invariants hold
assertNull(linkDiscovery.switchLinks.get(lt.getSrc()));
assertNull(linkDiscovery.switchLinks.get(lt.getDst()));
assertNull(linkDiscovery.portLinks.get(srcNpt));
assertNull(linkDiscovery.portLinks.get(dstNpt));
assertTrue(linkDiscovery.links.isEmpty());
}
@Test
public void testRemovedSwitchSelf() {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
IOFSwitch sw1 = createMockSwitch(1L);
replay(sw1);
Link lt = new Link(DatapathId.of(1L), OFPort.of(2), DatapathId.of(1L), OFPort.of(3), U64.ZERO);
LinkInfo info = new LinkInfo(new Date(),
new Date(), null);
linkDiscovery.addOrUpdateLink(lt, info);
// Mock up our expected behavior
linkDiscovery.switchRemoved(sw1.getId());
verify(sw1);
// check invariants hold
assertNull(linkDiscovery.switchLinks.get(lt.getSrc()));
assertNull(linkDiscovery.portLinks.get(lt.getSrc()));
assertNull(linkDiscovery.portLinks.get(lt.getDst()));
assertTrue(linkDiscovery.links.isEmpty());
}
@Test
public void testAddUpdateLinks() throws Exception {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
Link lt = new Link(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(1), U64.ZERO);
NodePortTuple srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(1));
NodePortTuple dstNpt = new NodePortTuple(DatapathId.of(2L), OFPort.of(1));
LinkInfo info;
info = new LinkInfo(new Date(System.currentTimeMillis() - 40000),
new Date(System.currentTimeMillis() - 40000), null);
linkDiscovery.addOrUpdateLink(lt, info);
// check invariants hold
assertNotNull(linkDiscovery.switchLinks.get(lt.getSrc()));
assertTrue(linkDiscovery.switchLinks.get(lt.getSrc()).contains(lt));
assertNotNull(linkDiscovery.portLinks.get(srcNpt));
assertTrue(linkDiscovery.portLinks.get(srcNpt).contains(lt));
assertNotNull(linkDiscovery.portLinks.get(dstNpt));
assertTrue(linkDiscovery.portLinks.get(dstNpt).contains(lt));
assertTrue(linkDiscovery.links.containsKey(lt));
linkDiscovery.timeoutLinks();
info = new LinkInfo(new Date(),/* firstseen */
null,/* unicast */
new Date());
linkDiscovery.addOrUpdateLink(lt, info);
assertTrue(linkDiscovery.links.get(lt).getUnicastValidTime() == null);
assertTrue(linkDiscovery.links.get(lt).getMulticastValidTime() != null);
// 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(new Date(System.currentTimeMillis() - 40000),
new Date(System.currentTimeMillis() - 40000), null);
linkDiscovery.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.
linkDiscovery.timeoutLinks();
assertTrue(linkDiscovery.links.get(lt).getUnicastValidTime() == null);
assertTrue(linkDiscovery.links.get(lt).getMulticastValidTime() != null);
// Set the multicastValidTime to be old and see if that also times out.
info = new LinkInfo(new Date(System.currentTimeMillis() - 40000),
null, new Date(System.currentTimeMillis() - 40000));
linkDiscovery.addOrUpdateLink(lt, info);
linkDiscovery.timeoutLinks();
assertTrue(linkDiscovery.links.get(lt) == null);
// Test again only with multicast LLDP
info = new LinkInfo(new Date(System.currentTimeMillis() - 40000),
null, new Date(System.currentTimeMillis() - 40000));
linkDiscovery.addOrUpdateLink(lt, info);
assertTrue(linkDiscovery.links.get(lt).getUnicastValidTime() == null);
assertTrue(linkDiscovery.links.get(lt).getMulticastValidTime() != null);
// Call timeout and check if link is no longer present.
linkDiscovery.timeoutLinks();
assertTrue(linkDiscovery.links.get(lt) == null);
// Start clean and see if loops are also added.
lt = new Link(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(2), U64.ZERO);
srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(1));
dstNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(2));
info = new LinkInfo(new Date(System.currentTimeMillis() - 40000),
null, new Date(System.currentTimeMillis() - 40000));
linkDiscovery.addOrUpdateLink(lt, info);
// Start clean and see if loops are also added.
lt = new Link(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO);
srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(1));
dstNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(3));
info = new LinkInfo(new Date(System.currentTimeMillis() - 40000),
null, new Date(System.currentTimeMillis() - 40000));
linkDiscovery.addOrUpdateLink(lt, info);
// Start clean and see if loops are also added.
lt = new Link(DatapathId.of(1L), OFPort.of(4), DatapathId.of(1L), OFPort.of(5), U64.ZERO);
srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(4));
dstNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(5));
info = new LinkInfo(new Date(System.currentTimeMillis() - 40000),
null, new Date(System.currentTimeMillis() - 40000));
linkDiscovery.addOrUpdateLink(lt, info);
// Start clean and see if loops are also added.
lt = new Link(DatapathId.of(1L), OFPort.of(3), DatapathId.of(1L), OFPort.of(5), U64.ZERO);
srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(3));
dstNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(5));
info = new LinkInfo(new Date(System.currentTimeMillis() - 40000),
null, new Date(System.currentTimeMillis() - 40000));
linkDiscovery.addOrUpdateLink(lt, info);
}
@Test
public void testHARoleChange() throws Exception {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
IOFSwitch sw1 = createMockSwitch(1L);
IOFSwitch sw2 = createMockSwitch(2L);
replay(sw1, sw2);
Link lt = new Link(DatapathId.of(1L), OFPort.of(2), DatapathId.of(2L), OFPort.of(1), U64.ZERO);
NodePortTuple srcNpt = new NodePortTuple(DatapathId.of(1L), OFPort.of(2));
NodePortTuple dstNpt = new NodePortTuple(DatapathId.of(2L), OFPort.of(1));
LinkInfo info = new LinkInfo(new Date(),
new Date(), null);
linkDiscovery.addOrUpdateLink(lt, info);
// check invariants hold
assertNotNull(linkDiscovery.switchLinks.get(lt.getSrc()));
assertTrue(linkDiscovery.switchLinks.get(lt.getSrc()).contains(lt));
assertNotNull(linkDiscovery.portLinks.get(srcNpt));
assertTrue(linkDiscovery.portLinks.get(srcNpt).contains(lt));
assertNotNull(linkDiscovery.portLinks.get(dstNpt));
assertTrue(linkDiscovery.portLinks.get(dstNpt).contains(lt));
assertTrue(linkDiscovery.links.containsKey(lt));
/* FIXME: what's the right thing to do here:
// check that it clears from memory
getMockFloodlightProvider().dispatchRoleChanged(Role.SLAVE);
assertTrue(linkDiscovery.switchLinks.isEmpty());
getMockFloodlightProvider().dispatchRoleChanged(Role.MASTER);
// check that lldps were sent
assertTrue(ldm.isSendLLDPsCalled);
assertTrue(ldm.isClearLinksCalled);
ldm.reset();
*/
}
@Test
public void testDontSendLLDPinSlave() throws Exception {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
OFPortDesc pd = createMock(OFPortDesc.class);
expect(pd.getHwAddr()).andReturn(MacAddress.of(1)).anyTimes();
expect(pd.getPortNo()).andReturn(OFPort.of(1)).anyTimes();
expect(pd.getName()).andReturn("1").anyTimes();
expect(pd.getConfig()).andReturn(Collections.<OFPortConfig> emptySet()).anyTimes();
expect(pd.getState()).andReturn(Collections.<OFPortState> emptySet()).anyTimes();
replay(pd);
/*OFPortDesc pd = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc()
.setHwAddr(MacAddress.of(1))
.setPortNo(OFPort.of(1))
.build();*/
MockOFConnection c3 = new MockOFConnection(DatapathId.of(3), OFAuxId.MAIN);
c3.updateLatency(U64.ZERO);
MockOFSwitchImpl sw3 = new MockOFSwitchImpl(c3);
sw3.setControllerRole(OFControllerRole.ROLE_MASTER);
sw3.setPorts(Collections.singleton(pd));
MockOFConnection c4 = new MockOFConnection(DatapathId.of(4), OFAuxId.MAIN);
c4.updateLatency(U64.ZERO);
MockOFSwitchImpl sw4 = new MockOFSwitchImpl(c4);
sw4.setControllerRole(OFControllerRole.ROLE_SLAVE);
sw4.setPorts(Collections.singleton(pd));
MockOFConnection c5 = new MockOFConnection(DatapathId.of(5), OFAuxId.MAIN);
c5.updateLatency(U64.ZERO);
MockOFSwitchImpl sw5 = new MockOFSwitchImpl(c5);
sw5.setControllerRole(OFControllerRole.ROLE_EQUAL);
sw5.setPorts(Collections.singleton(pd));
Map<DatapathId, IOFSwitch> newSwitches = new HashMap<DatapathId, IOFSwitch>(linkDiscovery.switchService.getAllSwitchMap());
newSwitches.put(DatapathId.of(3), sw3);
newSwitches.put(DatapathId.of(4), sw4);
newSwitches.put(DatapathId.of(5), sw5);
getMockSwitchService().setSwitches(newSwitches);
boolean pass = false;
try {
linkDiscovery.sendDiscoveryMessage(DatapathId.of(3L), OFPort.of(1), true, false);
} catch (IllegalArgumentException e) { /* expected exception, since we aren't wired to write packets */
log.info("LLDP packet-out sent while in MASTER (pass)");
pass = true;
}
assertTrue("LLDP packet-out NOT sent while in MASTER (fail)", pass);
assertFalse("LLDP packet-out DID occur while in SLAVE (fail)",
linkDiscovery.sendDiscoveryMessage(DatapathId.of(4L), OFPort.of(1), true, false));
log.info("LLDP packet-out did not occur while in SLAVE (pass)");
pass = false;
try {
linkDiscovery.sendDiscoveryMessage(DatapathId.of(5L), OFPort.of(1), true, false);
} catch (IllegalArgumentException e) { /* expected exception, since we aren't wired to write packets */
log.info("LLDP packet-out sent while in EQUAL/OTHER (pass)");
pass = true;
}
assertTrue("LLDP packet-out NOT sent while in EQUAL/OTHER (fail)", pass);
}
@Test
public void testSwitchAdded() throws Exception {
LinkDiscoveryManager linkDiscovery = getLinkDiscoveryManager();
linkDiscovery.switchService = getMockSwitchService();
Capture<OFMessage> wc;
Set<OFPort> qPorts;
OFPortDesc ofpp = OFFactories.getFactory(OFVersion.OF_13).buildPortDesc()
.setName("eth4242")
.setPortNo(OFPort.of(4242))
.setHwAddr(MacAddress.of("5c:16:c7:00:00:01"))
.setCurr(new HashSet<OFPortFeatures>()) // random
.build();
IOFSwitch sw1 = createMockSwitch(1L);
// Set switch map in floodlightProvider.
Map<DatapathId, IOFSwitch> switches = new HashMap<DatapathId, IOFSwitch>();
switches.put(DatapathId.of(1L), sw1);
getMockSwitchService().setSwitches(switches);
// Create the set of ports
List<OFPort> ports = new ArrayList<OFPort>();
for(short p=1; p<=20; ++p) {
ports.add(OFPort.of(p));
}
// Set the captures.
wc = EasyMock.newCapture(CaptureType.ALL);
// Expect switch to return those ports.
expect(sw1.getEnabledPortNumbers()).andReturn(ports).anyTimes();
expect(sw1.getPort(OFPort.of(EasyMock.anyInt()))).andReturn(ofpp).anyTimes();
expect(sw1.getOFFactory()).andReturn(OFFactories.getFactory(OFVersion.OF_13)).anyTimes();
expect(sw1.getLatency()).andReturn(U64.ZERO).anyTimes();
expect(sw1.write(capture(wc))).andReturn(true).anyTimes();
replay(sw1);
linkDiscovery.switchActivated(sw1.getId());
verify(sw1);
qPorts = linkDiscovery.getQuarantinedPorts(sw1.getId());
assertNotNull(qPorts);
assertFalse(qPorts.isEmpty());
Thread.sleep(100);
qPorts = linkDiscovery.getQuarantinedPorts(sw1.getId());
assertNotNull(qPorts);
assertFalse(qPorts.isEmpty());
Thread.sleep(200);
qPorts = linkDiscovery.getQuarantinedPorts(sw1.getId());
assertNotNull(qPorts);
assertTrue(qPorts.isEmpty());
// Ensure that through every switch port, an LLDP and BDDP
// packet was sent out. Total # of packets = # of ports * 2.
assertTrue(wc.hasCaptured());
List<OFMessage> msgList = wc.getValues();
assertTrue(msgList.size() == ports.size() * 2);
}
private OFPacketIn createPacketIn(String srcMAC, String dstMAC,
String srcIp, String dstIp, short vlan) {
IPacket testPacket = new Ethernet()
.setDestinationMACAddress(dstMAC)
.setSourceMACAddress(srcMAC)
.setVlanID(vlan)
.setEtherType(EthType.IPv4)
.setPayload(
new IPv4()
.setTtl((byte) 128)
.setSourceAddress(srcIp)
.setDestinationAddress(dstIp)
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
byte[] testPacketSerialized = testPacket.serialize();
OFPacketIn pi;
// build out input packet
pi = OFFactories.getFactory(OFVersion.OF_13).buildPacketIn()
.setBufferId(OFBufferId.NO_BUFFER)
.setData(testPacketSerialized)
.setReason(OFPacketInReason.NO_MATCH)
.build();
return pi;
}
@Test
public void testIgnoreSrcMAC() throws Exception {
String mac1 = "00:11:22:33:44:55";
String mac2 = "00:44:33:22:11:00";
String mac3 = "00:44:33:22:11:02";
String srcIp = "192.168.1.1";
String dstIp = "192.168.1.2";
short vlan = 42;
IOFSwitch mockSwitch = createMock(IOFSwitch.class);
expect(mockSwitch.getId()).andReturn(DatapathId.of(1L)).anyTimes();
replay(mockSwitch);
/* TEST1: See basic packet flow */
OFPacketIn pi;
pi = createPacketIn(mac1, mac2, srcIp, dstIp, vlan);
FloodlightContext cntx = new FloodlightContext();
Ethernet eth = new Ethernet();
eth.deserialize(pi.getData(), 0, pi.getData().length);
IFloodlightProviderService.bcStore.put(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
eth);
Command ret;
ret = ldm.receive(mockSwitch, pi, cntx);
assertEquals(Command.CONTINUE, ret);
/* TEST2: Add mac1 to the ignore MAC list and see that the packet is
* dropped
*/
ldm.addMACToIgnoreList(MacAddress.of(mac1), 0);
ret = ldm.receive(mockSwitch, pi, cntx);
assertEquals(Command.STOP, ret);
/* Verify that if we send a packet with another MAC it still works */
pi = createPacketIn(mac2, mac3, srcIp, dstIp, vlan);
cntx = new FloodlightContext();
eth = new Ethernet();
eth.deserialize(pi.getData(), 0, pi.getData().length);
IFloodlightProviderService.bcStore.put(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
eth);
ret = ldm.receive(mockSwitch, pi, cntx);
assertEquals(Command.CONTINUE, ret);
/* TEST3: Add a MAC range and see if that is ignored */
ldm.addMACToIgnoreList(MacAddress.of(mac2), 8);
ret = ldm.receive(mockSwitch, pi, cntx);
assertEquals(Command.STOP, ret);
/* Send a packet with source MAC as mac3 and see that that is ignored
* as well.
*/
pi = createPacketIn(mac3, mac1, srcIp, dstIp, vlan);
cntx = new FloodlightContext();
eth = new Ethernet();
eth.deserialize(pi.getData(), 0, pi.getData().length);
IFloodlightProviderService.bcStore.put(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
eth);
ret = ldm.receive(mockSwitch, pi, cntx);
assertEquals(Command.STOP, ret);
verify(mockSwitch);
}
}