diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java index 67345322dfeb7f1e4d3707cb007562ea4d36a47c..74fbcdd136456e64647afe6a61b52610bde789eb 100644 --- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java +++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java @@ -110,7 +110,7 @@ public interface IOFSwitch { * been received. * @return Unmodifiable list of ports */ - public List<OFPhysicalPort> getEnabledPorts(); + public List<Short> getEnabledPorts(); /** * Retrieve the port object by the port number. The port object diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java index 3f42059d91da2af5a2140b72481b2d2d3eb2ae24..4a6fd51a72893a20be353990cea914fbb6358b49 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java +++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java @@ -257,11 +257,11 @@ public class OFSwitchImpl implements IOFSwitch { } @JsonIgnore - public synchronized List<OFPhysicalPort> getEnabledPorts() { - List<OFPhysicalPort> result = new ArrayList<OFPhysicalPort>(); + public synchronized List<Short> getEnabledPorts() { + List<Short> result = new ArrayList<Short>(); for (OFPhysicalPort port : ports.values()) { if (portEnabled(port)) { - result.add(port); + result.add(port.getPortNumber()); } } return result; diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java index c4421acfcf4971431da1efa0f5686df4871cf54f..894f9f60440d4d32ff30cfb43c900096ac155148 100644 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java +++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java @@ -65,4 +65,9 @@ public interface ILinkDiscoveryService extends IFloodlightService { * Removes a switch port from suppress lldp set */ public void RemoveFromSuppressLLDPs(long sw, short port); + + /** + * Get the set of quarantined ports on a switch + */ + public Set<Short> getQuarantinedPorts(long sw); } diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java index ce205b17fdbf04b5648b0f4c8ccd25077c907654..c35be96b2824ab73780ab51772a83f19da193125 100644 --- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java +++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java @@ -130,7 +130,6 @@ IFloodlightModule, IInfoProvider, IHAListener { private static final String LINK_DST_PORT_STATE = "dst_port_state"; private static final String LINK_VALID_TIME = "valid_time"; private static final String LINK_TYPE = "link_type"; - private static final String SWITCH_CONFIG_TABLE_NAME = "controller_switchconfig"; private static final String SWITCH_CONFIG_CORE_SWITCH = "core_switch"; @@ -139,6 +138,7 @@ IFloodlightModule, IInfoProvider, IHAListener { protected IThreadPoolService threadPool; + // LLDP and BDDP fields private static final byte[] LLDP_STANDARD_DST_MAC_STRING = HexString.fromHexString("01:80:c2:00:00:0e"); private static final long LINK_LOCAL_MASK = 0xfffffffffff0L; @@ -167,12 +167,12 @@ IFloodlightModule, IInfoProvider, IHAListener { setLength((short)TLV_DIRECTION_LENGTH). setValue(TLV_DIRECTION_VALUE_REVERSE); + // Link discovery task details. protected SingletonTask discoveryTask; protected final int DISCOVERY_TASK_INTERVAL = 1; protected final int LINK_TIMEOUT = 35; // timeout as part of LLDP process. protected final int LLDP_TO_ALL_INTERVAL = 15 ; //15 seconds. protected long lldpClock = 0; - // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL. // If we want to identify link failures faster, we could decrease this // value to a small number, say 1 or 2 sec. @@ -196,7 +196,6 @@ IFloodlightModule, IInfoProvider, IHAListener { * Map from a id:port to the set of links containing it as an endpoint */ protected Map<NodePortTuple, Set<Link>> portLinks; - protected Set<NodePortTuple> suppressLLDPs; /** * Set of link tuples over which multicast LLDPs are received @@ -212,6 +211,30 @@ IFloodlightModule, IInfoProvider, IHAListener { protected BlockingQueue<LDUpdate> updates; protected Thread updatesThread; + /** + * List of ports through which LLDP/BDDPs are not sent. + */ + protected Set<NodePortTuple> suppressLLDPs; + + /** A list of ports that are quarantined for discovering links through + * them. Data traffic from these ports are not allowed until the ports + * are released from quarantine. + */ + protected LinkedBlockingQueue<NodePortTuple> quarantineQueue; + protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue; + /** + * Quarantine task + */ + protected SingletonTask bddpTask; + protected final int BDDP_TASK_INTERVAL = 100; // 100 ms. + protected final int BDDP_TASK_SIZE = 5; // # of ports per iteration + + /** + * Map of broadcast domain ports and the last time a BDDP was either + * sent or received on that port. + */ + protected Map<NodePortTuple, Long> broadcastDomainPortTimeMap; + /** * Get the LLDP sending period in seconds. * @return LLDP sending period in seconds. @@ -262,6 +285,10 @@ IFloodlightModule, IInfoProvider, IHAListener { return shuttingDown; } + public boolean isFastPort(long sw, short port) { + return false; + } + public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) { if (info.getUnicastValidTime() != null) { return ILinkDiscovery.LinkType.DIRECT_LINK; @@ -294,7 +321,6 @@ IFloodlightModule, IInfoProvider, IHAListener { } } while (updates.peek() != null); } - private boolean isLLDPSuppressed(long sw, short portNumber) { return this.suppressLLDPs.contains(new NodePortTuple(sw, portNumber)); } @@ -313,8 +339,133 @@ IFloodlightModule, IInfoProvider, IHAListener { } } + + /** + * Quarantine Ports. + */ + protected class QuarantineWorker implements Runnable { + @Override + public void run() { + try { + processBDDPLists(); + } + catch (Exception e) { + log.error("Error in quarantine worker thread", e); + } finally { + bddpTask.reschedule(BDDP_TASK_INTERVAL, + TimeUnit.MILLISECONDS); + } + } + } + + /** + * Add a switch port to the quarantine queue. Schedule the + * quarantine task if the quarantine queue was empty before adding + * this switch port. + * @param npt + */ + protected void addToQuarantineQueue(NodePortTuple npt) { + if (quarantineQueue.contains(npt) == false) + quarantineQueue.add(npt); + } + + /** + * Remove a switch port from the quarantine queue. + */ + protected void removeFromQuarantineQueue(NodePortTuple npt) { + // Remove all occurrences of the node port tuple from the list. + while (quarantineQueue.remove(npt)); + } + + /** + * Add a switch port to maintenance queue. + * @param npt + */ + protected void addToMaintenanceQueue(NodePortTuple npt) { + // TODO We are not checking if the switch port tuple is already + // in the maintenance list or not. This will be an issue for + // really large number of switch ports in the network. + maintenanceQueue.add(npt); + } + + /** + * Remove a switch port from maintenance queue. + * @param npt + */ + protected void removeFromMaintenanceQueue(NodePortTuple npt) { + // Remove all occurrences of the node port tuple from the queue. + while (maintenanceQueue.remove(npt)); + } + + /** + * This method processes the quarantine list in bursts. The task is + * at most once per BDDP_TASK_INTERVAL. + * One each call, BDDP_TASK_SIZE number of switch ports are processed. + * Once the BDDP packets are sent out through the switch ports, the ports + * are removed from the quarantine list. + */ + + protected void processBDDPLists() { + int count = 0; + Set<NodePortTuple> nptList = new HashSet<NodePortTuple>(); + + while(count < BDDP_TASK_SIZE && quarantineQueue.peek() !=null) { + NodePortTuple npt; + npt = quarantineQueue.remove(); + sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false); + nptList.add(npt); + count++; + } + + count = 0; + while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) { + NodePortTuple npt; + npt = maintenanceQueue.remove(); + sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false); + nptList.add(npt); + count++; + } + + for(NodePortTuple npt:nptList) { + generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId()); + } + } + + public Set<Short> getQuarantinedPorts(long sw) { + Set<Short> qPorts = new HashSet<Short>(); + + Iterator<NodePortTuple> iter = quarantineQueue.iterator(); + while (iter.hasNext()) { + NodePortTuple npt = iter.next(); + if (npt.getNodeId() == sw) { + qPorts.add(npt.getPortId()); + } + } + return qPorts; + } + + private void generateSwitchPortStatusUpdate(long sw, short port) { + UpdateOperation operation; + + IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); + if (iofSwitch == null) return; + + OFPhysicalPort ofp = iofSwitch.getPort(port); + if (ofp == null) return; + + int srcPortState = ofp.getState(); + boolean portUp = ((srcPortState & + OFPortState.OFPPS_STP_MASK.getValue()) != + OFPortState.OFPPS_STP_BLOCK.getValue()); + + if (portUp) operation = UpdateOperation.PORT_UP; + else operation = UpdateOperation.PORT_DOWN; + + updates.add(new LDUpdate(sw, port, operation)); + } + /** - * Send LLDP and BDDP on known + * Send LLDP on known ports */ protected void discoverOnKnownLinkPorts() { // Copy the port set. @@ -332,10 +483,7 @@ IFloodlightModule, IInfoProvider, IHAListener { } protected void discover(long sw, short port) { - // Send standard lldp first sendDiscoveryMessage(sw, port, true, false); - // Then send the bddp following that. - sendDiscoveryMessage(sw, port, false, false); } /** @@ -398,7 +546,6 @@ IFloodlightModule, IInfoProvider, IHAListener { // through provider and TPMR bridges (see IEEE 802.1AB-2009 and 802.1Q-2011), // in particular the Linux bridge which behaves mostly like a provider bridge - ethernet.setPayload(lldp); byte[] chassisId = new byte[] {4, 0, 0, 0, 0, 0, 0}; // filled in later byte[] portId = new byte[] {2, 0, 0}; // filled in later @@ -485,20 +632,18 @@ IFloodlightModule, IInfoProvider, IHAListener { IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); if (iofSwitch == null) continue; if (iofSwitch.getEnabledPorts() != null) { - for (OFPhysicalPort p : iofSwitch.getEnabledPorts()) { + for (short p: iofSwitch.getEnabledPorts()) { // sends only forward LLDPs and BDDPs - sendDiscoveryMessage(sw, p.getPortNumber(), true, false); - } - } - } - - for (long sw: switches) { - IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); - if (iofSwitch == null) continue; - if (iofSwitch.getEnabledPorts() != null) { - for (OFPhysicalPort p : iofSwitch.getEnabledPorts()) { - // sends only forward LLDPs and BDDPs - sendDiscoveryMessage(sw, p.getPortNumber(), false, false); + OFPhysicalPort ofp = iofSwitch.getPort(p); + if (ofp==null) continue; + sendDiscoveryMessage(sw, ofp.getPortNumber(), true, false); + + NodePortTuple npt = new NodePortTuple(sw, p); + if (portLinks.containsKey(npt) == false || + portBroadcastDomainLinks.containsKey(npt)) { + // add to maintenance list. + addToMaintenanceQueue(npt); + } } } } @@ -539,8 +684,6 @@ IFloodlightModule, IInfoProvider, IHAListener { this.controllerTLV = new LLDPTLV().setType((byte) 0x0c).setLength((short) controllerTLVValue.length).setValue(controllerTLVValue); } - - @Override public String getName() { return "linkdiscovery"; @@ -700,6 +843,28 @@ IFloodlightModule, IInfoProvider, IHAListener { } } + // If the received packet is a BDDP packet, then create a reverse BDDP + // link as well. + if (!isStandard) { + Link reverseLink = new Link(lt.getDst(), lt.getDstPort(), + lt.getSrc(), lt.getSrcPort()); + + // srcPortState and dstPort state are reversed. + LinkInfo reverseInfo = + new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime, + dstPortState, srcPortState); + + addOrUpdateLink(reverseLink, reverseInfo); + } + + // Remove the node ports from the quarantine and maintenance queues. + NodePortTuple nptSrc = new NodePortTuple(lt.getSrc(), lt.getSrcPort()); + NodePortTuple nptDst = new NodePortTuple(lt.getDst(), lt.getDstPort()); + removeFromQuarantineQueue(nptSrc); + removeFromMaintenanceQueue(nptSrc); + removeFromQuarantineQueue(nptDst); + removeFromMaintenanceQueue(nptDst); + // Consume this message return Command.STOP; } @@ -724,6 +889,11 @@ IFloodlightModule, IInfoProvider, IHAListener { return Command.STOP; } } + + // If packet-in is from a quarantine port, stop processing. + NodePortTuple npt = new NodePortTuple(sw, pi.getInPort()); + if (quarantineQueue.contains(npt)) return Command.STOP; + return Command.CONTINUE; } @@ -741,6 +911,8 @@ IFloodlightModule, IInfoProvider, IHAListener { return UpdateOperation.LINK_REMOVED; } + + protected UpdateOperation getUpdateOperation(int srcPortState) { boolean portUp = ((srcPortState & OFPortState.OFPPS_STP_MASK.getValue()) != @@ -925,10 +1097,11 @@ IFloodlightModule, IInfoProvider, IHAListener { this.portLinks.remove(dstNpt); } - this.links.remove(lt); + LinkInfo info = this.links.remove(lt); updates.add(new LDUpdate(lt.getSrc(), lt.getSrcPort(), lt.getDst(), lt.getDstPort(), - null, UpdateOperation.LINK_REMOVED)); + getLinkType(lt, info), + UpdateOperation.LINK_REMOVED)); // Update Event History evHistTopoLink(lt.getSrc(), @@ -1070,15 +1243,13 @@ IFloodlightModule, IInfoProvider, IHAListener { */ @Override public void addedSwitch(IOFSwitch sw) { - // It's probably overkill to send LLDP from all switches, but we don't - // know which switches might be connected to the new switch. - // Need to optimize when supporting a large number of switches. - NodePortTuple npt; + NodePortTuple npt; if (sw.getEnabledPorts() != null) { - for (OFPhysicalPort p : sw.getEnabledPorts()) { - npt = new NodePortTuple(sw.getId(), p.getPortNumber()); + for (Short p : sw.getEnabledPorts()) { + npt = new NodePortTuple(sw.getId(), p); discover(npt); + addToQuarantineQueue(npt); } } // Update event history @@ -1543,6 +1714,9 @@ IFloodlightModule, IInfoProvider, IHAListener { Collections.synchronizedSet(new HashSet<NodePortTuple>()); this.portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>(); this.switchLinks = new HashMap<Long, Set<Link>>(); + this.quarantineQueue = new LinkedBlockingQueue<NodePortTuple>(); + this.maintenanceQueue = new LinkedBlockingQueue<NodePortTuple>(); + this.evHistTopologySwitch = new EventHistory<EventHistoryTopologySwitch>("Topology: Switch"); this.evHistTopologyLink = @@ -1599,6 +1773,20 @@ IFloodlightModule, IInfoProvider, IHAListener { } }); + // null role implies HA mode is not enabled. + Role role = floodlightProvider.getRole(); + if (role == null || role == Role.MASTER) { + log.trace("Setup: Rescheduling discovery task. role = {}", role); + discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS); + } else { + log.trace("Setup: Not scheduling LLDP as role = {}.", role); + } + + // Setup the BDDP task. It is invoked whenever switch port tuples + // are added to the quarantine list. + bddpTask = new SingletonTask(ses, new QuarantineWorker()); + bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS); + updatesThread = new Thread(new Runnable () { @Override public void run() { @@ -1612,14 +1800,8 @@ IFloodlightModule, IInfoProvider, IHAListener { }}, "Topology Updates"); updatesThread.start(); - // null role implies HA mode is not enabled. - Role role = floodlightProvider.getRole(); - if (role == null || role == Role.MASTER) { - log.trace("Setup: Rescheduling discovery task. role = {}", role); - discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS); - } else { - log.trace("Setup: Not scheduling LLDP as role = {}.", role); - } + + // Register for the OpenFlow messages we want to receive floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this); diff --git a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java index 82a67fec4062512367ddeca22e1b5a7242db62a1..cc62e82ac86f78eb63c20da7b70833d5786248e7 100644 --- a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java +++ b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java @@ -91,8 +91,8 @@ public interface ITopologyService extends IFloodlightService { * @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); + public Set<Short> getPortsWithLinks(long sw); + public Set<Short> getPortsWithLinks(long sw, boolean tunnelEnabled); /** Get broadcast ports on a target switch for a given attachmentpoint * point port. @@ -101,7 +101,7 @@ public interface ITopologyService extends IFloodlightService { public Set<Short> getBroadcastPorts(long targetSw, long src, short srcPort, boolean tunnelEnabled); - + /** * */ @@ -166,15 +166,15 @@ public interface ITopologyService extends IFloodlightService { short srcPort, boolean tunnelEnabled); - + /** * Gets the set of ports that belong to a broadcast domain. * @return The set of ports that belong to a broadcast domain. */ public Set<NodePortTuple> getBroadcastDomainPorts(); public Set<NodePortTuple> getTunnelPorts(); - - + + /** * Returns a set of blocked ports. The set of blocked * ports is the union of all the blocked ports across all @@ -182,7 +182,7 @@ public interface ITopologyService extends IFloodlightService { * @return */ public Set<NodePortTuple> getBlockedPorts(); - + /** * ITopologyListener provides topologyChanged notification, * but not *what* the changes were. @@ -190,4 +190,9 @@ public interface ITopologyService extends IFloodlightService { * @return */ public List<LDUpdate> getLastLinkUpdates(); + + /** + * Switch methods + */ + public Set<Short> getPorts(long sw); } diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java index 298c49861236391997dd8adcf72f12d85d89af1e..1d24cf3e04c1038465cf2e01c8c9db65c9ce346c 100644 --- a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java +++ b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java @@ -741,7 +741,7 @@ public class TopologyInstance { return switches; } - public Set<Short> getPorts(long sw) { + public Set<Short> getPortsWithLinks(long sw) { return switchPorts.get(sw); } diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java index 71751f9950738f9a58460927c8175322ab08cb9a..27cae7298be228e3badcdbf856509afb89ca84d6 100644 --- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java +++ b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java @@ -62,15 +62,20 @@ public class TopologyManager implements "com.bigswitch.floodlight.topologymanager.tunnelEnabled"; /** - * Set of ports for each switch + * Set of ports for each switch */ - protected Map<Long, Set<Short>> switchPorts; + protected Map<Long, Set<Short>> switchPorts; /** * Set of links organized by node port tuple */ protected Map<NodePortTuple, Set<Link>> switchPortLinks; + /** + * Set of direct links + */ + protected Map<NodePortTuple, Set<Link>> directLinks; + /** * set of links that are broadcast domain links. */ @@ -80,6 +85,7 @@ public class TopologyManager implements * set of tunnel links */ protected Map<NodePortTuple, Set<Link>> tunnelLinks; + protected ILinkDiscoveryService linkDiscovery; protected IThreadPoolService threadPool; protected IFloodlightProviderService floodlightProvider; @@ -97,19 +103,17 @@ public class TopologyManager implements protected SingletonTask newInstanceTask; private Date lastUpdateTime; + protected boolean recomputeTopologyFlag; /** * Thread for recomputing topology. The thread is always running, * however the function applyUpdates() has a blocking call. */ - protected class NewInstanceWorker implements Runnable { + protected class UpdateTopologyWorker implements Runnable { @Override public void run() { try { - applyUpdates(); - createNewInstance(); - lastUpdateTime = new Date(); - informListeners(); + updateTopology(); } catch (Exception e) { log.error("Error in topology instance task thread", e); @@ -117,6 +121,15 @@ public class TopologyManager implements } } + public boolean updateTopology() { + recomputeTopologyFlag = false; + applyUpdates(); + createNewInstance(); + lastUpdateTime = new Date(); + informListeners(); + return recomputeTopologyFlag; + } + // ********************** // ILinkDiscoveryListener // ********************** @@ -241,15 +254,15 @@ public class TopologyManager implements //////////////////////////////////////////////////////////////////////// /** Get all the ports connected to the switch */ @Override - public Set<Short> getPorts(long sw) { - return getPorts(sw, true); + public Set<Short> getPortsWithLinks(long sw) { + return getPortsWithLinks(sw, true); } /** Get all the ports connected to the switch */ @Override - public Set<Short> getPorts(long sw, boolean tunnelEnabled) { + public Set<Short> getPortsWithLinks(long sw, boolean tunnelEnabled) { TopologyInstance ti = getCurrentInstance(tunnelEnabled); - return ti.getPorts(sw); + return ti.getPortsWithLinks(sw); } //////////////////////////////////////////////////////////////////////// @@ -613,6 +626,7 @@ public class TopologyManager implements switchPorts = new HashMap<Long,Set<Short>>(); switchPortLinks = new HashMap<NodePortTuple, Set<Link>>(); + directLinks = new HashMap<NodePortTuple, Set<Link>>(); portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>(); tunnelLinks = new HashMap<NodePortTuple, Set<Link>>(); topologyAware = new ArrayList<ITopologyListener>(); @@ -624,7 +638,7 @@ public class TopologyManager implements @Override public void startUp(FloodlightModuleContext context) { ScheduledExecutorService ses = threadPool.getScheduledExecutor(); - newInstanceTask = new SingletonTask(ses, new NewInstanceWorker()); + newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker()); linkDiscovery.addListener(this); floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); floodlightProvider.addHAListener(this); @@ -753,13 +767,13 @@ public class TopologyManager implements 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()); + if (sw.getEnabledPorts() == null) continue; + ports.addAll(sw.getEnabledPorts()); // 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); + Set<Short> portsKnownToTopo = ti.getPortsWithLinks(sid); if (portsKnownToTopo != null) { for(short p: portsKnownToTopo) { @@ -798,7 +812,6 @@ public class TopologyManager implements return Command.STOP; } - public void applyUpdates() { appliedUpdates.clear(); @@ -834,13 +847,15 @@ public class TopologyManager implements * This function computes a new topology. */ /** - * This function computes a new topology intance. + * This function computes a new topology instance. * It ignores links connected to all broadcast domain ports * and tunnel ports. */ - public void createNewInstance() { + protected void createNewInstance() { Set<NodePortTuple> blockedPorts = new HashSet<NodePortTuple>(); + if (!recomputeTopologyFlag) return; + Map<NodePortTuple, Set<Link>> openflowLinks; openflowLinks = new HashMap<NodePortTuple, Set<Link>>(switchPortLinks); @@ -920,6 +935,13 @@ public class TopologyManager implements return true; } + /** + * Add the given link to the data structure. Returns true if a link was + * added. + * @param s + * @param l + * @return + */ private boolean addLinkToStructure(Map<NodePortTuple, Set<Link>> s, Link l) { boolean result1 = false, result2 = false; @@ -928,17 +950,24 @@ public class TopologyManager implements NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort()); if (s.get(n1) == null) { - s.put(n1, new HashSet<Link>()); + s.put(n1, new HashSet<Link>()); } if (s.get(n2) == null) { - s.put(n2, new HashSet<Link>()); + s.put(n2, new HashSet<Link>()); } result1 = s.get(n1).add(l); result2 = s.get(n2).add(l); - return (result1 && result2); + return (result1 || result2); } + /** + * Delete the given link from the data strucure. Returns true if the + * link was deleted. + * @param s + * @param l + * @return + */ private boolean removeLinkFromStructure(Map<NodePortTuple, Set<Link>> s, Link l) { @@ -954,13 +983,14 @@ public class TopologyManager implements result2 = s.get(n2).remove(l); if (s.get(n2).isEmpty()) s.remove(n2); } - return result1 && result2; + return result1 || result2; } public void addOrUpdateLink(long srcId, short srcPort, long dstId, short dstPort, LinkType type) { - Link link = new Link(srcId, srcPort, dstId, dstPort); + boolean flag1 = false, flag2 = false; + Link link = new Link(srcId, srcPort, dstId, dstPort); addPortToSwitch(srcId, srcPort); addPortToSwitch(dstId, dstPort); @@ -968,19 +998,31 @@ public class TopologyManager implements if (type.equals(LinkType.MULTIHOP_LINK)) { addLinkToStructure(portBroadcastDomainLinks, link); - removeLinkFromStructure(tunnelLinks, link); + flag1 = removeLinkFromStructure(tunnelLinks, link); + flag2 = removeLinkFromStructure(directLinks, link); + recomputeTopologyFlag = flag1 || flag2; } else if (type.equals(LinkType.TUNNEL)) { addLinkToStructure(tunnelLinks, link); removeLinkFromStructure(portBroadcastDomainLinks, link); + removeLinkFromStructure(directLinks, link); + recomputeTopologyFlag = true; } else if (type.equals(LinkType.DIRECT_LINK)) { + addLinkToStructure(directLinks, link); removeLinkFromStructure(tunnelLinks, link); removeLinkFromStructure(portBroadcastDomainLinks, link); + recomputeTopologyFlag = true; } } public void removeLink(Link link) { + boolean flag1 = false, flag2 = false; + + flag1 = removeLinkFromStructure(directLinks, link); + flag2 = removeLinkFromStructure(tunnelLinks, link); + + recomputeTopologyFlag = flag1 || flag2; + removeLinkFromStructure(portBroadcastDomainLinks, link); - removeLinkFromStructure(tunnelLinks, link); removeLinkFromStructure(switchPortLinks, link); NodePortTuple srcNpt = @@ -1020,6 +1062,7 @@ public class TopologyManager implements switchPortLinks.clear(); portBroadcastDomainLinks.clear(); tunnelLinks.clear(); + directLinks.clear(); appliedUpdates.clear(); } @@ -1057,5 +1100,23 @@ public class TopologyManager implements public TopologyInstance getCurrentInstance() { return this.getCurrentInstance(true); } -} + /** + * Switch methods + */ + public Set<Short> getPorts(long sw) { + Set<Short> ports = new HashSet<Short>(); + IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw); + if (iofSwitch == null) return null; + + List<Short> ofpList = iofSwitch.getEnabledPorts(); + if (ofpList == null) return null; + + Set<Short> qPorts = linkDiscovery.getQuarantinedPorts(sw); + if (qPorts != null) + ofpList.removeAll(qPorts); + + ports.addAll(ofpList); + return ports; + } +} \ No newline at end of file diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java index a6b6d6abc82308ca139036eaab1cc2d4f458e74c..df4d8e7ca069643094a1909fabdbd8bec4113e99 100644 --- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java +++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java @@ -700,6 +700,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { EasyMock.anyLong(), EasyMock.anyShort())).andReturn(false). anyTimes(); + expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); Date currentDate = new Date(); @@ -1259,6 +1260,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); + expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); doTestDeviceQuery(); } @@ -1270,6 +1272,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); + expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); doTestDeviceQuery(); @@ -1339,6 +1342,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); + expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); doTestDeviceClassQuery(); @@ -1351,11 +1355,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase { expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); + expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); doTestDeviceClassQuery(); } - + @Test public void testFindDevice() { boolean exceptionCaught; @@ -1367,6 +1372,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase { expect(mockTopology.isAttachmentPointPort(anyLong(), anyShort())). andReturn(true).anyTimes(); + expect(mockTopology.getL2DomainId(EasyMock.anyLong())).andReturn(1L).anyTimes(); replay(mockTopology); Entity entity1 = new Entity(1L, (short)1, 1, 1L, 1, new Date()); diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java index e2f1e7d31ac18e4fa397d67b6cd33c5340845730..4f474da897c47413da975f05a8711d5bb9482e95 100644 --- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java +++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java @@ -373,6 +373,7 @@ public class ForwardingTest extends FloodlightTestCase { reset(topology); expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort())) .andReturn(true).anyTimes(); + expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); replay(topology); srcDevice =