/* * 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.topology; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.easymock.EasyMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import org.junit.Before; import org.junit.Test; import org.sdnplatform.core.IControllerService; import org.sdnplatform.core.IOFSwitch; import org.sdnplatform.core.module.ModuleContext; import org.sdnplatform.core.test.MockControllerProvider; import org.sdnplatform.core.test.MockThreadPoolService; import org.sdnplatform.linkdiscovery.ILinkDiscoveryService; import org.sdnplatform.routing.Route; import org.sdnplatform.threadpool.IThreadPoolService; import org.sdnplatform.topology.BetterTopologyInstance; import org.sdnplatform.topology.BetterTopologyManager; import org.sdnplatform.topology.NodePortTuple; import org.sdnplatform.topology.OrderedNodePair; public class BetterTopologyInstanceTest extends TopologyInstanceTest { @Before public void SetUp() throws Exception { fmc = new ModuleContext(); linkDiscovery = EasyMock.createMock(ILinkDiscoveryService.class); mockControllerProvider = new MockControllerProvider(); fmc.addService(IControllerService.class, mockControllerProvider); MockThreadPoolService tp = new MockThreadPoolService(); fmc.addService(IThreadPoolService.class, tp); fmc.addService(ILinkDiscoveryService.class, linkDiscovery); topologyManager = new BetterTopologyManager(); topologyManager.init(fmc); tp.init(fmc); tp.startUp(fmc); } private void verifyBroadcastDomains(int [][][] ebd) { verifyBroadcastDomains(ebd, true); } private void verifyBroadcastDomains(int [][][] ebd, boolean tunnelsEnabled){ NodePortTuple npt = null; Set<NodePortTuple> expected = new HashSet<NodePortTuple>(); for(int i=0; i<ebd.length; ++i) { int [][] nptList = ebd[i]; expected.clear(); for(int j=0; j<nptList.length; ++j) { npt = new NodePortTuple((long)nptList[j][0], (short)nptList[j][1]); expected.add(npt); } BetterTopologyInstance ti = (BetterTopologyInstance) topologyManager.getCurrentInstance(tunnelsEnabled); Set<NodePortTuple> computed = ti.getBroadcastDomainPorts(npt); if (computed != null) assertTrue(computed.equals(expected)); else if (computed == null) assertTrue(expected.isEmpty()); } } private void verifyBlockedPorts(int [][] bports) { Set<NodePortTuple> expected = new HashSet<NodePortTuple>(); for(int i=0; i<bports.length; ++i) { int [] entry = bports[i]; NodePortTuple npt = new NodePortTuple((long)entry[0], (short)entry[1]); expected.add(npt); } BetterTopologyInstance ti = (BetterTopologyInstance) topologyManager.getCurrentInstance(); Set<NodePortTuple> computed = ti.getBlockedPorts(); if (bports.length == 0) { assertTrue (ti.getBlockedPorts().isEmpty() == true); } else { assertTrue(expected.equals(computed)); } } private void verifyExternalBroadcastPorts (int [][][] ebports) { BetterTopologyInstance ti = (BetterTopologyInstance) topologyManager.getCurrentInstance(); int count; for(int i=0; i<ebports.length; ++i) { int [][] nptList = ebports[i]; count = 0; for(int j=0; j<nptList.length; ++j) { if (ti.isIncomingBroadcastAllowedOnSwitchPort( (long)nptList[j][0], (short)nptList[j][1])) { count++; } } assertTrue(count == 0 || count == 1); } } private void verifyHigherLevelTopology(int numberOfNodes) { BetterTopologyInstance ti = (BetterTopologyInstance) topologyManager.getCurrentInstance(); assertTrue(ti.getHTNeighbors().keySet().size() == numberOfNodes); Set<OrderedNodePair> allowedNodePairs = ti.getAllowedNodePairs(); assertTrue(allowedNodePairs.size() <= 2*(numberOfNodes-1)); Map<Long, Map<Long,Long>> nexthop = ti.getNextHopMap(); for(long s: nexthop.keySet()) { HashSet<Long> neighbors = new HashSet<Long>(nexthop.get(s).values()); for(long nbr: neighbors) { if (s == nbr) continue; OrderedNodePair onp = new OrderedNodePair(s,nbr); assertTrue(allowedNodePairs.contains(onp)); assertTrue(nexthop.get(s).size() == nexthop.get(nbr).size()); } } } @Test public void testBroadcastDomains() throws Exception { BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager(); tm.clear(); { int [][] linkArray = { {1, 2, 2, 1, MULTIHOP_LINK}, {2, 1, 1, 2, MULTIHOP_LINK}, {2, 2, 3, 1, DIRECT_LINK}, {3, 1, 2, 2, DIRECT_LINK}, {3, 2, 4, 1, MULTIHOP_LINK}, {4, 1, 3, 2, MULTIHOP_LINK}, {4, 2, 1, 1, DIRECT_LINK}, {1, 1, 4, 2, DIRECT_LINK}, {1, 2, 4, 5, MULTIHOP_LINK}, {4, 5, 1, 2, MULTIHOP_LINK}, {1, 5, 3, 2, MULTIHOP_LINK}, {3, 2, 1, 5, MULTIHOP_LINK}, }; int [][] expectedClusters = { {1,4}, {2,3}, }; int [][][] ebd = { {{1,2},{2,1},{4,5}}, {{1,5},{3,2},{4,1}}, }; int [][][] ebports = { {{1,2},{4,5}}, {{2,1}}, {{3,2}}, {{4,1},{1,5}} }; int [][]blockedPorts = { {1,2}, {4,5}, }; createTopologyFromLinks(linkArray); topologyManager.updateTopology(); verifyClusters(expectedClusters); verifyBroadcastDomains(ebd, false); verifyExternalBroadcastPorts(ebports); verifyBlockedPorts(blockedPorts); verifyHigherLevelTopology(4); // give the number of nodes } tm.clear(); { int [][] linkArray = { {1, 2, 2, 1, MULTIHOP_LINK}, {2, 1, 1, 2, MULTIHOP_LINK}, {2, 2, 3, 1, DIRECT_LINK}, {3, 1, 2, 2, DIRECT_LINK}, {3, 2, 4, 1, MULTIHOP_LINK}, {4, 1, 3, 2, MULTIHOP_LINK}, {4, 2, 1, 1, DIRECT_LINK}, {1, 1, 4, 2, DIRECT_LINK}, }; int [][] expectedClusters = { {1,4}, {2,3}, }; int [][][] ebd = { {{1,2},{2,1}}, {{3,2},{4,1}}, }; int [][][] ebports = { {{1,2}}, {{2,1}}, {{3,2}}, {{4,1}}, }; int [][]blockedPorts = { {1,2} }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); verifyBroadcastDomains(ebd); verifyBlockedPorts(blockedPorts); verifyExternalBroadcastPorts(ebports); } // The following are a bit of weird test cases. tm.clear(); { int [][] linkArray = { {1, 1, 2, 1, MULTIHOP_LINK}, {2, 1, 1, 1, MULTIHOP_LINK}, {2, 1, 3, 1, DIRECT_LINK}, {3, 1, 2, 1, DIRECT_LINK}, {3, 1, 4, 1, DIRECT_LINK}, {4, 1, 3, 1, DIRECT_LINK}, {4, 1, 5, 1, MULTIHOP_LINK}, {5, 1, 4, 1, MULTIHOP_LINK}, }; int [][] expectedClusters = { {1}, {2}, {3}, {4}, {5} }; int [][][] ebd = { {{1,1},{2,1},{3,1},{4,1},{5,1}} }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); verifyBroadcastDomains(ebd); } { int [][] linkArray = { {1, 1, 3, 1, MULTIHOP_LINK}, {3, 1, 1, 1, MULTIHOP_LINK}, }; createTopologyFromLinks(linkArray); boolean flag = tm.updateTopology(); assertFalse(flag); } { tm.removeLink((long)1,(short)1,(long)3,(short)1); tm.removeLink((long)3,(short)1,(long)1,(short)1); boolean flag = tm.updateTopology(); assertFalse(flag); } { tm.removeLink((long)1,(short)1,(long)2,(short)1); tm.removeLink((long)2,(short)1,(long)1,(short)1); int [][] expectedClusters = { {2}, {3}, {4}, {5} }; int [][][] ebd = { {{2,1},{3,1},{4,1},{5,1}} }; tm.applyUpdates(); boolean flag = tm.updateTopology(); assertTrue(flag); verifyClusters(expectedClusters); verifyBroadcastDomains(ebd); } { tm.removeLink((long)4,(short)1,(long)5,(short)1); tm.removeLink((long)5,(short)1,(long)4,(short)1); int [][] expectedClusters = { {2}, {3}, {4}, }; int [][][] ebd = {}; topologyManager.updateTopology(); verifyClusters(expectedClusters); verifyBroadcastDomains(ebd); } { tm.removeLink((long)3,(short)1,(long)4,(short)1); tm.removeLink((long)4,(short)1,(long)3,(short)1); int [][] expectedClusters = { {2,3}, {4}, }; int [][][] ebd = {}; topologyManager.updateTopology(); verifyClusters(expectedClusters); verifyBroadcastDomains(ebd); } } /** * Same test as in sdnplatform, but the tunnel links should be ignored * in the SDN Platform part of the code and must only be used as * needed. */ @Test @Override public void testLoopDetectionWithIslands() throws Exception { // +-------+ +-------+ // | | | | // | 1 1|-------------|1 2 | // | 2 | | 2 | // +-------+ +-------+ // | | // | | // +-------+ | // | 1 | | // | 3 2|-----------------+ // | 3 | // +-------+ // // // +-------+ // | 1 | // | 4 2|----------------+ // | 3 | | // +-------+ | // | | // | | // +-------+ +-------+ // | 1 | | 2 | // | 5 2|-------------|1 6 | // | | | | // +-------+ +-------+ { int [][] linkArray = { {1, 1, 2, 1, DIRECT_LINK}, {2, 1, 1, 1, DIRECT_LINK}, {1, 2, 3, 1, DIRECT_LINK}, {3, 1, 1, 2, DIRECT_LINK}, {2, 2, 3, 2, DIRECT_LINK}, {3, 2, 2, 2, DIRECT_LINK}, {4, 2, 6, 2, DIRECT_LINK}, {6, 2, 4, 2, DIRECT_LINK}, {4, 3, 5, 1, DIRECT_LINK}, {5, 1, 4, 3, DIRECT_LINK}, {5, 2, 6, 1, DIRECT_LINK}, {6, 1, 5, 2, DIRECT_LINK}, }; int [][] expectedClusters = { {1, 2, 3}, {4, 5, 6} }; int [][][] expectedBroadcastPorts = { {{1,2}, {3,1}, {1,1}, {2,1}}, {{4,2}, {4,3}, {5,1}, {6,2}}, }; createTopologyFromLinks(linkArray); topologyManager.updateTopology(); verifyClusters(expectedClusters); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); BetterTopologyInstance ti = (BetterTopologyInstance) topologyManager.getCurrentInstance(false); assertNull(ti.multiroute(3L, 5L, 0)); } // +-------+ +-------+ // | | | | // | 1 1|-------------|1 2 | // | 2 | | 2 | // +-------+ +-------+ // | | // | | // +-------+ | // | 1 | | // | 3 2|-----------------+ // | 3 | // +-------+ // | // | // | // +-------+ // | 1 | // | 4 2|----------------+ // | 3 | | // +-------+ | // | | // | | // +-------+ +-------+ // | 1 | | 2 | // | 5 2|-------------|1 6 | // | | | | // +-------+ +-------+ { int [][] linkArray = { {3, 3, 4, 1, DIRECT_LINK}, {4, 1, 3, 3, DIRECT_LINK}, }; int [][] expectedClusters = { {1, 2, 3, 4, 5, 6} }; int [][][] expectedBroadcastPorts = { {{1,1}, {2,1}, {1,2}, {3,1}, {3,3}, {4,1}, {4,3}, {5,1}, {4,2}, {6,2}} }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); } } /** * This test ensures that tunnel links are not getting added to topology. * @throws Exception */ @Test public void testBroadcastDomainLoopDetection() throws Exception { BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager(); tm.clear(); { int [][] linkArray = { {1, 2, 2, 1, MULTIHOP_LINK}, {2, 1, 1, 2, MULTIHOP_LINK}, {2, 2, 3, 1, TUNNEL_LINK}, {3, 1, 2, 2, TUNNEL_LINK}, {3, 2, 4, 1, MULTIHOP_LINK}, {4, 1, 3, 2, MULTIHOP_LINK}, {4, 2, 1, 1, TUNNEL_LINK}, {1, 1, 4, 2, TUNNEL_LINK}, {4, 3, 5, 3, TUNNEL_LINK}, {5, 3, 4, 3, TUNNEL_LINK}, {5, 4, 6, 4, TUNNEL_LINK}, {6, 5, 1, 5, TUNNEL_LINK}, }; int [][] expectedClusters = { {1},{2},{3},{4} }; int [][][] ebd = { {{1,2},{2,1}}, {{3,2},{4,1}}, }; createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); verifyBroadcastDomains(ebd); verifyHigherLevelTopology(6); // give the number of nodes } } @Test public void testBroadcastPortsBetweenClusters() throws Exception { // +-------+ +-------+ // | | | | // | 1 1|-------------|1 2 | // | 2 | | 2 | // +-------+ +-------+ // | | // | | // +-------+ | // | 1 | | // | 3 2|-----------------+ // | 3 | // +-------+ // // // // +-------+ // | 1 | // | 4 2|----------------+ // | 3 | | // +-------+ | // | | // | | // +-------+ +-------+ // | 1 | | 2 | // | 5 2|-------------|1 6 | // | | | | // +-------+ +-------+ BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager(); { int [][] linkArray = { {1, 1, 2, 1, DIRECT_LINK}, {2, 1, 1, 1, DIRECT_LINK}, {1, 2, 3, 1, DIRECT_LINK}, {3, 1, 1, 2, DIRECT_LINK}, {2, 2, 3, 2, DIRECT_LINK}, {3, 2, 2, 2, DIRECT_LINK}, {4, 2, 6, 2, DIRECT_LINK}, {6, 2, 4, 2, DIRECT_LINK}, {4, 3, 5, 1, DIRECT_LINK}, {5, 1, 4, 3, DIRECT_LINK}, {5, 2, 6, 1, DIRECT_LINK}, {6, 1, 5, 2, DIRECT_LINK}, {1, 7, 4, 7, DIRECT_LINK}, {2, 7, 5, 7, DIRECT_LINK}, {3, 7, 6, 7, DIRECT_LINK}, }; int [][] expectedClusters = { {1, 2, 3}, {4, 5, 6} }; int [][][] expectedBroadcastPorts = { {{1,1}, {2,1}, {1,2}, {3,1}}, {{4,3}, {5,1}, {4,2}, {6,2}}, }; // Use the same switch object for all values. IOFSwitch sw1 = EasyMock.createMock(IOFSwitch.class); Map<Long, IOFSwitch> switchMap = new HashMap<Long, IOFSwitch>(); switchMap.put(1L, sw1); switchMap.put(2L, sw1); switchMap.put(3L, sw1); switchMap.put(4L, sw1); switchMap.put(5L, sw1); switchMap.put(6L, sw1); expect(linkDiscovery.isTunnelPort(1L, (short)7)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(2L, (short)7)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(3L, (short)7)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(4L, (short)7)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(5L, (short)7)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(6L, (short)7)).andReturn(false).anyTimes(); mockControllerProvider.setSwitches(switchMap); expect(sw1.portEnabled(EasyMock.anyShort())).andReturn(true).anyTimes(); replay(sw1, linkDiscovery); createTopologyFromLinks(linkArray); verifyClusters(expectedClusters); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); assertTrue(tm.isAttachmentPointPort(1L, (short)7)); assertTrue(tm.isAttachmentPointPort(2L, (short)7)); assertTrue(tm.isAttachmentPointPort(3L, (short)7)); assertTrue(tm.isAttachmentPointPort(4L, (short)7)); assertTrue(tm.isAttachmentPointPort(5L, (short)7)); assertTrue(tm.isAttachmentPointPort(6L, (short)7)); verify(sw1, linkDiscovery); } } @Test public void testUnicastPortMappings() throws Exception { BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager(); tm.clear(); { int [][] linkArray = { {1, 1, 3, 1, MULTIHOP_LINK}, {3, 1, 1, 1, MULTIHOP_LINK}, {1, 1, 4, 1, MULTIHOP_LINK}, {4, 1, 1, 1, MULTIHOP_LINK}, {2, 1, 3, 1, MULTIHOP_LINK}, {3, 1, 2, 1, MULTIHOP_LINK}, {2, 1, 4, 1, MULTIHOP_LINK}, {4, 1, 2, 1, MULTIHOP_LINK}, {3, 3, 5, 3, MULTIHOP_LINK}, {5, 3, 3, 3, MULTIHOP_LINK}, {3, 3, 6, 3, MULTIHOP_LINK}, {6, 3, 3, 3, MULTIHOP_LINK}, {4, 3, 5, 3, MULTIHOP_LINK}, {5, 3, 4, 3, MULTIHOP_LINK}, {4, 3, 6, 3, MULTIHOP_LINK}, {6, 3, 4, 3, MULTIHOP_LINK}, {1, 2, 2, 2, DIRECT_LINK}, {2, 2, 1, 2, DIRECT_LINK}, {3, 2, 4, 2, DIRECT_LINK}, {4, 2, 3, 2, DIRECT_LINK}, {5, 2, 6, 2, DIRECT_LINK}, {6, 2, 5, 2, DIRECT_LINK}, }; int [][] expectedClusters = { {1,2}, {3,4}, {5,6} }; int [][][] ebd = { {{1,1},{2,1},{3,1},{4,1}}, {{3,3},{4,3},{5,3},{6,3}} }; int [][][] ebports = { {{1,1},{2,1}}, {{3,1},{4,1}}, {{3,3},{4,3}}, {{5,3},{6,3}} }; createTopologyFromLinks(linkArray); topologyManager.updateTopology(); verifyClusters(expectedClusters); verifyBroadcastDomains(ebd); verifyExternalBroadcastPorts(ebports); verifyHigherLevelTopology(5); // give the number of nodes NodePortTuple nptOut, nptIn; NodePortTuple npt11 = new NodePortTuple((long)1, (short)1); NodePortTuple npt21 = new NodePortTuple((long)2, (short)1); NodePortTuple npt15 = new NodePortTuple((long)1, (short)5); NodePortTuple npt25 = new NodePortTuple((long)2, (short)5); NodePortTuple npt31 = new NodePortTuple((long)3, (short)1); NodePortTuple npt33 = new NodePortTuple((long)3, (short)3); new NodePortTuple((long)4, (short)1); NodePortTuple npt43 = new NodePortTuple((long)4, (short)3); // There are some cases, where the switchport that will be used // will be either (3,1) & (3,3) or (4,1) or (4,3). For those // cases, it would be easier define a single variable that's // assigned one of the values depending on whether // nofTrafficSpreading is enabled or not. NodePortTuple npt31or41; NodePortTuple npt33or43; npt31or41 = new NodePortTuple((long)3, (short)1); npt33or43 = new NodePortTuple((long)3, (short)3); BetterTopologyInstance ti = (BetterTopologyInstance) topologyManager.getCurrentInstance(); assertTrue(ti.inSameBroadcastDomain(1L, (short)1, 2L, (short)1)); assertFalse(ti.inSameBroadcastDomain(1L, (short)1, 3L, (short)3)); assertTrue(ti.inSameBroadcastDomain(1L, (short)10, 1L, (short)10)); assertFalse(ti.inSameBroadcastDomain(1L, (short)10, 1L, (short)11)); nptIn = ti.getIncomingSwitchPort((long)1, (short)5, (long)1, (short)1); assertTrue(nptIn.equals(npt15)); nptOut = ti.getOutgoingSwitchPort((long)1, (short)5, (long)1, (short)1); assertTrue(nptOut.equals(npt11)); nptIn = ti.getIncomingSwitchPort((long)1, (short)5, (long)2, (short)1); assertTrue(nptIn.equals(npt15)); nptOut = ti.getOutgoingSwitchPort((long)1, (short)5, (long)2, (short)1); assertTrue(nptOut.equals(npt11)); nptIn = ti.getIncomingSwitchPort((long)1, (short)5, (long)2, (short)5); assertTrue(nptIn.equals(npt15)); nptOut = ti.getOutgoingSwitchPort((long)1, (short)5, (long)2, (short)5); assertTrue(nptOut.equals(npt25)); nptIn = ti.getIncomingSwitchPort((long)1, (short)1, (long)1, (short)5); assertTrue(nptIn.equals(npt11)); nptOut = ti.getOutgoingSwitchPort((long)1, (short)1, (long)1, (short)5); assertTrue(nptOut.equals(npt15)); nptIn = ti.getIncomingSwitchPort((long)1, (short)1, (long)2, (short)5); assertTrue(nptIn.equals(npt21)); nptOut = ti.getOutgoingSwitchPort((long)2, (short)1, (long)2, (short)5); assertTrue(nptOut.equals(npt25)); nptIn = ti.getIncomingSwitchPort((long)3, (short)3, (long)4, (short)3); nptOut = ti.getOutgoingSwitchPort((long)3, (short)3, (long)4, (short)3); assertTrue(nptIn == null); assertTrue(nptOut == null); nptIn = ti.getIncomingSwitchPort((long)3, (short)3, (long)4, (short)3); nptOut = ti.getOutgoingSwitchPort((long)3, (short)3, (long)4, (short)3); assertTrue(nptIn == null); assertTrue(nptOut == null); // the broadcast domain to broadcast domain traffic should // traverse through ports (4,3) and (4,1) nptIn = ti.getIncomingSwitchPort((long)4, (short)1, (long)4, (short)3); nptOut = ti.getOutgoingSwitchPort((long)4, (short)1, (long)4, (short)3); assertTrue(nptIn.equals(npt31)); assertTrue(nptOut.equals(npt33)); // the broadcast domain to broadcast domain traffic should // traverse through ports (4,3) and (4,1) nptIn = ti.getIncomingSwitchPort((long)4, (short)1, (long)5, (short)3); nptOut = ti.getOutgoingSwitchPort((long)4, (short)1, (long)5, (short)3); assertTrue(nptIn.equals(npt31or41)); assertTrue(nptOut.equals(npt33or43)); // Get the incoming and outgoing switchports when the src and dst // are in different openflow domains. nptIn = ti.getIncomingSwitchPort((long)1, (short)5, (long)4, (short)3); nptOut = ti.getOutgoingSwitchPort((long)1, (short)5, (long)4, (short)3); assertTrue(nptIn.equals(npt15)); assertTrue(nptOut.equals(npt33or43)); // Get the incoming and outgoing switchports when the src and dst // are in different openflow domains. nptIn = ti.getIncomingSwitchPort((long)1, (short)5, (long)5, (short)3); nptOut = ti.getOutgoingSwitchPort((long)1, (short)5, (long)5, (short)3); assertTrue(nptIn.equals(npt15)); assertTrue(nptOut.equals(npt33or43)); // check for outgoing broacast port assignment nptOut = ti.getAllowedOutgoingBroadcastPort((long)1, (short)5, (long)6, (short)5); assertTrue(nptOut.equals(npt11)); nptOut = ti.getAllowedOutgoingBroadcastPort((long)2, (short)5, (long)6, (short)5); assertTrue(nptOut.equals(npt21)); NodePortTuple npt67 = new NodePortTuple(6L, (short)7); nptOut = ti.getAllowedOutgoingBroadcastPort((long)6, (short)5, (long)6, (short)7); assertTrue(nptOut.equals(npt67)); nptOut = ti.getAllowedOutgoingBroadcastPort((long)5, (short)5, (long)6, (short)7); assertTrue(nptOut.equals(npt67)); NodePortTuple npt1010 = new NodePortTuple(10L, (short)10); nptOut = ti.getAllowedOutgoingBroadcastPort((long)10, (short)5, (long)10, (short)10); assertTrue(nptOut.equals(npt1010)); nptOut = ti.getAllowedOutgoingBroadcastPort((long)10, (short)5, (long)20, (short)10); assertNull(nptOut); // There are two paths, one out of 3,3 and one out of 4,3 // The system could pick either one of them. // No matter where the attachment points are, the method should // provide the right broadcast port nptOut = ti.getAllowedOutgoingBroadcastPort((long)3, (short)1, (long)6, (short)5); assertTrue(nptOut.equals(npt33) || nptOut.equals(npt43)); nptOut = ti.getAllowedOutgoingBroadcastPort((long)4, (short)1, (long)6, (short)5); assertTrue(nptOut.equals(npt33) || nptOut.equals(npt43)); // ***** nptOut = ti.getAllowedOutgoingBroadcastPort((long)3, (short)5, (long)6, (short)5); assertTrue(nptOut.equals(npt33)); nptOut = ti.getAllowedOutgoingBroadcastPort((long)4, (short)5, (long)6, (short)5); assertTrue(nptOut.equals(npt43)); nptOut = ti.getAllowedOutgoingBroadcastPort((long)3, (short)3, (long)6, (short)5); assertTrue(nptOut == null); nptOut = ti.getAllowedOutgoingBroadcastPort((long)4, (short)3, (long)6, (short)5); assertTrue(nptOut == null); // ***** nptOut = ti.getAllowedOutgoingBroadcastPort((long)3, (short)1, (long)4, (short)3); assertTrue(nptOut.equals(npt33) || nptOut.equals(npt43)); nptOut = ti.getAllowedOutgoingBroadcastPort((long)3, (short)1, (long)5, (short)3); assertTrue(nptOut.equals(npt33) || nptOut.equals(npt43)); // End of AllowedOutgoingBroadcastPort tests. // Let's check consistency on the checkpoints here. assertTrue(ti.isConsistent((long)1, (short)5, (long)3,(short)1)); assertTrue(ti.isConsistent((long)1, (short)5, (long)4,(short)1)); assertTrue(!ti.isConsistent((long)1, (short)5, (long)1,(short)1)); assertTrue(!ti.isConsistent((long)1, (short)5, (long)3,(short)3)); assertTrue(!ti.isConsistent((long)1, (short)5, (long)3,(short)3)); assertTrue(ti.isConsistent((long)1, (short)5, (long)5,(short)3)); // test set 2 assertTrue(ti.isConsistent((long)1, (short)1, (long)2,(short)1)); assertTrue(ti.isConsistent((long)1, (short)1, (long)3,(short)1)); assertTrue(ti.isConsistent((long)2, (short)1, (long)3,(short)1)); assertTrue(ti.isConsistent((long)2, (short)1, (long)4,(short)1)); // test 3 assertTrue(!ti.isConsistent((long)2, (short)5, (long)4,(short)5)); assertTrue(!ti.isConsistent((long)10, (short)1, (long)12,(short)5)); assertTrue(!ti.isConsistent((long)1, (short)1, (long)12,(short)5)); assertTrue(!ti.isConsistent((long)12, (short)5, (long)1,(short)1)); // any internal switch port should be consistent. assertTrue(ti.isConsistent((long)12, (short)5, (long)1,(short)2)); assertTrue(ti.isConsistent((long)1, (short)2, (long)2,(short)2)); // any non-broadcast domain attachment point port should be // consistent with itself assertTrue(ti.isConsistent((long)12, (short)5, (long)12,(short)5)); // test inSameIsland assertTrue(ti.inSameL2Domain(1L, 2L)); assertTrue(ti.inSameL2Domain(1L, 3L)); assertTrue(ti.inSameL2Domain(1L, 5L)); assertTrue(ti.inSameL2Domain(4L, 6L)); assertTrue(!ti.inSameL2Domain(1L, 12L)); assertTrue(!ti.inSameL2Domain(12L, 4L)); assertTrue(!ti.inSameL2Domain(20L, 30L)); assertTrue(ti.inSameL2Domain(15L, 15L)); // test the same island membership differently. assertTrue(ti.getL2DomainId(1L) == ti.getL2DomainId(2L)); assertTrue(ti.getL2DomainId(1L) == ti.getL2DomainId(3L)); assertTrue(ti.getL2DomainId(1L) == ti.getL2DomainId(5L)); assertTrue(ti.getL2DomainId(4L) == ti.getL2DomainId(6L)); assertTrue(ti.getL2DomainId(1L) != ti.getL2DomainId(12L)); assertTrue(ti.getL2DomainId(12L) != ti.getL2DomainId(4L)); assertTrue(ti.getL2DomainId(20L) != ti.getL2DomainId(30L)); // test getBroadcastPorts Set<Short> ports = ti.getBroadcastPorts((long)3, (long)3, (short)5); assertTrue(ports.contains((short)1)); assertFalse(ports.contains((short)2)); assertTrue(ports.contains((short)3)); ports = ti.getBroadcastPorts((long)3, (long)4, (short)3); assertTrue(ports.contains((short)1)); assertFalse(ports.contains((short)2)); assertFalse(ports.contains((short)3)); ports = ti.getBroadcastPorts((long)4, (long)4, (short)1); assertFalse(ports.contains((short)1)); assertFalse(ports.contains((short)2)); assertFalse(ports.contains((short)3)); // Even though 4,1 is not the right node port for the broadcast // traffic from the broadcast domain to enter this cluster, // the output port assignment should be right. It is up to the // forwarding module to drop this traffic as the incoming // broadcast is not allowed on the switchport (4,1). ports = ti.getBroadcastPorts((long)4, (long)4, (short)1); assertFalse(ports.contains((short)1)); assertFalse(ports.contains((short)2)); assertFalse(ports.contains((short)3)); ports = ti.getBroadcastPorts((long)4, (long)3, (short)1); assertFalse(ports.contains((short)1)); assertFalse(ports.contains((short)2)); assertFalse(ports.contains((short)3)); ports = ti.getBroadcastPorts((long)3, (long)12, (short)1); assertTrue(ports.isEmpty()); // test Broadcast ports for a host in a different cluster. ports = ti.getBroadcastPorts((long)4, (long)1, (short)1); assertFalse(ports.contains((short)1)); assertFalse(ports.contains((short)2)); assertFalse(ports.contains((short)3)); // test Broadcast ports for a host in a different cluster. ports = ti.getBroadcastPorts((long)4, (long)1, (short)1); assertFalse(ports.contains((short)1)); assertFalse(ports.contains((short)2)); assertFalse(ports.contains((short)3)); // test routes. List<NodePortTuple> nptList; List<NodePortTuple> expectedNptList = new ArrayList<NodePortTuple>();; nptList = ti.getFirstHopRoute(1, 5, 0); expectedNptList.add(new NodePortTuple(1L, (short)1)); assertTrue(nptList.equals(expectedNptList)); nptList = ti.getFirstHopRoute(2, 5, 0); expectedNptList.clear(); expectedNptList.add(new NodePortTuple(2L, (short)1)); assertTrue(nptList.equals(expectedNptList)); nptList = ti.getLastHopRoute(4, 5, 0); expectedNptList.clear(); expectedNptList.add(new NodePortTuple(5L, (short)3)); assertTrue(nptList.equals(expectedNptList)); nptList = ti.getLastHopRoute(4, 6, 0); expectedNptList.clear(); expectedNptList.add(new NodePortTuple(6L, (short)3)); assertTrue(nptList.equals(expectedNptList)); nptList = ti.getRouteThroughCluster(4, 5, 2, 0); expectedNptList.clear(); expectedNptList.add(new NodePortTuple(3L, (short)3)); expectedNptList.add(new NodePortTuple(3L, (short)1)); assertTrue(nptList.equals(expectedNptList)); nptList = ti.multiroute(1, 6, 0); expectedNptList.clear(); expectedNptList.add(new NodePortTuple(1L, (short)1)); expectedNptList.add(new NodePortTuple(3L, (short)1)); expectedNptList.add(new NodePortTuple(3L, (short)3)); expectedNptList.add(new NodePortTuple(6L, (short)3)); assertTrue(nptList.equals(expectedNptList)); nptList = ti.multiroute(5, true, 6, false, 0); expectedNptList.clear(); expectedNptList.add(new NodePortTuple(3L, (short)1)); expectedNptList.add(new NodePortTuple(3L, (short)3)); expectedNptList.add(new NodePortTuple(6L, (short)3)); assertTrue(nptList.equals(expectedNptList)); nptList = ti.multiroute(5, true, 4, true, 0); expectedNptList.clear(); expectedNptList.add(new NodePortTuple(3L, (short)1)); expectedNptList.add(new NodePortTuple(3L, (short)3)); assertTrue(nptList.equals(expectedNptList)); // Ensure that for every cluster -- broadcast domain connection, // the lowest switch port is chosen for incoming broadcast traffic. NodePortTuple npt; assertTrue(ti.isIncomingBroadcastAllowedOnSwitchPort(1L, (short)1)); assertFalse(ti.isIncomingBroadcastAllowedOnSwitchPort(2L, (short)1)); assertTrue(ti.isIncomingBroadcastAllowedOnSwitchPort(3L, (short)1)); assertFalse(ti.isIncomingBroadcastAllowedOnSwitchPort(4L, (short)1)); assertTrue(ti.isIncomingBroadcastAllowedOnSwitchPort(3L, (short)3)); assertFalse(ti.isIncomingBroadcastAllowedOnSwitchPort(4L, (short)3)); assertTrue(ti.isIncomingBroadcastAllowedOnSwitchPort(5L, (short)3)); assertFalse(ti.isIncomingBroadcastAllowedOnSwitchPort(6L, (short)3)); NodePortTuple npt53; npt53 = new NodePortTuple(5L, (short)3); npt = ti.getConsistentBroadcastAttachmentPoint(6L, 1L, (short)10); log.info("{}", npt); assertTrue(npt.equals(npt53)); npt = ti.getConsistentBroadcastAttachmentPoint(6L, 1L, (short)2); assertTrue(npt == null); npt = ti.getConsistentBroadcastAttachmentPoint(6L, 4L, (short)1); assertTrue(npt.equals(npt53)); npt = ti.getConsistentBroadcastAttachmentPoint(6L, 4L, (short)1); assertTrue(npt.equals(npt53)); npt = ti.getConsistentBroadcastAttachmentPoint(6L, 15L, (short)1); assertTrue(npt == null); npt = ti.getConsistentBroadcastAttachmentPoint(15L, 15L, (short)1); assertTrue(npt.equals(new NodePortTuple(15L, (short)1))); npt = ti.getConsistentBroadcastAttachmentPoint(15L, 1L, (short)1); assertTrue(npt == null); npt = ti.getConsistentBroadcastAttachmentPoint(15L, 1L, (short)2); assertTrue(npt == null); } } /** * This test checks if the tunnel domain is created when topology * manager is created. * @throws Exception */ @Test public void testTunnelDomainCreation() throws Exception { BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager(); tm.clearCurrentTopology(); Long tunnelDomain = tm.getTunnelDomainId(); assertTrue(tunnelDomain != null); } /** * Ensure that tunnel ports are added and removed. */ @Test public void testTunnelDomainPorts() throws Exception { BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager(); tm.clearCurrentTopology(); assertTrue(tm.getTunnelPorts().isEmpty()); tm.addTunnelPort(1L, (short)10); tm.addTunnelPort(2L, (short)10); assertTrue(tm.getTunnelPorts().size() == 2); tm.removeTunnelPort(2L, (short)10); assertTrue(tm.getTunnelPorts().size() == 1); } /** * Ensure that tunnel ports are added and removed. */ @Test public void testSwitchClusterWithTunnelDomain() throws Exception { BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager(); tm.clearCurrentTopology(); // +-------+ +-------+ // | | | | // | 1 1|-------------|1 2 | // | 2 | | 2 | // +-------+ +-------+ // | | // | | // +-------+ | // | 1 | | // | 3 2|-----------------+ // | 3 | // +-------+ // // // // +-------+ // | 1 | // | 4 2|----------------+ // | 3 | | // +-------+ | // | | // | | // +-------+ +-------+ // | 1 | | 2 | // | 5 2|-------------|1 6 | // | | | | // +-------+ +-------+ { int [][] linkArray = { {1, 1, 2, 1, DIRECT_LINK}, {2, 1, 1, 1, DIRECT_LINK}, {1, 2, 3, 1, DIRECT_LINK}, {3, 1, 1, 2, DIRECT_LINK}, {2, 2, 3, 2, DIRECT_LINK}, {3, 2, 2, 2, DIRECT_LINK}, {4, 2, 6, 2, DIRECT_LINK}, {6, 2, 4, 2, DIRECT_LINK}, {4, 3, 5, 1, DIRECT_LINK}, {5, 1, 4, 3, DIRECT_LINK}, {5, 2, 6, 1, DIRECT_LINK}, {6, 1, 5, 2, DIRECT_LINK}, }; int [][] expectedClusters = { {1, 2, 3}, {4, 5, 6} }; // Use the same switch object for all values. IOFSwitch sw1 = EasyMock.createMock(IOFSwitch.class); Map<Long, IOFSwitch> switchMap = new HashMap<Long, IOFSwitch>(); switchMap.put(1L, sw1); switchMap.put(2L, sw1); switchMap.put(3L, sw1); switchMap.put(4L, sw1); switchMap.put(5L, sw1); switchMap.put(6L, sw1); mockControllerProvider.setSwitches(switchMap); expect(sw1.portEnabled(EasyMock.anyShort())).andReturn(true).anyTimes(); replay(sw1); createTopologyFromLinks(linkArray); verify(sw1); verifyClusters(expectedClusters); } { int [][] expectedClusters = { {1, 2, 3, 4, 5, 6} }; int [][][] expectedBroadcastPorts = { {{1,1}, {2,1}, {1,2}, {3,1}, {4,3}, {5,1}, {4,2}, {6,2}}, }; // Add two tunnel ports. tm.addTunnelPort(1L, (short)10); tm.addTunnelPort(4L, (short)10); // Create new instance, this should create a new instance to update // the tunnel port features. tm.createNewInstance(); verifyClusters(expectedClusters); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); // Get routes to see if the tunnel domain ports are eliminated. Route route = tm.getRoute(1L, 4L, 0); assertTrue(route != null); assertTrue(route.getPath().size() == 2); // Route doesn't exist in the tunnel-less topology. route = tm.getRoute(1L, 4L, 0, false); assertTrue(route == null || route.getPath().isEmpty()); // Verify if the routes to others are computed correctly. // The route is through the tunnel. route = tm.getRoute(1L, 5L, 0); assertTrue(route.getPath().size() == 4); assertTrue(route.getPath().contains(new NodePortTuple(1L, (short)10))); assertTrue(route.getPath().contains(new NodePortTuple(4L, (short)10))); } { // Add two tunnel ports. tm.removeTunnelPort(1L, (short)10); int [][] expectedClusters = { {1, 2, 3}, {4, 5, 6} }; tm.createNewInstance(); verifyClusters(expectedClusters); } } }