/* * Copyright (c) 2013 Big Switch Networks, Inc. * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html * * 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 org.sdnplatform.linkdiscovery; import static org.easymock.EasyMock.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.easymock.Capture; import org.easymock.CaptureType; 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.OFPhysicalPort.OFPortFeatures; import org.openflow.util.HexString; import org.sdnplatform.core.ListenerContext; import org.sdnplatform.core.IControllerService; import org.sdnplatform.core.IOFSwitch; import org.sdnplatform.core.module.ModuleContext; import org.sdnplatform.core.test.MockThreadPoolService; import org.sdnplatform.linkdiscovery.BetterLinkDiscoveryManager; import org.sdnplatform.linkdiscovery.ILinkDiscovery; import org.sdnplatform.linkdiscovery.LinkInfo; import org.sdnplatform.routing.Link; import org.sdnplatform.storage.IStorageSourceService; import org.sdnplatform.storage.memory.MemoryStorageSource; import org.sdnplatform.test.PlatformTestCase; import org.sdnplatform.threadpool.IThreadPoolService; import org.sdnplatform.tunnelmanager.ITunnelManagerService; public class BetterLinkDiscoveryManagerTest extends PlatformTestCase{ BetterLinkDiscoveryManager bldm; IOFSwitch sw1, sw2; OFPhysicalPort p1, p2; Link lt; LinkInfo info; ITunnelManagerService tunnelManager; @Before public void setUp() throws Exception { super.setUp(); ModuleContext cntx = new ModuleContext(); MockThreadPoolService tp = new MockThreadPoolService(); tunnelManager = createMock(ITunnelManagerService.class); cntx.addService(ITunnelManagerService.class, tunnelManager); cntx.addService(IControllerService.class, getMockControllerProvider()); cntx.addService(IThreadPoolService.class, tp); cntx.addService(IStorageSourceService.class, new MemoryStorageSource()); bldm = new BetterLinkDiscoveryManager(); bldm.init(cntx); tp.init(cntx); bldm.startUp(cntx); tp.startUp(cntx); sw1 = createNiceMock(IOFSwitch.class); sw2 = createNiceMock(IOFSwitch.class); expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw2.getId()).andReturn(2L).anyTimes(); p1 = new OFPhysicalPort(); p2 = new OFPhysicalPort(); expect(sw1.getPort((short)1)).andReturn(p1).anyTimes(); expect(sw2.getPort((short)1)).andReturn(p2).anyTimes(); lt = new Link(1L, (short)1, 2L, (short)1); info = new LinkInfo(System.currentTimeMillis(), System.currentTimeMillis(), null, 0, 0); Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); switches.put(1L, sw1); switches.put(2L, sw2); getMockControllerProvider().setSwitches(switches); replay(sw1, sw2); } /** * Test to verify if the tunnel link classification works fine or not. * It is sufficient to specify the tunnelManager expect methods for * switch 1 due to the short-circuiting nature of the if () statement * in the getLinkType() method. */ @Test public void testLinkTypeTunnel() { expect(tunnelManager.getTunnelPortNumber(1L)).andReturn(new Short((short)1)).once(); replay(tunnelManager); assertTrue(bldm.getLinkType(lt, info) == ILinkDiscovery.LinkType.TUNNEL); verify(tunnelManager); reset(tunnelManager); expect(tunnelManager.getTunnelPortNumber(1L)).andReturn(null); expect(tunnelManager.getTunnelPortNumber(2L)).andReturn(null); replay(tunnelManager); assertTrue(bldm.getLinkType(lt, info) == ILinkDiscovery.LinkType.DIRECT_LINK); verify(tunnelManager); } /** * In this case, autoportfast is disabled; and autoneg is ON. * @throws Exception */ @Test public void testSwitchAddedCase1() throws Exception { BetterLinkDiscoveryManager linkDiscovery = bldm; Capture<OFMessage> wc; Capture<ListenerContext> fc; Set<Short> qPorts; OFPhysicalPort p1 = new OFPhysicalPort(); p1.setHardwareAddress(HexString.fromHexString("5c:16:c7:00:00:01")); IOFSwitch sw1 = createMock(IOFSwitch.class); // Set switch map in controllerProvider. Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); switches.put(1L, sw1); getMockControllerProvider().setSwitches(switches); // Create the set of ports List<Short> ports = new ArrayList<Short>(); for(short p=1; p<=10; ++p) { ports.add(p); } // Set the captures. wc = new Capture<OFMessage>(CaptureType.ALL); fc = new Capture<ListenerContext>(CaptureType.ALL); // Expect switch to return those ports. expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw1.getActions()).andReturn(1).anyTimes(); expect(sw1.getEnabledPortNumbers()).andReturn(ports).anyTimes(); expect(sw1.getPort(EasyMock.anyShort())).andReturn(p1).anyTimes(); expect(sw1.isFastPort(EasyMock.anyShort())).andReturn(false).anyTimes(); sw1.write(capture(wc), capture(fc)); expectLastCall().anyTimes(); sw1.flush(); expectLastCall().anyTimes(); expect(sw1.getInetAddress()).andReturn(null); expect(tunnelManager.getTunnelPortNumber(EasyMock.anyLong())).andReturn(null).anyTimes(); replay(sw1, tunnelManager); // Set autoportfast feature to false linkDiscovery.setAutoPortFastFeature(false); // set the port autoneg feature to ON. p1.setCurrentFeatures(OFPortFeatures.OFPPF_AUTONEG.getValue()); linkDiscovery.addedSwitch(sw1); verify(sw1, tunnelManager); 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); } /** * In this case, autoportfast is enabled; and autoneg is ON. * @throws Exception */ @Test public void testSwitchAddedCase2() throws Exception { BetterLinkDiscoveryManager linkDiscovery = bldm; Capture<OFMessage> wc; Capture<ListenerContext> fc; Set<Short> qPorts; OFPhysicalPort p1 = new OFPhysicalPort(); p1.setHardwareAddress(HexString.fromHexString("5c:16:c7:00:00:01")); IOFSwitch sw1 = createMock(IOFSwitch.class); // Set switch map in controllerProvider. Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); switches.put(1L, sw1); getMockControllerProvider().setSwitches(switches); // Create the set of ports List<Short> ports = new ArrayList<Short>(); for(short p=1; p<=10; ++p) { ports.add(p); } // Set the captures. wc = new Capture<OFMessage>(CaptureType.ALL); fc = new Capture<ListenerContext>(CaptureType.ALL); // Expect switch to return those ports. expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw1.getActions()).andReturn(1).anyTimes(); expect(sw1.getEnabledPortNumbers()).andReturn(ports).anyTimes(); expect(sw1.getPort(EasyMock.anyShort())).andReturn(p1).anyTimes(); expect(sw1.isFastPort(EasyMock.anyShort())).andReturn(false).anyTimes(); sw1.write(capture(wc), capture(fc)); expectLastCall().anyTimes(); sw1.flush(); expectLastCall().anyTimes(); expect(sw1.getInetAddress()).andReturn(null); expect(tunnelManager.getTunnelPortNumber(EasyMock.anyLong())).andReturn(null).anyTimes(); replay(sw1, tunnelManager); // Set autoportfast feature to true linkDiscovery.setAutoPortFastFeature(true); // set the port autoneg feature to ON. p1.setCurrentFeatures(OFPortFeatures.OFPPF_AUTONEG.getValue()); linkDiscovery.addedSwitch(sw1); verify(sw1, tunnelManager); 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); } /** * In this case, autoportfast is disabled; and autoneg is OFF. * @throws Exception */ @Test public void testSwitchAddedCase3() throws Exception { BetterLinkDiscoveryManager linkDiscovery = bldm; Capture<OFMessage> wc; Capture<ListenerContext> fc; Set<Short> qPorts; OFPhysicalPort p1 = new OFPhysicalPort(); p1.setHardwareAddress(HexString.fromHexString("5c:16:c7:00:00:01")); IOFSwitch sw1 = createMock(IOFSwitch.class); // Set switch map in controllerProvider. Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); switches.put(1L, sw1); getMockControllerProvider().setSwitches(switches); // Create the set of ports List<Short> ports = new ArrayList<Short>(); for(short p=1; p<=10; ++p) { ports.add(p); } // Set the captures. wc = new Capture<OFMessage>(CaptureType.ALL); fc = new Capture<ListenerContext>(CaptureType.ALL); // Expect switch to return those ports. expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw1.getActions()).andReturn(1).anyTimes(); expect(sw1.getEnabledPortNumbers()).andReturn(ports).anyTimes(); expect(sw1.getPort(EasyMock.anyShort())).andReturn(p1).anyTimes(); // Fast ports expect(sw1.isFastPort(EasyMock.anyShort())).andReturn(true).anyTimes(); sw1.write(capture(wc), capture(fc)); expectLastCall().anyTimes(); sw1.flush(); expectLastCall().anyTimes(); expect(sw1.getInetAddress()).andReturn(null); expect(tunnelManager.getTunnelPortNumber(EasyMock.anyLong())).andReturn(null).anyTimes(); replay(sw1, tunnelManager); // Set autoportfast feature to false linkDiscovery.setAutoPortFastFeature(false); linkDiscovery.addedSwitch(sw1); verify(sw1, tunnelManager); // Since all ports are fast ports, none of them are quarantined. qPorts = linkDiscovery.getQuarantinedPorts(sw1.getId()); assertNotNull(qPorts); assertTrue(qPorts.isEmpty()); Thread.sleep(300); // 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); } /** * In this case, autoportfast is disabled; and autoneg is OFF. * @throws Exception */ @Test public void testSwitchAddedCase4() throws Exception { BetterLinkDiscoveryManager linkDiscovery = bldm; Capture<OFMessage> wc; Capture<ListenerContext> fc; Set<Short> qPorts; OFPhysicalPort p1 = new OFPhysicalPort(); p1.setHardwareAddress(HexString.fromHexString("5c:16:c7:00:00:01")); // set the port autoneg feature to OFF, thus fast port. IOFSwitch sw1 = createMock(IOFSwitch.class); // Set switch map in controllerProvider. Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); switches.put(1L, sw1); getMockControllerProvider().setSwitches(switches); // Create the set of ports List<Short> ports = new ArrayList<Short>(); for(short p=1; p<=15; ++p) { ports.add(p); } // Set the captures. wc = new Capture<OFMessage>(CaptureType.ALL); fc = new Capture<ListenerContext>(CaptureType.ALL); // Expect switch to return those ports. expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw1.getEnabledPortNumbers()).andReturn(ports).anyTimes(); expect(sw1.getPort(EasyMock.anyShort())).andReturn(p1).anyTimes(); // fast ports on expect(sw1.isFastPort(EasyMock.anyShort())).andReturn(true).anyTimes(); sw1.write(capture(wc), capture(fc)); expectLastCall().anyTimes(); sw1.flush(); expectLastCall().anyTimes(); expect(sw1.getInetAddress()).andReturn(null); replay(sw1); // Set autoportfast feature to true linkDiscovery.setAutoPortFastFeature(true); linkDiscovery.addedSwitch(sw1); verify(sw1); // Since all ports are fast ports, none of them are quarantined. qPorts = linkDiscovery.getQuarantinedPorts(sw1.getId()); assertNotNull(qPorts); assertTrue(qPorts.isEmpty()); // Since autoportfast feature is on and all ports are fastports, // no LLDP or BDDP is sent out. assertFalse(wc.hasCaptured()); } /** * Ensure that LLDPs are not sent through the tunnel ports. * @throws Exception */ @Test public void testNoDiscoveryOnTunnelPorts() throws Exception { BetterLinkDiscoveryManager linkDiscovery = bldm; Capture<OFMessage> wc; Capture<ListenerContext> fc; Set<Short> qPorts; OFPhysicalPort p1 = new OFPhysicalPort(); p1.setHardwareAddress(HexString.fromHexString("5c:16:c7:00:00:01")); IOFSwitch sw1 = createMock(IOFSwitch.class); // Set switch map in controllerProvider. Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>(); switches.put(1L, sw1); getMockControllerProvider().setSwitches(switches); // Create the set of ports List<Short> ports = new ArrayList<Short>(); for(short p=1; p<=10; ++p) { ports.add(p); } // Set the captures. wc = new Capture<OFMessage>(CaptureType.ALL); fc = new Capture<ListenerContext>(CaptureType.ALL); // Expect switch to return those ports. expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw1.getActions()).andReturn(1).anyTimes(); expect(sw1.getEnabledPortNumbers()).andReturn(ports).anyTimes(); expect(sw1.getPort(EasyMock.anyShort())).andReturn(p1).anyTimes(); expect(sw1.isFastPort(EasyMock.anyShort())).andReturn(false).anyTimes(); sw1.write(capture(wc), capture(fc)); expectLastCall().anyTimes(); sw1.flush(); expectLastCall().anyTimes(); expect(sw1.getInetAddress()).andReturn(null); expect(tunnelManager.getTunnelPortNumber(EasyMock.anyLong())).andReturn(new Short((short)1)).anyTimes(); replay(sw1, tunnelManager); linkDiscovery.addedSwitch(sw1); 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(); // Port #1 will not get LLDP as it is a tunnel port. assertTrue(msgList.size() == (ports.size() - 1) * 2); } }