diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java index 57abf6c532b4e08b9bd7c41cca488abb69b5aa94..326ad13f1fc5f5fe35ebbddee058bda0549615ab 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java @@ -248,7 +248,7 @@ public class Device implements IDevice { blocked = new ArrayList<SwitchPort>(); clusterBlocked = new ArrayList<SwitchPort>(); } - + ITopologyService topology = deviceManager.topology; long prevCluster = 0; int clEntIndex = -1; @@ -259,10 +259,20 @@ public class Device implements IDevice { Long dpid = cur.getSwitchDPID(); Integer port = cur.getSwitchPort(); if (dpid == null || port == null || - !deviceManager.isValidAttachmentPoint(dpid, port)) + !deviceManager.isValidAttachmentPoint(dpid, port) || + ///*|| + (prev != null && + topology.isBroadcastDomainPort(prev.getSwitchDPID().longValue(), + prev.getSwitchPort().shortValue()) == false && + topology.isBroadcastDomainPort(dpid.longValue(), port.shortValue()) && + topology.isConsistent(prev.getSwitchDPID().longValue(), + prev.getSwitchPort().shortValue(), + dpid.longValue(), + port.shortValue())) + )//*/ continue; long curCluster = - topology.getSwitchClusterId(cur.switchDPID); + topology.getL2DomainId(cur.switchDPID); if (prevCluster != curCluster) { prev = null; latestLastSeen = 0; @@ -272,7 +282,7 @@ public class Device implements IDevice { clusterBlocked.clear(); } } - + if (prev != null && !(dpid.equals(prev.getSwitchDPID()) && port.equals(prev.getSwitchPort())) && diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java index 80960bbc90436048b7382f50be04c3e93afd1e27..784a43d77bca110399a72250601af7012eb3702e 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java @@ -266,9 +266,9 @@ public class DeviceManagerImpl implements r = 1; else { Long d1ClusterId = - topology.getSwitchClusterId(swdpid1); + topology.getL2DomainId(swdpid1); Long d2ClusterId = - topology.getSwitchClusterId(swdpid2); + topology.getL2DomainId(swdpid2); r = d1ClusterId.compareTo(d2ClusterId); } if (r != 0) return r; @@ -677,7 +677,7 @@ public class DeviceManagerImpl implements if (sw == null) return false; OFPhysicalPort port = sw.getPort((short)switchPort); if (port == null || !sw.portEnabled(port)) return false; - if (topology.isInternal(switchDPID, (short)switchPort)) + if (topology.isAttachmentPointPort(switchDPID, (short)switchPort) == false) return false; // Check whether the port is a physical port. We should not learn diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java index 3585833a49f3abc46bb6c4c652ce31350ce91bd7..92abe576e0df221a8ae7617a81d171dffc652a4d 100644 --- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java +++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java @@ -43,6 +43,7 @@ import net.floodlightcontroller.routing.IRoutingDecision; import net.floodlightcontroller.routing.IRoutingService; import net.floodlightcontroller.routing.Route; import net.floodlightcontroller.topology.ITopologyService; +import net.floodlightcontroller.topology.TopologyManager; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; @@ -72,7 +73,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule { return Command.CONTINUE; } - + protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, boolean requestFlowRemovedNotifn) { @@ -88,7 +89,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule { IDevice srcDevice = IDeviceService.fcStore. get(cntx, IDeviceService.CONTEXT_SRC_DEVICE); - Long srcIsland = topology.getSwitchClusterId(sw.getId()); + Long srcIsland = topology.getL2DomainId(sw.getId()); if (srcDevice == null) { log.error("No device entry found for source device"); @@ -106,7 +107,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule { boolean on_same_if = false; for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) { long dstSwDpid = dstDap.getSwitchDPID(); - Long dstIsland = topology.getSwitchClusterId(dstSwDpid); + Long dstIsland = topology.getL2DomainId(dstSwDpid); if ((dstIsland != null) && dstIsland.equals(srcIsland)) { on_same_island = true; if ((sw.getId() == dstSwDpid) && @@ -145,14 +146,14 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule { Arrays.sort(dstDaps, clusterIdComparator); int iSrcDaps = 0, iDstDaps = 0; - + while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) { SwitchPort srcDap = srcDaps[iSrcDaps]; SwitchPort dstDap = dstDaps[iDstDaps]; Long srcCluster = - topology.getSwitchClusterId(srcDap.getSwitchDPID()); + topology.getL2DomainId(srcDap.getSwitchDPID()); Long dstCluster = - topology.getSwitchClusterId(dstDap.getSwitchDPID()); + topology.getL2DomainId(dstDap.getSwitchDPID()); int srcVsDest = srcCluster.compareTo(dstCluster); if (srcVsDest == 0) { diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java index a1f58f0b35c7c30516cd8c159ed50dd4d89143aa..8f9daed0384a884f33168f3a0df0ee5e0737cc85 100644 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java +++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java @@ -403,8 +403,6 @@ public class LinkDiscoveryManager bb.putLong(result); - log.info("Controller TLV: {}", result); - bb.rewind(); bb.get(controllerTLVValue, 0, 8); diff --git a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java index 2763f90353ed58d4b56c305720b694aab334eb5e..44833301cee3ced38080a9c0f7ce57451e90ac84 100644 --- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java +++ b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java @@ -78,9 +78,9 @@ public abstract class ForwardingBase implements @Override public int compare(SwitchPort d1, SwitchPort d2) { Long d1ClusterId = - topology.getSwitchClusterId(d1.getSwitchDPID()); + topology.getL2DomainId(d1.getSwitchDPID()); Long d2ClusterId = - topology.getSwitchClusterId(d2.getSwitchDPID()); + topology.getL2DomainId(d2.getSwitchDPID()); return d1ClusterId.compareTo(d2ClusterId); } }; diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java index 1074dc1b26d380fb21ec26e16fa5289a87d8058f..fcd70ad8b132c2d3e899532862c5d65b2162f2b9 100644 --- a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java +++ b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java @@ -22,9 +22,28 @@ import net.floodlightcontroller.routing.Route; public interface IRoutingService extends IFloodlightService { + /** Provides a route between src and dst that allows tunnels. */ public Route getRoute(long src, long dst); + /** Provides a route between src and dst, with option to allow or + * not allow tunnels in the path.*/ + public Route getRoute(long src, long dst, boolean tunnelEnabled); + + + public Route getRoute(long srcId, short srcPort, + long dstId, short dstPort); + + public Route getRoute(long srcId, short srcPort, + long dstId, short dstPort, + boolean tunnelEnabled); + + /** Check if a route exists between src and dst, including tunnel links + * in the path. + */ public boolean routeExists(long src, long dst); - public BroadcastTree getBroadcastTreeForCluster(long cluster); -} + /** Check if a route exists between src and dst, with option to have + * or not have tunnels as part of the path. + */ + public boolean routeExists(long src, long dst, boolean tunnelEnabled); +} \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java index 1d8c58b619e1e3a37e46178b8f7d7f8b73028d01..df1b2e3b195a35cfdba468e6b83d7f9dfeda64f2 100644 --- a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java +++ b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java @@ -5,41 +5,36 @@ import java.util.Set; import net.floodlightcontroller.core.module.IFloodlightService; public interface ITopologyService extends IFloodlightService { + + public void addListener(ITopologyListener listener); + /** - * Query to determine if the specified switch id and port are - * connected to another switch or not. If so, this means the link - * is passing LLDPs properly between two OpenFlow switches. - * @param switchid - * @param port - * @return + * Query to determine if devices must be learned on a given switch port. */ - public boolean isInternal(long switchid, short port); + public boolean isAttachmentPointPort(long switchid, short port); + public boolean isAttachmentPointPort(long switchid, short port, + boolean tunnelEnabled); + + public long getOpenflowDomainId(long switchId); + public long getOpenflowDomainId(long switchId, boolean tunnelEnabled); /** - * Returns the cluster ID of a given switch. + * Returns the identifier of the L2 domain of a given switch. * @param switchId The DPID of the switch in long form * @return The DPID of the switch that is the key for the cluster */ - public long getSwitchClusterId(long switchId); - - /** - * Retrieves a set of all the switches in the same cluster as sw. - * A cluster is a set of switches that are directly or indirectly - * connected via Openflow switches that use the same controller - * (not necessarily the same controller instance but any controller - * instance in a group sharing the same network database). - * @param sw The switch whose cluster we're obtaining - * @return Set of switches in the cluster - */ - public Set<Long> getSwitchesInCluster(long switchId); + public long getL2DomainId(long switchId); + public long getL2DomainId(long switchId, boolean tunnelEnabled); /** * Queries whether two switches are in the same cluster. - * @param switch1 the DPID of the first switch - * @param switch2 the DPID of the second switch + * @param switch1 + * @param switch2 * @return true if the switches are in the same cluster */ - public boolean inSameCluster(long switch1, long switch2); + public boolean inSameOpenflowDomain(long switch1, long switch2); + public boolean inSameOpenflowDomain(long switch1, long switch2, + boolean tunnelEnabled); /** * Queries whether two switches are in the same island. @@ -49,71 +44,134 @@ public interface ITopologyService extends IFloodlightService { * @param switch2 * @return True of they are in the same island, false otherwise */ - public boolean inSameIsland(long switch1, long switch2); + public boolean inSameL2Domain(long switch1, long switch2); + public boolean inSameL2Domain(long switch1, long switch2, + boolean tunnelEnabled); + + public boolean isBroadcastDomainPort(long sw, short port); + public boolean isBroadcastDomainPort(long sw, short port, + boolean tunnelEnabled); + + + public boolean isAllowed(long sw, short portId); + public boolean isAllowed(long sw, short portId, boolean tunnelEnabled); /** - * Adds a listener to get topology notifications - * @param listener The module that wants to listen for events + * Indicates if an attachment point on the new switch port is consistent + * with the attachment point on the old switch port or not. */ - public void addListener(ITopologyListener listener); + public boolean isConsistent(long oldSw, short oldPort, + long newSw, short newPort); + public boolean isConsistent(long oldSw, short oldPort, + long newSw, short newPort, + boolean tunnelEnabled); /** - * Gets the set of ports that belong to a broadcast domain. - * @return The set of ports that belong to a broadcast domain. + * Indicates if the two switch ports are connected to the same + * broadcast domain or not. + * @param s1 + * @param p1 + * @param s2 + * @param p2 + * @return */ - public Set<NodePortTuple> getBroadcastDomainLinks(); - + public boolean isInSameBroadcastDomain(long s1, short p1, + long s2, short p2); + public boolean isInSameBroadcastDomain(long s1, short p1, + long s2, short p2, + boolean tunnelEnabled); + /** - * Returns that set of links that are tunnel links. - * @return The set of links that are tunnel links. + * Gets a list of ports on a given switch that are known to topology. + * @param sw The switch DPID in long + * @return The set of ports on this switch + */ + public Set<Short> getPorts(long sw); + public Set<Short> getPorts(long sw, boolean tunnelEnabled); + + /** Get broadcast ports on a target switch for a given attachmentpoint + * point port. */ - public Set<NodePortTuple> getTunnelLinks(); + public Set<Short> getBroadcastPorts(long targetSw, long src, short srcPort); + + public Set<Short> getBroadcastPorts(long targetSw, long src, short srcPort, + boolean tunnelEnabled); - public boolean isBroadcastDomainPort(long sw, short port); + /** + * + */ + public boolean isIncomingBroadcastAllowed(long sw, short portId); + public boolean isIncomingBroadcastAllowed(long sw, short portId, + boolean tunnelEnabled); - public boolean isAllowed(long sw, short portId); - public boolean isConsistent(long oldSw, short oldPort, long newSw, - short newPort); + /** Get the proper outgoing switchport for a given pair of src-dst + * switchports. + */ + public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, + long dst, short dstPort); + + + public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, + long dst, short dstPort, + boolean tunnelEnabled); + + + public NodePortTuple getIncomingSwitchPort(long src, short srcPort, + long dst, short dstPort); + public NodePortTuple getIncomingSwitchPort(long src, short srcPort, + long dst, short dstPort, + boolean tunnelEnabled); + /** - * If the dst is not allowed by the higher-level topology, this method provides - * the topologically equivalent broadcast port. + * If the dst is not allowed by the higher-level topology, + * this method provides the topologically equivalent broadcast port. * @param src * @param dst * @return the allowed broadcast port */ - public NodePortTuple getAllowedOutgoingBroadcastPort(long src, - short srcPort, - long dst, - short dstPort); - + public NodePortTuple + getAllowedOutgoingBroadcastPort(long src, + short srcPort, + long dst, + short dstPort); + + public NodePortTuple + getAllowedOutgoingBroadcastPort(long src, + short srcPort, + long dst, + short dstPort, + boolean tunnelEnabled); + /** - * If the src broadcast domain port is not allowed for incoming broadcast, - * this method provides the topologically equivalent incoming broadcast-allowed + * If the src broadcast domain port is not allowed for incoming + * broadcast, this method provides the topologically equivalent + * incoming broadcast-allowed * src port. * @param src * @param dst * @return the allowed broadcast port */ - public NodePortTuple getAllowedIncomingBroadcastPort(long src, - short srcPort); - - public boolean isIncomingBroadcastAllowed(long sw, short portId); + public NodePortTuple + getAllowedIncomingBroadcastPort(long src, + short srcPort); - public boolean isInSameBroadcastDomain(long s1, short p1, long s2, short p2); + public NodePortTuple + getAllowedIncomingBroadcastPort(long src, + short srcPort, + boolean tunnelEnabled); + /** - * Gets a list of ports on a given switch - * @param sw The switch DPID in long - * @return The set of ports on this switch + * Gets the set of ports that belong to a broadcast domain. + * @return The set of ports that belong to a broadcast domain. */ - public Set<Short> getPorts(long sw); - - public Set<Short> getBroadcastPorts(long targetSw, long src, short srcPort); - - public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, - long dst, short dstPort); - - public NodePortTuple getIncomingSwitchPort(long src, short srcPort, - long dst, short dstPort); + public Set<NodePortTuple> getBroadcastDomainPorts(); + public Set<NodePortTuple> getTunnelPorts(); + + /** + * Indicates if tunnels are allowed between a given source + * destination pair. + */ + public boolean isTunnelEnabled(long srcMac, long dstMac); } diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java index d69a6ec2ca2858b7eda863b9172a2227b722cdd2..a106bdccb1a45e6927f80b5282aaa5c9b27a9434 100644 --- a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java +++ b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java @@ -2,6 +2,7 @@ package net.floodlightcontroller.topology; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.PriorityQueue; @@ -31,19 +32,26 @@ public class TopologyInstance { protected static Logger log = LoggerFactory.getLogger(TopologyInstance.class); protected Map<Long, Set<Short>> switchPorts; // Set of ports for each switch + /** Set of switch ports that are marked as blocked. A set of blocked + * switch ports may be provided at the time of instantiation. In addition, + * we may add additional ports to this set. + */ + protected Set<NodePortTuple> blockedPorts; protected Map<NodePortTuple, Set<Link>> switchPortLinks; // Set of links organized by node port tuple + /** Set of links that are blocked. */ + protected Set<Link> blockedLinks; protected Set<Long> switches; protected Set<NodePortTuple> broadcastDomainPorts; protected Set<NodePortTuple> tunnelPorts; - protected Set<Cluster> clusters; // set of clusters - protected Map<Long, Cluster> switchClusterMap; // switch to cluster map + protected Set<Cluster> clusters; // set of openflow domains + protected Map<Long, Cluster> switchClusterMap; // switch to OF domain map // States for routing - protected Map<Long, BroadcastTree> destinationRootedTrees; // DPID -> BroadcastTree - protected Map<Long, Set<NodePortTuple>> clusterBroadcastNodePorts; // ClusterID -> BroadcastTree - protected Map<Long, BroadcastTree> clusterBroadcastTrees; // ClusterID -> BroadcastTree + protected Map<Long, BroadcastTree> destinationRootedTrees; + protected Map<Long, Set<NodePortTuple>> clusterBroadcastNodePorts; + protected Map<Long, BroadcastTree> clusterBroadcastTrees; protected LRUHashMap<RouteId, Route> pathcache; public TopologyInstance() { @@ -52,23 +60,33 @@ public class TopologyInstance { this.switchPortLinks = new HashMap<NodePortTuple, Set<Link>>(); this.broadcastDomainPorts = new HashSet<NodePortTuple>(); this.tunnelPorts = new HashSet<NodePortTuple>(); + this.blockedPorts = new HashSet<NodePortTuple>(); + this.blockedLinks = new HashSet<Link>(); } public TopologyInstance(Map<Long, Set<Short>> switchPorts, + Set<NodePortTuple> blockedPorts, Map<NodePortTuple, Set<Link>> switchPortLinks, - Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks, - Map<NodePortTuple, Set<Link>> tunnelLinks){ + Set<NodePortTuple> broadcastDomainPorts, + Set<NodePortTuple> tunnelPorts){ // copy these structures this.switches = new HashSet<Long>(switchPorts.keySet()); - this.switchPorts = new HashMap<Long, Set<Short>>(switchPorts); - this.switchPortLinks = new HashMap<NodePortTuple, Set<Link>>(switchPortLinks); - this.broadcastDomainPorts = new HashSet<NodePortTuple>(portBroadcastDomainLinks.keySet()); - this.tunnelPorts = new HashSet<NodePortTuple>(tunnelLinks.keySet()); + this.switchPorts = new HashMap<Long, Set<Short>>(); + for(long sw: switchPorts.keySet()) { + this.switchPorts.put(sw, new HashSet<Short>(switchPorts.get(sw))); + } - // create new empty ones. - //blockedPorts = new HashSet<NodePortTuple>(); + this.blockedPorts = new HashSet<NodePortTuple>(blockedPorts); + this.switchPortLinks = new HashMap<NodePortTuple, Set<Link>>(); + for(NodePortTuple npt: switchPortLinks.keySet()) { + this.switchPortLinks.put(npt, + new HashSet<Link>(switchPortLinks.get(npt))); + } + this.broadcastDomainPorts = new HashSet<NodePortTuple>(broadcastDomainPorts); + this.tunnelPorts = new HashSet<NodePortTuple>(tunnelPorts); + blockedLinks = new HashSet<Link>(); clusters = new HashSet<Cluster>(); switchClusterMap = new HashMap<Long, Cluster>(); destinationRootedTrees = new HashMap<Long, BroadcastTree>(); @@ -78,12 +96,19 @@ public class TopologyInstance { } public void compute() { + // Step 1: Compute clusters ignoring broadcast domain links // Create nodes for clusters in the higher level topology - identifyClusters(); + // Must ignore blocked links. + identifyOpenflowDomains(); + + // Step 0: Remove all links connected to blocked ports. + // removeLinksOnBlockedPorts(); + // Step 1.1: Add links to clusters - addLinksToClusters(); + // Avoid adding blocked links to clusters + addLinksToOpenflowDomains(); // Step 2. Compute shortest path trees in each cluster for // unicast routing. The trees are rooted at the destination. @@ -112,7 +137,7 @@ public class TopologyInstance { log.debug("-----------------------------------------------"); } - protected void addLinksToClusters() { + protected void addLinksToOpenflowDomains() { for(long s: switches) { if (switchPorts.get(s) == null) continue; for (short p: switchPorts.get(s)) { @@ -120,6 +145,7 @@ public class TopologyInstance { if (switchPortLinks.get(np) == null) continue; if (isBroadcastDomainPort(np)) continue; for(Link l: switchPortLinks.get(np)) { + if (isBlockedLink(l)) continue; if (isBroadcastDomainLink(l)) continue; Cluster c1 = switchClusterMap.get(l.getSrc()); Cluster c2 = switchClusterMap.get(l.getDst()); @@ -145,7 +171,7 @@ public class TopologyInstance { * * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm */ - public void identifyClusters() { + public void identifyOpenflowDomains() { Map<Long, ClusterDFS> dfsList = new HashMap<Long, ClusterDFS>(); if (switches == null) return; @@ -225,6 +251,9 @@ public class TopologyInstance { // another cluster if (switchClusterMap.get(dstSw) != null) continue; + // ignore the link if it is blocked. + if (isBlockedLink(l)) continue; + // ignore this link if it is in broadcast domain if (isBroadcastDomainLink(l)) continue; @@ -278,6 +307,74 @@ public class TopologyInstance { return currIndex; } + /** + * Go through every link and identify it is a blocked link or not. + * If blocked, remove it from the switchport links and put them in the + * blocked link category. + * + * Note that we do not update the tunnel ports and broadcast domain + * port structures. We need those to still answer the question if the + * ports are tunnel or broadcast domain ports. + * + * If we add additional ports to blocked ports later on, we may simply + * call this method again to remove the links on the newly blocked ports. + */ + protected void removeLinksOnBlockedPorts() { + Iterator<NodePortTuple> nptIter; + Iterator<Link> linkIter; + + // Iterate through all the links and all the switch ports + // and move the links on blocked switch ports to blocked links + nptIter = this.switchPortLinks.keySet().iterator(); + while (nptIter.hasNext()) { + NodePortTuple npt = nptIter.next(); + linkIter = switchPortLinks.get(npt).iterator(); + while (linkIter.hasNext()) { + Link link = linkIter.next(); + if (isBlockedLink(link)) { + this.blockedLinks.add(link); + linkIter.remove(); + } + } + // Note that at this point, the switchport may have + // no links in it. We could delete the switch port, + // but we will leave it as is. + } + } + + public Set<NodePortTuple> getBlockedPorts() { + return this.blockedPorts; + } + + protected Set<Link> getBlockedLinks() { + return this.blockedLinks; + } + + /** Returns true if a link has either one of its switch ports + * blocked. + * @param l + * @return + */ + protected boolean isBlockedLink(Link l) { + NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); + NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); + return (isBlockedPort(n1) || isBlockedPort(n2)); + } + + protected boolean isBlockedPort(NodePortTuple npt) { + return blockedPorts.contains(npt); + } + + protected boolean isTunnelPort(NodePortTuple npt) { + return tunnelPorts.contains(npt); + } + + protected boolean isTunnelLink(Link l) { + NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); + NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); + return (isTunnelPort(n1) || isTunnelPort(n2)); + } + public boolean isBroadcastDomainLink(Link l) { NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort()); NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); @@ -314,13 +411,13 @@ public class TopologyInstance { protected BroadcastTree dijkstra(Cluster c, Long dst, Map<Link, Integer> linkCost) { HashMap<Long, Link> nexthoplinks = new HashMap<Long, Link>(); - HashMap<Long, Long> nexthopnodes = new HashMap<Long, Long>(); + //HashMap<Long, Long> nexthopnodes = new HashMap<Long, Long>(); HashMap<Long, Integer> cost = new HashMap<Long, Integer>(); int w; for (Long node: c.links.keySet()) { nexthoplinks.put(node, null); - nexthopnodes.put(node, null); + //nexthopnodes.put(node, null); cost.put(node, MAX_PATH_WEIGHT); } @@ -345,7 +442,7 @@ public class TopologyInstance { if (ndist < cost.get(neighbor)) { cost.put(neighbor, ndist); nexthoplinks.put(neighbor, link); - nexthopnodes.put(neighbor, cnode); + //nexthopnodes.put(neighbor, cnode); nodeq.add(new NodeDist(neighbor, ndist)); } } @@ -358,9 +455,21 @@ public class TopologyInstance { protected void calculateShortestPathTreeInClusters() { pathcache.clear(); destinationRootedTrees.clear(); + + Map<Link, Integer> linkCost = new HashMap<Link, Integer>(); + int tunnel_weight = switchPorts.size() + 1; + + for(NodePortTuple npt: tunnelPorts) { + if (switchPortLinks.get(npt) == null) continue; + for(Link link: switchPortLinks.get(npt)) { + if (link == null) continue; + linkCost.put(link, tunnel_weight); + } + } + for(Cluster c: clusters) { for (Long node : c.links.keySet()) { - BroadcastTree tree = dijkstra(c, node, null); + BroadcastTree tree = dijkstra(c, node, linkCost); destinationRootedTrees.put(node, tree); } } @@ -400,7 +509,7 @@ public class TopologyInstance { } } - private Route buildroute(RouteId id, long srcId, long dstId) { + protected Route buildroute(RouteId id, long srcId, long dstId) { LinkedList<Link> path = new LinkedList<Link>(); if (destinationRootedTrees == null) return null; @@ -456,6 +565,13 @@ public class TopologyInstance { return true; } + protected Route getRoute(long srcId, short srcPort, + long dstId, short dstPort) { + // currently ignores source and dst ports. + // if needed we can get different paths. + return getRoute(srcId, dstId); + } + protected Route getRoute(long srcId, long dstId) { RouteId id = new RouteId(srcId, dstId); Route result = null; @@ -481,25 +597,33 @@ public class TopologyInstance { // ITopologyService interface method helpers. // - protected boolean isInternal(long switchid, short port) { + protected boolean isInternalToOpenflowDomain(long switchid, short port) { NodePortTuple npt = new NodePortTuple(switchid, port); if (switchPortLinks.containsKey(npt)) return true; return false; } - protected long getSwitchClusterId(long switchId) { + public boolean isAttachmentPointPort(long switchid, short port) { + return !isInternalToOpenflowDomain(switchid, port); + } + + protected long getOpenflowDomainId(long switchId) { Cluster c = switchClusterMap.get(switchId); if (c == null) return switchId; return c.getId(); } - protected Set<Long> getSwitchesInCluster(long switchId) { + protected long getL2DomainId(long switchId) { + return getOpenflowDomainId(switchId); + } + + protected Set<Long> getSwitchesInOpenflowDomain(long switchId) { Cluster c = switchClusterMap.get(switchId); if (c == null) return null; return (c.getNodes()); } - protected boolean inSameCluster(Long switch1, Long switch2) { + protected boolean inSameOpenflowDomain(long switch1, long switch2) { Cluster c1 = switchClusterMap.get(switch1); Cluster c2 = switchClusterMap.get(switch2); if (c1 != null && c2 != null) @@ -513,8 +637,8 @@ public class TopologyInstance { protected boolean isIncomingBroadcastAllowedOnSwitchPort(long sw, short portId) { - if (isInternal(sw, portId)) { - long clusterId = getSwitchClusterId(sw); + if (isInternalToOpenflowDomain(sw, portId)) { + long clusterId = getOpenflowDomainId(sw); NodePortTuple npt = new NodePortTuple(sw, portId); if (clusterBroadcastNodePorts.get(clusterId).contains(npt)) return true; @@ -525,22 +649,22 @@ public class TopologyInstance { public boolean isConsistent(long oldSw, short oldPort, long newSw, short newPort) { - if (isInternal(newSw, newPort)) return true; + if (isInternalToOpenflowDomain(newSw, newPort)) return true; return (oldSw == newSw && oldPort == newPort); } protected Set<NodePortTuple> getBroadcastNodePortsInCluster(long sw) { - long clusterId = getSwitchClusterId(sw); + long clusterId = getOpenflowDomainId(sw); return clusterBroadcastNodePorts.get(clusterId); } - public boolean isInSameBroadcastDomain(long s1, short p1, long s2, short p2) { + public boolean inSameBroadcastDomain(long s1, short p1, long s2, short p2) { return false; } - public boolean inSameIsland(long switch1, long switch2) { - return inSameCluster(switch1, switch2); + public boolean inSameL2Domain(long switch1, long switch2) { + return inSameOpenflowDomain(switch1, switch2); } public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, @@ -565,7 +689,7 @@ public class TopologyInstance { public Set<Short> getBroadcastPorts(long targetSw, long src, short srcPort) { Set<Short> result = new HashSet<Short>(); - long clusterId = getSwitchClusterId(targetSw); + long clusterId = getOpenflowDomainId(targetSw); for(NodePortTuple npt: clusterBroadcastNodePorts.get(clusterId)) { if (npt.getNodeId() == targetSw) { result.add(npt.getPortId()); diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java index 5865c246c146e8f3572a12ea2aabd34082cc6915..f0b278590e1616a948cb75875181659f9c201050 100644 --- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java +++ b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java @@ -1,9 +1,11 @@ package net.floodlightcontroller.topology; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.BlockingQueue; @@ -22,11 +24,11 @@ import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.core.util.SingletonTask; +import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener; import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.restserver.IRestApiService; -import net.floodlightcontroller.routing.BroadcastTree; import net.floodlightcontroller.routing.IRoutingService; import net.floodlightcontroller.routing.Link; import net.floodlightcontroller.routing.Route; @@ -35,7 +37,11 @@ import net.floodlightcontroller.topology.web.TopologyWebRoutable; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; +import org.openflow.protocol.OFPacketOut; +import org.openflow.protocol.OFPort; import org.openflow.protocol.OFPhysicalPort.OFPortState; +import org.openflow.protocol.action.OFAction; +import org.openflow.protocol.action.OFActionOutput; import org.openflow.protocol.OFType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,21 +58,24 @@ public class TopologyManager implements protected static Logger log = LoggerFactory.getLogger(TopologyManager.class); + public static final String CONTEXT_TUNNEL_ENABLED = + "com.bigswitch.floodlight.topologymanager.tunnelEnabled"; + /** * Set of ports for each switch */ protected Map<Long, Set<Short>> switchPorts; - + /** * Set of links organized by node port tuple */ protected Map<NodePortTuple, Set<Link>> switchPortLinks; - + /** * set of links that are broadcast domain links. */ protected Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks; - + /** * set of tunnel links */ @@ -74,6 +83,7 @@ public class TopologyManager implements protected ILinkDiscoveryService linkDiscovery; protected IThreadPoolService threadPool; protected IFloodlightProviderService floodlightProvider; + protected ICounterStoreService counterStore; protected IRestApiService restApi; // Modules that listen to our updates @@ -81,9 +91,9 @@ public class TopologyManager implements protected BlockingQueue<LDUpdate> ldUpdates; protected TopologyInstance currentInstance; + protected TopologyInstance currentInstanceWithoutTunnels; protected SingletonTask newInstanceTask; - /** * Thread for recomputing topology. The thread is always running, * however the function applyUpdates() has a blocking call. @@ -128,136 +138,319 @@ public class TopologyManager implements // ITopologyService // **************** + // + // ITopologyService interface methods + // + @Override - public boolean isInternal(long switchid, short port) { - return currentInstance.isInternal(switchid, port); + public void addListener(ITopologyListener listener) { + topologyAware.add(listener); + } + + @Override + public boolean isAttachmentPointPort(long switchid, short port) { + return isAttachmentPointPort(switchid, port, true); } @Override - public long getSwitchClusterId(long switchId) { - return currentInstance.getSwitchClusterId(switchId); + public boolean isAttachmentPointPort(long switchid, short port, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.isAttachmentPointPort(switchid, port); + } + + public long getOpenflowDomainId(long switchId) { + return getOpenflowDomainId(switchId, true); + } + + public long getOpenflowDomainId(long switchId, boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getOpenflowDomainId(switchId); } @Override - public Set<Long> getSwitchesInCluster(long switchId) { - return currentInstance.getSwitchesInCluster(switchId); + public long getL2DomainId(long switchId) { + return getL2DomainId(switchId, true); } @Override - public boolean inSameCluster(long switch1, long switch2) { - return currentInstance.inSameCluster(switch1, switch2); + public long getL2DomainId(long switchId, boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getL2DomainId(switchId); } @Override - public void addListener(ITopologyListener listener) { - topologyAware.add(listener); + public boolean inSameOpenflowDomain(long switch1, long switch2) { + return inSameOpenflowDomain(switch1, switch2, true); } @Override - public boolean isAllowed(long sw, short portId) { - return currentInstance.isAllowed(sw, portId); + public boolean inSameOpenflowDomain(long switch1, long switch2, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.inSameOpenflowDomain(switch1, switch2); } @Override - public NodePortTuple getAllowedOutgoingBroadcastPort(long src, - short srcPort, - long dst, - short dstPort) { - return currentInstance.getAllowedOutgoingBroadcastPort(src,srcPort, - dst,dstPort); + public boolean isAllowed(long sw, short portId) { + return isAllowed(sw, portId, true); } @Override - public NodePortTuple getAllowedIncomingBroadcastPort(long src, - short srcPort) { - return currentInstance.getAllowedIncomingBroadcastPort(src,srcPort); + public boolean isAllowed(long sw, short portId, boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.isAllowed(sw, portId); } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// @Override public boolean isIncomingBroadcastAllowed(long sw, short portId) { - return currentInstance.isIncomingBroadcastAllowedOnSwitchPort(sw, - portId); + return isIncomingBroadcastAllowed(sw, portId, true); } + public boolean isIncomingBroadcastAllowed(long sw, short portId, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.isIncomingBroadcastAllowedOnSwitchPort(sw, portId); + } + + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + /** Get all the ports connected to the switch */ @Override public Set<Short> getPorts(long sw) { - return currentInstance.getPorts(sw); + return getPorts(sw, true); } - public Set<Short> getBroadcastPorts(long targetSw, long src, - short srcPort) { - return currentInstance.getBroadcastPorts(targetSw, src, srcPort); + /** Get all the ports connected to the switch */ + @Override + public Set<Short> getPorts(long sw, boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getPorts(sw); } - @Override - public boolean isInSameBroadcastDomain(long s1, short p1, - long s2, short p2) { - return currentInstance.isInSameBroadcastDomain(s1, p1, s2, p2); + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + /** Get all the ports on the target switch (targetSw) on which a + * broadcast packet must be sent from a host whose attachment point + * is on switch port (src, srcPort). + */ + public Set<Short> getBroadcastPorts(long targetSw, + long src, short srcPort) { + return getBroadcastPorts(targetSw, src, srcPort, true); + } + /** Get all the ports on the target switch (targetSw) on which a + * broadcast packet must be sent from a host whose attachment point + * is on switch port (src, srcPort). + */ + public Set<Short> getBroadcastPorts(long targetSw, + long src, short srcPort, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getBroadcastPorts(targetSw, src, srcPort); } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// @Override public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, long dst, short dstPort) { // Use this function to redirect traffic if needed. - return currentInstance.getOutgoingSwitchPort(src, srcPort, + return getOutgoingSwitchPort(src, srcPort, dst, dstPort, true); + } + + @Override + public NodePortTuple getOutgoingSwitchPort(long src, short srcPort, + long dst, short dstPort, + boolean tunnelEnabled) { + // Use this function to redirect traffic if needed. + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getOutgoingSwitchPort(src, srcPort, dst, dstPort); } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// @Override public NodePortTuple getIncomingSwitchPort(long src, short srcPort, long dst, short dstPort) { - return currentInstance.getIncomingSwitchPort(src, srcPort, + return getIncomingSwitchPort(src, srcPort, dst, dstPort, true); + } + + @Override + public NodePortTuple getIncomingSwitchPort(long src, short srcPort, + long dst, short dstPort, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getIncomingSwitchPort(src, srcPort, dst, dstPort); } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + /** + * Checks if the two switchports belong to the same broadcast domain. + */ + @Override + public boolean isInSameBroadcastDomain(long s1, short p1, long s2, + short p2) { + return isInSameBroadcastDomain(s1, p1, s2, p2, true); + + } + + @Override + public boolean isInSameBroadcastDomain(long s1, short p1, + long s2, short p2, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.inSameBroadcastDomain(s1, p1, s2, p2); + + } + + + /** + * Checks if the switchport is a broadcast domain port or not. + */ @Override public boolean isBroadcastDomainPort(long sw, short port) { - return currentInstance.isBroadcastDomainPort(new NodePortTuple(sw, - port)); + return isBroadcastDomainPort(sw, port, true); } @Override - public boolean isConsistent(long oldSw, short oldPort, long newSw, - short newPort) { - return currentInstance.isConsistent(oldSw, oldPort, newSw, newPort); + public boolean isBroadcastDomainPort(long sw, short port, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.isBroadcastDomainPort(new NodePortTuple(sw, port)); } + + /** + * Checks if the new attachment point port is consistent with the + * old attachment point port. + */ @Override - public boolean inSameIsland(long switch1, long switch2) { - return currentInstance.inSameIsland(switch1, switch2); + public boolean isConsistent(long oldSw, short oldPort, + long newSw, short newPort) { + return isConsistent(oldSw, oldPort, + newSw, newPort, true); } - + + @Override + public boolean isConsistent(long oldSw, short oldPort, + long newSw, short newPort, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.isConsistent(oldSw, oldPort, newSw, newPort); + } + + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + /** + * Checks if the two switches are in the same Layer 2 domain. + */ + @Override + public boolean inSameL2Domain(long switch1, long switch2) { + return inSameL2Domain(switch1, switch2, true); + } + + @Override + public boolean inSameL2Domain(long switch1, long switch2, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.inSameL2Domain(switch1, switch2); + } + + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + @Override + public NodePortTuple getAllowedOutgoingBroadcastPort(long src, + short srcPort, + long dst, + short dstPort) { + return getAllowedOutgoingBroadcastPort(src, srcPort, + dst, dstPort, true); + } + + @Override + public NodePortTuple getAllowedOutgoingBroadcastPort(long src, + short srcPort, + long dst, + short dstPort, + boolean tunnelEnabled){ + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getAllowedOutgoingBroadcastPort(src, srcPort, + dst, dstPort); + } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + @Override + public NodePortTuple + getAllowedIncomingBroadcastPort(long src, short srcPort) { + return getAllowedIncomingBroadcastPort(src,srcPort, true); + } + + @Override + public NodePortTuple + getAllowedIncomingBroadcastPort(long src, short srcPort, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getAllowedIncomingBroadcastPort(src,srcPort); + } + @Override - public Set<NodePortTuple> getBroadcastDomainLinks() { + public Set<NodePortTuple> getBroadcastDomainPorts() { return portBroadcastDomainLinks.keySet(); } @Override - public Set<NodePortTuple> getTunnelLinks() { + public Set<NodePortTuple> getTunnelPorts() { return tunnelLinks.keySet(); } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + // *************** // IRoutingService // *************** @Override public Route getRoute(long src, long dst) { - Route r = currentInstance.getRoute(src, dst); - return r; + return getRoute(src, dst, true); + } + + @Override + public Route getRoute(long src, long dst, boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getRoute(src, dst); + } + + @Override + public Route getRoute(long src, short srcPort, long dst, short dstPort) { + return getRoute(src, srcPort, dst, dstPort, true); + } + + @Override + public Route getRoute(long src, short srcPort, long dst, short dstPort, + boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.getRoute(src, srcPort, dst, dstPort); } @Override public boolean routeExists(long src, long dst) { - return currentInstance.routeExists(src, dst); + return routeExists(src, dst, true); } @Override - public BroadcastTree getBroadcastTreeForCluster(long clusterId) { - return currentInstance.getBroadcastTreeForCluster(clusterId); + public boolean routeExists(long src, long dst, boolean tunnelEnabled) { + TopologyInstance ti = getCurrentInstance(tunnelEnabled); + return ti.routeExists(src, dst); } + // ****************** // IOFMessageListener // ****************** @@ -356,6 +549,7 @@ public class TopologyManager implements l.add(ILinkDiscoveryService.class); l.add(IThreadPoolService.class); l.add(IFloodlightProviderService.class); + l.add(ICounterStoreService.class); l.add(IRestApiService.class); return l; } @@ -367,14 +561,17 @@ public class TopologyManager implements threadPool = context.getServiceImpl(IThreadPoolService.class); floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); + counterStore = + context.getServiceImpl(ICounterStoreService.class); restApi = context.getServiceImpl(IRestApiService.class); - + switchPorts = new HashMap<Long,Set<Short>>(); switchPortLinks = new HashMap<NodePortTuple, Set<Link>>(); portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>(); tunnelLinks = new HashMap<NodePortTuple, Set<Link>>(); topologyAware = new ArrayList<ITopologyListener>(); ldUpdates = new LinkedBlockingQueue<LDUpdate>(); + } @Override @@ -390,17 +587,24 @@ public class TopologyManager implements // **************** // Internal methods // **************** - - protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, + public static boolean isTunnelEnabled(FloodlightContext cntx) { + if (cntx == null) return false; + Boolean flag = (Boolean) cntx.getStorage().get(CONTEXT_TUNNEL_ENABLED); + if (flag == null || flag == false) return false; + return true; + } + + protected Command dropFilter(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) { + Command result = Command.CONTINUE; Ethernet eth = IFloodlightProviderService.bcStore. get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD); - + if (isAllowed(sw.getId(), pi.getInPort()) == false) { if (eth.getEtherType() == Ethernet.TYPE_BDDP || (eth.isBroadcast() == false && eth.isMulticast() == false)) { - return Command.CONTINUE; + result = Command.CONTINUE; } else { if (log.isTraceEnabled()) { log.trace("Ignoring packet because of topology " + @@ -408,12 +612,153 @@ public class TopologyManager implements new Object[] {sw.getStringId(), pi.getInPort()}); } - return Command.STOP; + result = Command.STOP; } } - return Command.CONTINUE; + return result; + } + + protected void checkTunnelUsage(IOFSwitch sw, OFPacketIn pi, + FloodlightContext cntx) { + // tunnels are disabled. + cntx.getStorage().put(CONTEXT_TUNNEL_ENABLED, false); } + + /** + * TODO This method must be moved to a layer below forwarding + * so that anyone can use it. + * @param packetData + * @param sw + * @param ports + * @param cntx + */ + public void doMultiActionPacketOut(byte[] packetData, IOFSwitch sw, + Set<Short> ports, + FloodlightContext cntx) { + + if (ports == null) return; + if (packetData == null || packetData.length <= 0) return; + + OFPacketOut po = + (OFPacketOut) floodlightProvider.getOFMessageFactory(). + getMessage(OFType.PACKET_OUT); + + List<OFAction> actions = new ArrayList<OFAction>(); + for(short p: ports) { + actions.add(new OFActionOutput(p, (short) 0)); + } + + // set actions + po.setActions(actions); + // set action length + po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * + ports.size())); + // set buffer-id to BUFFER_ID_NONE + po.setBufferId(OFPacketOut.BUFFER_ID_NONE); + // set in-port to OFPP_NONE + po.setInPort(OFPort.OFPP_NONE.getValue()); + + // set packet data + po.setPacketData(packetData); + + // compute and set packet length. + short poLength = (short)(OFPacketOut.MINIMUM_LENGTH + + po.getActionsLength() + + packetData.length); + + po.setLength(poLength); + + try { + //counterStore.updatePktOutFMCounterStore(sw, po); + if (log.isTraceEnabled()) { + log.trace("write broadcast packet on switch-id={} " + + "interaces={} packet-data={} packet-out={}", + new Object[] {sw.getId(), ports, packetData, po}); + } + sw.write(po, cntx); + + } catch (IOException e) { + log.error("Failure writing packet out", e); + } + } + + + /** + * The BDDP packets are forwarded out of all the ports out of an + * openflowdomain. Get all the switches in the same openflow + * domain as the sw (disabling tunnels). Then get all the + * external switch ports and send these packets out. + * @param sw + * @param pi + * @param cntx + */ + protected void doFloodBDDP(long pinSwitch, OFPacketIn pi, + FloodlightContext cntx) { + + TopologyInstance ti = this.currentInstanceWithoutTunnels; + + Set<Long> switches = ti.getSwitchesInOpenflowDomain(pinSwitch); + + if (switches == null) // this implies that there are no links connected to the switches + { + switches = new HashSet<Long>(); + switches.add(pinSwitch); + } + + for(long sid: switches) { + IOFSwitch sw = floodlightProvider.getSwitches().get(sid); + if (sw == null) continue; + Set<Short> ports = new HashSet<Short>(); + if (sw.getPorts() == null) continue; + ports.addAll(sw.getPorts().keySet()); + + // all the ports known to topology // without tunnels. + // out of these, we need to choose only those that are + // broadcast port, otherwise, we should eliminate. + Set<Short> portsKnownToTopo = ti.getPorts(sid); + + if (portsKnownToTopo != null) { + for(short p: portsKnownToTopo) { + NodePortTuple npt = + new NodePortTuple(sid, p); + if (ti.isBroadcastDomainPort(npt) == false) { + ports.remove(p); + } + } + } + + // remove the incoming switch port + if (pinSwitch == sid) { + ports.remove(pi.getInPort()); + } + + // we have all the switch ports to which we need to broadcast. + doMultiActionPacketOut(pi.getPacketData(), sw, ports, cntx); + } + + } + + protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, + FloodlightContext cntx) { + + // get the packet-in switch. + Ethernet eth = + IFloodlightProviderService.bcStore. + get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD); + + if (eth.getEtherType() == Ethernet.TYPE_BDDP) { + doFloodBDDP(sw.getId(), pi, cntx); + } else { + // if the packet is BDDP, then send flood it on all the external + // switch ports in the same openflow domain. + checkTunnelUsage(sw, pi, cntx); + return dropFilter(sw, pi, cntx); + } + return Command.STOP; + } + + public void applyUpdates() { LDUpdate update = null; while (ldUpdates.peek() != null) { @@ -423,7 +768,7 @@ public class TopologyManager implements log.error("Error reading link discovery update.", e); } if (log.isTraceEnabled()) { - log.info("Applying update: {}", update); + log.trace("Applying update: {}", update); } if (update.getOperation() == UpdateOperation.ADD_OR_UPDATE) { boolean added = @@ -451,14 +796,43 @@ public class TopologyManager implements /** * This function computes a new topology. */ + /** + * This function computes a new topology intance. + * It ignores links connected to all broadcast domain ports + * and tunnel ports. + */ public void createNewInstance() { - TopologyInstance nt = - new TopologyInstance(switchPorts, switchPortLinks, - portBroadcastDomainLinks, tunnelLinks); + Set<NodePortTuple> blockedPorts = new HashSet<NodePortTuple>(); + + Map<NodePortTuple, Set<Link>> openflowLinks; + openflowLinks = + new HashMap<NodePortTuple, Set<Link>>(switchPortLinks); + + // Remove all tunnel links. + for(NodePortTuple npt: tunnelLinks.keySet()) { + if (openflowLinks.get(npt) != null) + openflowLinks.remove(npt); + } + + // Remove all broadcast domain links. + for(NodePortTuple npt: portBroadcastDomainLinks.keySet()) { + if (openflowLinks.get(npt) != null) + openflowLinks.remove(npt); + } + + TopologyInstance nt = new TopologyInstance(switchPorts, + blockedPorts, + openflowLinks, + portBroadcastDomainLinks.keySet(), + tunnelLinks.keySet()); nt.compute(); + // We set the instances with and without tunnels to be identical. + // If needed, we may compute them differently. currentInstance = nt; + currentInstanceWithoutTunnels = nt; } + public void informListeners() { for(int i=0; i<topologyAware.size(); ++i) { ITopologyListener listener = topologyAware.get(i); @@ -622,8 +996,19 @@ public class TopologyManager implements return portBroadcastDomainLinks; } + public TopologyInstance getCurrentInstance(boolean tunnelEnabled) { + if (tunnelEnabled) + return currentInstance; + else return this.currentInstanceWithoutTunnels; + } + public TopologyInstance getCurrentInstance() { - return currentInstance; + return this.getCurrentInstance(true); + } + + @Override + public boolean isTunnelEnabled(long srcMac, long dstMac) { + return false; } } diff --git a/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainResource.java b/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainResource.java index dc7dd46ebaeeacd88608ad9b93528717ffd6ed77..b2196c66e85f56d490e6b3965e2b45248aad4de9 100644 --- a/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainResource.java +++ b/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainResource.java @@ -15,6 +15,6 @@ public class BroadcastDomainResource extends ServerResource { (ITopologyService)getContext().getAttributes(). get(ITopologyService.class.getCanonicalName()); - return topology.getBroadcastDomainLinks(); + return topology.getBroadcastDomainPorts(); } } diff --git a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java b/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java index fd5e6e1a61474f589a6b1748d7af5b88200f6165..8edf5bd20a1efa3be4699469a3fc7906e2e30810 100644 --- a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java +++ b/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java @@ -46,7 +46,7 @@ public class SwitchClustersResource extends ServerResource { Map<String, List<String>> switchClusterMap = new HashMap<String, List<String>>(); for (Entry<Long, IOFSwitch> entry : floodlightProvider.getSwitches().entrySet()) { - Long clusterDpid = topology.getSwitchClusterId(entry.getValue().getId()); + Long clusterDpid = topology.getL2DomainId(entry.getValue().getId()); List<String> switchesInCluster = switchClusterMap.get(HexString.toHexString(clusterDpid)); if (switchesInCluster != null) { switchesInCluster.add(HexString.toHexString(entry.getKey())); diff --git a/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java b/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java index ac7c0e367681910573f22f1c350c30bca679b038..71c3f120912844fa636227e2c1853a5bf69ce58f 100644 --- a/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java +++ b/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java @@ -15,6 +15,6 @@ public class TunnelLinksResource extends ServerResource { (ITopologyService)getContext().getAttributes(). get(ITopologyService.class.getCanonicalName()); - return topology.getTunnelLinks(); + return topology.getTunnelPorts(); } } diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java index 7db7c6659843b6117297325f8f3597b15f4e11b8..09e46699b3d05fa556126367e15783b10bec818e 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java @@ -273,13 +273,13 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.startUp(null); ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.getSwitchClusterId(anyLong())). + expect(mockTopology.getL2DomainId(anyLong())). andReturn(1L).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); - expect(mockTopology.isInternal(anyLong(), - anyShort())).andReturn(false).anyTimes(); + expect(mockTopology.isAttachmentPointPort(anyLong(), + anyShort())).andReturn(true).anyTimes(); deviceManager.topology = mockTopology; Entity entity1 = new Entity(1L, null, null, 1L, 1, new Date()); @@ -405,21 +405,21 @@ public class DeviceManagerImplTest extends FloodlightTestCase { deviceManager.addListener(mockListener); ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.getSwitchClusterId(1L)). + expect(mockTopology.getL2DomainId(1L)). andReturn(1L).anyTimes(); - expect(mockTopology.getSwitchClusterId(5L)). + expect(mockTopology.getL2DomainId(5L)). andReturn(1L).anyTimes(); - expect(mockTopology.getSwitchClusterId(10L)). + expect(mockTopology.getL2DomainId(10L)). andReturn(10L).anyTimes(); - expect(mockTopology.getSwitchClusterId(50L)). + expect(mockTopology.getL2DomainId(50L)). andReturn(10L).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); - expect(mockTopology.isInternal(anyLong(), - anyShort())).andReturn(false).anyTimes(); + expect(mockTopology.isAttachmentPointPort(anyLong(), + anyShort())).andReturn(true).anyTimes(); replay(mockTopology); @@ -493,10 +493,10 @@ public class DeviceManagerImplTest extends FloodlightTestCase { @Test public void testBDAttachmentPointLearning() throws Exception { ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.getSwitchClusterId(anyLong())). + expect(mockTopology.getL2DomainId(anyLong())). andReturn(1L).anyTimes(); - expect(mockTopology.isInternal(anyLong(), anyShort())). - andReturn(false).anyTimes(); + expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). + andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(1L, (short)1)). andReturn(false).anyTimes(); expect(mockTopology.isBroadcastDomainPort(1L, (short)2)). @@ -505,6 +505,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { 1L, (short)2)).andReturn(true).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(1L, (short)2, 1L, (short)1)).andReturn(true).anyTimes(); + expect(mockTopology.isConsistent(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); replay(mockTopology); @@ -548,8 +549,8 @@ public class DeviceManagerImplTest extends FloodlightTestCase { // Mock up our expected behavior ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.isInternal(anyLong(), - anyShort())).andReturn(false).anyTimes(); + expect(mockTopology.isAttachmentPointPort(anyLong(), + anyShort())).andReturn(true).anyTimes(); deviceManager.topology = mockTopology; Date currentDate = new Date(); @@ -608,10 +609,10 @@ public class DeviceManagerImplTest extends FloodlightTestCase { DefaultEntityClassifier.entityClasses); reset(mockTopology); - expect(mockTopology.isInternal(anyLong(), - anyShort())).andReturn(false).anyTimes(); - expect(mockTopology.getSwitchClusterId(1L)).andReturn(1L).anyTimes(); - expect(mockTopology.getSwitchClusterId(5L)).andReturn(1L).anyTimes(); + expect(mockTopology.isAttachmentPointPort(anyLong(), + anyShort())).andReturn(true).anyTimes(); + expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes(); + expect(mockTopology.getL2DomainId(5L)).andReturn(1L).anyTimes(); // Start recording the replay on the mocks replay(mockTopology); @@ -639,13 +640,13 @@ public class DeviceManagerImplTest extends FloodlightTestCase { mockListener.deviceMoved(isA(IDevice.class)); ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.isInternal(anyLong(), - anyShort())).andReturn(false).anyTimes(); + expect(mockTopology.isAttachmentPointPort(anyLong(), + anyShort())).andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); - expect(mockTopology.getSwitchClusterId(1L)).andReturn(1L).anyTimes(); - expect(mockTopology.getSwitchClusterId(5L)).andReturn(5L).anyTimes(); + expect(mockTopology.getL2DomainId(1L)).andReturn(1L).anyTimes(); + expect(mockTopology.getL2DomainId(5L)).andReturn(5L).anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; @@ -718,14 +719,14 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Calendar c = Calendar.getInstance(); ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.isInternal(anyLong(), - anyShort())).andReturn(false).anyTimes(); + expect(mockTopology.isAttachmentPointPort(anyLong(), + anyShort())).andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); - expect(mockTopology.getSwitchClusterId(anyLong())). + expect(mockTopology.getL2DomainId(anyLong())). andReturn(1L).anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; @@ -812,16 +813,16 @@ public class DeviceManagerImplTest extends FloodlightTestCase { Calendar c = Calendar.getInstance(); ITopologyService mockTopology = createMock(ITopologyService.class); - expect(mockTopology.isInternal(anyLong(), - anyShort())).andReturn(false).anyTimes(); + expect(mockTopology.isAttachmentPointPort(anyLong(), + anyShort())).andReturn(true).anyTimes(); expect(mockTopology.isBroadcastDomainPort(anyLong(), anyShort())). andReturn(false).anyTimes(); expect(mockTopology.isInSameBroadcastDomain(anyLong(), anyShort(), anyLong(), anyShort())).andReturn(false).anyTimes(); - expect(mockTopology.getSwitchClusterId(1L)). + expect(mockTopology.getL2DomainId(1L)). andReturn(1L).anyTimes(); - expect(mockTopology.getSwitchClusterId(5L)). + expect(mockTopology.getL2DomainId(5L)). andReturn(5L).anyTimes(); replay(mockTopology); deviceManager.topology = mockTopology; diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java index dd4cf8d3168ef584208cc8ff7635a9ec448219ca..b07ee2b2bc266963465b59e51cada55692f4b6db 100644 --- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java +++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java @@ -119,11 +119,11 @@ public class ForwardingTest extends FloodlightTestCase { // Mock switches sw1 = EasyMock.createNiceMock(IOFSwitch.class); expect(sw1.getId()).andReturn(1L).anyTimes(); - expect(topology.getSwitchClusterId(1L)).andReturn(1L).anyTimes(); + expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); sw2 = EasyMock.createNiceMock(IOFSwitch.class); expect(sw2.getId()).andReturn(2L).anyTimes(); - expect(topology.getSwitchClusterId(2L)).andReturn(1L).anyTimes(); + expect(topology.getL2DomainId(2L)).andReturn(1L).anyTimes(); //fastWilcards mocked as this constant int fastWildcards = diff --git a/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java b/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java index be2d226749fe08529846b5569798a351541b5bbc..e72179d037c0ce24cf9a25383c566595b22c6c08 100644 --- a/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java +++ b/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java @@ -46,6 +46,10 @@ public class TopologyInstanceTest { } 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 @@ -53,7 +57,8 @@ public class TopologyInstanceTest { for (int i = 0; i < clusters.length; i++) Arrays.sort(clusters[i]); - TopologyInstance ti = topologyManager.getCurrentInstance(); + TopologyInstance ti = + topologyManager.getCurrentInstance(tunnelsEnabled); Set<Long> switches = ti.getSwitches(); for (long sw: switches) { @@ -68,7 +73,7 @@ public class TopologyInstanceTest { } } if (expectedCluster != null) { - Set<Long> cluster = ti.getSwitchesInCluster(sw); + Set<Long> cluster = ti.getSwitchesInOpenflowDomain(sw); assertEquals(expectedCluster.length, cluster.size()); for (long sw2: cluster) { assertTrue(Arrays.binarySearch(expectedCluster, (int)sw2) >= 0); @@ -79,7 +84,14 @@ public class TopologyInstanceTest { } } - protected void verifyExpectedBroadcastPortsInClusters(int [][][] ebp) { + 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) { @@ -89,7 +101,7 @@ public class TopologyInstanceTest { npt = new NodePortTuple((long)nptList[j][0], (short)nptList[j][1]); expected.add(npt); } - TopologyInstance ti = topologyManager.getCurrentInstance(); + TopologyInstance ti = topologyManager.getCurrentInstance(tunnelsEnabled); Set<NodePortTuple> computed = ti.getBroadcastNodePortsInCluster(npt.nodeId); if (computed != null) assertTrue(computed.equals(expected)); @@ -278,6 +290,120 @@ public class TopologyInstanceTest { verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); } + @Test + public void testTunnelLinkDeletion() 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, TUNNEL_LINK}, + {3, 1, 1, 2, TUNNEL_LINK}, + {2, 2, 3, 2, TUNNEL_LINK}, + {3, 2, 2, 2, TUNNEL_LINK}, + + {4, 2, 6, 2, DIRECT_LINK}, + {6, 2, 4, 2, DIRECT_LINK}, + {4, 3, 5, 1, TUNNEL_LINK}, + {5, 1, 4, 3, TUNNEL_LINK}, + {5, 2, 6, 1, TUNNEL_LINK}, + {6, 1, 5, 2, TUNNEL_LINK}, + + }; + + int [][] expectedClusters = { + {1, 2}, + {4, 6}, + }; + int [][][] expectedBroadcastPorts = { + {{1,1}, {2,1}}, + {{4,2}, {6,2}} + }; + + createTopologyFromLinks(linkArray); + topologyManager.createNewInstance(); + verifyClusters(expectedClusters, false); + verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts, false); + } + + // +-------+ +-------+ + // | | 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, TUNNEL_LINK}, + {4, 1, 3, 3, TUNNEL_LINK}, + + }; + int [][] expectedClusters = { + {1, 2}, + {4, 6}, + {3}, + {5}, + }; + int [][][] expectedBroadcastPorts = { + {{1,1}, {2,1}}, + {{4,2}, {6,2}} + }; + + createTopologyFromLinks(linkArray); + topologyManager.createNewInstance(); + verifyClusters(expectedClusters, false); + verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts, false); + } + } + @Test public void testLoopDetectionWithIslands() throws Exception { @@ -330,8 +456,8 @@ public class TopologyInstanceTest { {4, 5, 6} }; int [][][] expectedBroadcastPorts = { - {{1,1}, {2,1}, {1,2}, {3,1}}, - {{4,3}, {5,1}, {4,2}, {6,2}}, + {{1,2}, {3,1}, {2,2}, {3,2}}, + {{4,3}, {5,1}, {5,2}, {6,1}}, }; createTopologyFromLinks(linkArray); @@ -375,15 +501,17 @@ public class TopologyInstanceTest { }; int [][] expectedClusters = { - {1, 2, 3, 4, 5, 6} + {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}}, + {{1,2}, {3,1}, {2,2}, {3,2}}, + {{4,3}, {5,1}, {5,2}, {6,1}}, }; createTopologyFromLinks(linkArray); topologyManager.createNewInstance(); - verifyClusters(expectedClusters); + verifyClusters(expectedClusters, false); verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts); } } diff --git a/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java b/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java index bcc886a42f1670371032d6e9e79e521ea838c4ec..113cecbaea0492d36831d1221ad9c1e904c59891 100644 --- a/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java +++ b/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java @@ -40,7 +40,7 @@ public class TopologyManagerTest extends FloodlightTestCase { assertTrue(tm.getSwitchPorts().get((long)2).size()==1); assertTrue(tm.getSwitchPortLinks().size()==2); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); - assertTrue(tm.getTunnelLinks().size()==0); + assertTrue(tm.getTunnelPorts().size()==0); tm.addOrUpdateLink((long)1, (short)2, (long)2, (short)2, ILinkDiscovery.LinkType.MULTIHOP_LINK); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. @@ -48,7 +48,7 @@ public class TopologyManagerTest extends FloodlightTestCase { assertTrue(tm.getSwitchPorts().get((long)2).size()==2); assertTrue(tm.getSwitchPortLinks().size()==4); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - assertTrue(tm.getTunnelLinks().size()==0); + assertTrue(tm.getTunnelPorts().size()==0); tm.addOrUpdateLink((long)1, (short)3, (long)2, (short)3, ILinkDiscovery.LinkType.TUNNEL); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. @@ -56,7 +56,7 @@ public class TopologyManagerTest extends FloodlightTestCase { assertTrue(tm.getSwitchPorts().get((long)2).size()==3); assertTrue(tm.getSwitchPortLinks().size()==6); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - assertTrue(tm.getTunnelLinks().size()==2); + assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)1, (short)2, (long)2, (short)2); log.info("# of switchports. {}", tm.getSwitchPorts().get((long)1).size()); @@ -65,7 +65,7 @@ public class TopologyManagerTest extends FloodlightTestCase { assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. assertTrue(tm.getSwitchPortLinks().size()==4); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); - assertTrue(tm.getTunnelLinks().size()==2); + assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)1, (short)1, (long)2, (short)1); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. @@ -73,13 +73,13 @@ public class TopologyManagerTest extends FloodlightTestCase { assertTrue(tm.getSwitchPorts().get((long)2).size()==1); assertTrue(tm.getSwitchPortLinks().size()==2); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); - assertTrue(tm.getTunnelLinks().size()==2); + assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)1, (short)3, (long)2, (short)3); assertTrue(tm.getSwitchPorts().size() == 0); assertTrue(tm.getSwitchPortLinks().size()==0); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); - assertTrue(tm.getTunnelLinks().size()==0); + assertTrue(tm.getTunnelPorts().size()==0); } @Test @@ -93,7 +93,7 @@ public class TopologyManagerTest extends FloodlightTestCase { assertTrue(tm.getSwitchPorts().get((long)3).size()==2); assertTrue(tm.getSwitchPortLinks().size()==6); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - assertTrue(tm.getTunnelLinks().size()==2); + assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)1, (short)1, (long)2, (short)1); assertTrue(tm.getSwitchPorts().size() == 3); // for two nodes. @@ -102,7 +102,7 @@ public class TopologyManagerTest extends FloodlightTestCase { assertTrue(tm.getSwitchPorts().get((long)3).size()==2); assertTrue(tm.getSwitchPortLinks().size()==4); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - assertTrue(tm.getTunnelLinks().size()==2); + assertTrue(tm.getTunnelPorts().size()==2); // nonexistent link // no null pointer exceptions. tm.removeLink((long)3, (short)1, (long)2, (short)2); @@ -112,7 +112,7 @@ public class TopologyManagerTest extends FloodlightTestCase { assertTrue(tm.getSwitchPorts().get((long)3).size()==2); assertTrue(tm.getSwitchPortLinks().size()==4); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - assertTrue(tm.getTunnelLinks().size()==2); + assertTrue(tm.getTunnelPorts().size()==2); tm.removeLink((long)3, (short)2, (long)1, (short)2); assertTrue(tm.getSwitchPorts().size() == 2); // for two nodes. @@ -121,15 +121,15 @@ public class TopologyManagerTest extends FloodlightTestCase { assertTrue(tm.getSwitchPorts().get((long)3).size()==1); assertTrue(tm.getSwitchPortLinks().size()==2); assertTrue(tm.getPortBroadcastDomainLinks().size()==2); - assertTrue(tm.getTunnelLinks().size()==0); + assertTrue(tm.getTunnelPorts().size()==0); tm.removeLink((long)2, (short)2, (long)3, (short)1); assertTrue(tm.getSwitchPorts().size() == 0); // for two nodes. assertTrue(tm.getSwitchPortLinks().size()==0); assertTrue(tm.getPortBroadcastDomainLinks().size()==0); - assertTrue(tm.getTunnelLinks().size()==0); + assertTrue(tm.getTunnelPorts().size()==0); } - + @Test public void testHARoleChange() throws Exception { testBasic2();