/**
* Copyright 2013, Big Switch Networks, Inc.
*
* 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.topology;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.*;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.test.MockFloodlightProvider;
import net.floodlightcontroller.core.test.MockThreadPoolService;
import net.floodlightcontroller.linkdiscovery.ILinkDiscovery;
import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.topology.NodePortTuple;
import net.floodlightcontroller.topology.TopologyInstance;
import net.floodlightcontroller.topology.TopologyManager;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TopologyInstanceTest {
protected static Logger log = LoggerFactory.getLogger(TopologyInstanceTest.class);
protected TopologyManager topologyManager;
protected FloodlightModuleContext fmc;
protected ILinkDiscoveryService linkDiscovery;
protected MockFloodlightProvider mockFloodlightProvider;
protected int DIRECT_LINK = 1;
protected int MULTIHOP_LINK = 2;
protected int TUNNEL_LINK = 3;
@Before
public void SetUp() throws Exception {
fmc = new FloodlightModuleContext();
linkDiscovery = EasyMock.createMock(ILinkDiscoveryService.class);
mockFloodlightProvider = new MockFloodlightProvider();
fmc.addService(IFloodlightProviderService.class, mockFloodlightProvider);
fmc.addService(ILinkDiscoveryService.class, linkDiscovery);
MockThreadPoolService tp = new MockThreadPoolService();
topologyManager = new TopologyManager();
fmc.addService(IThreadPoolService.class, tp);
topologyManager.init(fmc);
tp.init(fmc);
tp.startUp(fmc);
}
protected void verifyClusters(int[][] clusters) {
verifyClusters(clusters, true);
}
protected void verifyClusters(int[][] clusters, boolean tunnelsEnabled) {
List<Long> verifiedSwitches = new ArrayList<Long>();
// Make sure the expected cluster arrays are sorted so we can
// use binarySearch to test for membership
for (int i = 0; i < clusters.length; i++)
Arrays.sort(clusters[i]);
TopologyInstance ti =
topologyManager.getCurrentInstance(tunnelsEnabled);
Set<Long> switches = ti.getSwitches();
for (long sw: switches) {
if (!verifiedSwitches.contains(sw)) {
int[] expectedCluster = null;
for (int j = 0; j < clusters.length; j++) {
if (Arrays.binarySearch(clusters[j], (int) sw) >= 0) {
expectedCluster = clusters[j];
break;
}
}
if (expectedCluster != null) {
Set<Long> cluster = ti.getSwitchesInOpenflowDomain(sw);
assertEquals(expectedCluster.length, cluster.size());
for (long sw2: cluster) {
assertTrue(Arrays.binarySearch(expectedCluster, (int)sw2) >= 0);
verifiedSwitches.add(sw2);
}
}
}
}
}
protected void
verifyExpectedBroadcastPortsInClusters(int [][][] ebp) {
verifyExpectedBroadcastPortsInClusters(ebp, true);
}
protected void
verifyExpectedBroadcastPortsInClusters(int [][][] ebp,
boolean tunnelsEnabled) {
NodePortTuple npt = null;
Set<NodePortTuple> expected = new HashSet<NodePortTuple>();
for(int i=0; i<ebp.length; ++i) {
int [][] nptList = ebp[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);
}
TopologyInstance ti = topologyManager.getCurrentInstance(tunnelsEnabled);
Set<NodePortTuple> computed = ti.getBroadcastNodePortsInCluster(npt.nodeId);
log.info("computed: {}", computed);
if (computed != null)
assertTrue(computed.equals(expected));
else if (computed == null)
assertTrue(expected.isEmpty());
}
}
public void createTopologyFromLinks(int [][] linkArray) throws Exception {
ILinkDiscovery.LinkType type = ILinkDiscovery.LinkType.DIRECT_LINK;
// Use topologymanager to write this test, it will make it a lot easier.
for (int i = 0; i < linkArray.length; i++) {
int [] r = linkArray[i];
if (r[4] == DIRECT_LINK)
type= ILinkDiscovery.LinkType.DIRECT_LINK;
else if (r[4] == MULTIHOP_LINK)
type= ILinkDiscovery.LinkType.MULTIHOP_LINK;
else if (r[4] == TUNNEL_LINK)
type = ILinkDiscovery.LinkType.TUNNEL;
topologyManager.addOrUpdateLink((long)r[0], (short)r[1], (long)r[2], (short)r[3], type);
}
topologyManager.createNewInstance();
}
public TopologyManager getTopologyManager() {
return topologyManager;
}
@Test
public void testClusters() throws Exception {
TopologyManager tm = getTopologyManager();
{
int [][] linkArray = {
{1, 1, 2, 1, DIRECT_LINK},
{2, 2, 3, 2, DIRECT_LINK},
{3, 1, 1, 2, DIRECT_LINK},
{2, 3, 4, 2, DIRECT_LINK},
{3, 3, 4, 1, DIRECT_LINK}
};
int [][] expectedClusters = {
{1,2,3},
{4}
};
//tm.recompute();
createTopologyFromLinks(linkArray);
verifyClusters(expectedClusters);
}
{
int [][] linkArray = {
{5, 3, 6, 1, DIRECT_LINK}
};
int [][] expectedClusters = {
{1,2,3},
{4},
{5},
{6}
};
createTopologyFromLinks(linkArray);
verifyClusters(expectedClusters);
}
{
int [][] linkArray = {
{6, 1, 5, 3, DIRECT_LINK}
};
int [][] expectedClusters = {
{1,2,3},
{4},
{5,6}
};
createTopologyFromLinks(linkArray);
verifyClusters(expectedClusters);
}
{
int [][] linkArray = {
{4, 2, 2, 3, DIRECT_LINK}
};
int [][] expectedClusters = {
{1,2,3,4},
{5,6}
};
createTopologyFromLinks(linkArray);
verifyClusters(expectedClusters);
}
{
int [][] linkArray = {
{4, 3, 5, 1, DIRECT_LINK}
};
int [][] expectedClusters = {
{1,2,3,4},
{5,6}
};
createTopologyFromLinks(linkArray);
verifyClusters(expectedClusters);
}
{
int [][] linkArray = {
{5, 2, 2, 4, DIRECT_LINK}
};
int [][] expectedClusters = {
{1,2,3,4,5,6}
};
createTopologyFromLinks(linkArray);
verifyClusters(expectedClusters);
}
//Test 2.
{
int [][] linkArray = {
{3, 2, 2, 2, DIRECT_LINK},
{2, 1, 1, 1, DIRECT_LINK},
{1, 2, 3, 1, DIRECT_LINK},
{4, 1, 3, 3, DIRECT_LINK},
{5, 1, 4, 3, DIRECT_LINK},
{2, 4, 5, 2, DIRECT_LINK}
};
int [][] expectedClusters = {
{1,2,3,4,5,6}
};
createTopologyFromLinks(linkArray);
verifyClusters(expectedClusters);
}
// Test 3. Remove links
{
tm.removeLink((long)5,(short)3,(long)6,(short)1);
tm.removeLink((long)6,(short)1,(long)5,(short)3);
int [][] expectedClusters = {
{1,2,3,4,5},
};
topologyManager.createNewInstance();
verifyClusters(expectedClusters);
}
// Remove Switch
{
tm.removeSwitch(4);
int [][] expectedClusters = {
{1,2,3,5},
};
topologyManager.createNewInstance();
verifyClusters(expectedClusters);
}
}
@Test
public void testLoopDetectionInSingleIsland() throws Exception {
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},
{3, 3, 4, 1, DIRECT_LINK},
{4, 1, 3, 3, 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,1}, {2,1}, {1,2}, {3,1}, {3,3}, {4,1}, {4,3}, {5,1}, {4,2}, {6,2}},
};
createTopologyFromLinks(linkArray);
topologyManager.createNewInstance();
verifyClusters(expectedClusters);
verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
}
@Test
public void testLoopDetectionWithIslands() throws Exception {
// +-------+ +-------+
// | | TUNNEL | |
// | 1 1|-------------|1 2 |
// | 2 | | 2 |
// +-------+ +-------+
// | |
// | |
// +-------+ |
// | 1 | |
// | 3 2|-----------------+
// | 3 |
// +-------+
//
//
// +-------+
// | 1 | TUNNEL
// | 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,1}, {2,1}, {1,2}, {3,1}},
{{4,3}, {5,1}, {4,2}, {6,2}},
};
createTopologyFromLinks(linkArray);
topologyManager.createNewInstance();
verifyClusters(expectedClusters);
verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
}
// +-------+ +-------+
// | | TUNNEL | |
// | 1 1|-------------|1 2 |
// | 2 | | 2 |
// +-------+ +-------+
// | |
// | |
// +-------+ |
// | 1 | |
// | 3 2|-----------------+
// | 3 |
// +-------+
// |
// | TUNNEL
// |
// +-------+
// | 1 | TUNNEL
// | 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);
topologyManager.createNewInstance();
verifyClusters(expectedClusters, false);
verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
}
}
@Test
public void testLinkRemovalOnBroadcastDomainPorts() throws Exception {
{
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},
{1, 1, 3, 2, DIRECT_LINK},
// the last link should make ports
// (1,1) and (3,2) to be broadcast
// domain ports, hence all links
// from these ports must be eliminated.
};
int [][] expectedClusters = {
{1, 3}, {2},
};
createTopologyFromLinks(linkArray);
topologyManager.createNewInstance();
if (topologyManager.getCurrentInstance() instanceof TopologyInstance)
verifyClusters(expectedClusters);
}
{
int [][] linkArray = {
{1, 2, 3, 2, DIRECT_LINK},
// the last link should make ports
// (1,1) and (3,2) to be broadcast
// domain ports, hence all links
// from these ports must be eliminated.
};
int [][] expectedClusters = {
{1}, {3}, {2},
};
createTopologyFromLinks(linkArray);
topologyManager.createNewInstance();
if (topologyManager.getCurrentInstance() instanceof TopologyInstance)
verifyClusters(expectedClusters);
}
}
}