diff --git a/src/main/java/net/floodlightcontroller/core/types/JsonObjectWrapper.java b/src/main/java/net/floodlightcontroller/core/types/JsonObjectWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e9b515551fbd24e5b95d20a0a26c8d7df9f052f
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/types/JsonObjectWrapper.java
@@ -0,0 +1,68 @@
+package net.floodlightcontroller.core.types;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import net.floodlightcontroller.core.web.serializers.JsonObjectWrapperSerializer;
+
+/**
+ * Use this class to wrap return types that will otherwise be 
+ * serialized by Jackson as arrays. The outer-most type
+ * of JSON must be an object. The end result will be:
+ * 
+ * {
+ *      "result": <Object-you-provide>
+ * }
+ * 
+ * instead of Jackson-default for your type:s
+ * 
+ * [
+ *      <Object-you-provide's data>
+ * ]
+ * 
+ * which is an illegal JSON construct.
+ * 
+ * @author rizard
+ */
+@JsonSerialize(using=JsonObjectWrapperSerializer.class)
+public class JsonObjectWrapper {
+    private Object o;
+    
+    private JsonObjectWrapper() { }
+    
+    private JsonObjectWrapper(Object o) {
+        this.o = o;
+    }
+    
+    public static JsonObjectWrapper of(Object o) {
+        return new JsonObjectWrapper(o);
+    }
+    
+    public Object getObject() {
+        return o;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((o == null) ? 0 : o.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        JsonObjectWrapper other = (JsonObjectWrapper) obj;
+        if (o == null) {
+            if (other.o != null)
+                return false;
+        } else if (!o.equals(other.o))
+            return false;
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/types/NodePortTuple.java b/src/main/java/net/floodlightcontroller/core/types/NodePortTuple.java
index 828c9bc5cb533911afd20b3a00df304fe21b7f14..c16cae9ecd02a0b862c6389c6f8fe485454d4b75 100644
--- a/src/main/java/net/floodlightcontroller/core/types/NodePortTuple.java
+++ b/src/main/java/net/floodlightcontroller/core/types/NodePortTuple.java
@@ -17,6 +17,7 @@
 package net.floodlightcontroller.core.types;
 
 import net.floodlightcontroller.core.web.serializers.DPIDSerializer;
+import net.floodlightcontroller.core.web.serializers.NodePortTupleSerializer;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@@ -31,6 +32,7 @@ import org.projectfloodlight.openflow.types.OFPort;
  * @author srini
  */
 
+@JsonSerialize(using=NodePortTupleSerializer.class)
 public class NodePortTuple implements Comparable<NodePortTuple> {
     private DatapathId nodeId; // switch DPID
     private OFPort portId; // switch port id
diff --git a/src/main/java/net/floodlightcontroller/core/types/PathNode.java b/src/main/java/net/floodlightcontroller/core/types/PathNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd16ac6f08d1bd465f16808b259a5db29441563c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/types/PathNode.java
@@ -0,0 +1,187 @@
+package net.floodlightcontroller.core.types;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+
+/**
+ * Simple classes for defining a hop in a path.
+ * 
+ * Class PathNode good for tracking hops in
+ * an outer container that guarantees ordering
+ * or for standalone use. It can also be useful
+ * when lookup of specific nodes needs to be
+ * faster than O(n)... lookup time dependent on 
+ * containing class.
+ * 
+ * Inner class LinkedPathNode useful for chaining
+ * LinkedPathNodes together. Note traversal will
+ * always be O(n), since it's effectively a linked
+ * list.
+ * 
+ * @author rizard
+ *
+ */
+public class PathNode {
+    private DatapathId node;
+    private OFPort in;
+    private OFPort out;
+    private int hopId;
+
+    private PathNode() { }
+
+    private PathNode(DatapathId node, OFPort in, OFPort out, int hopId) {
+        this.node = node;
+        this.in = in;
+        this.out = out;
+        this.hopId = hopId;
+    }
+
+    public static PathNode of(DatapathId node, OFPort in, OFPort out, int hopId) {
+        return new PathNode(node, in, out, hopId);
+    }
+
+    public DatapathId getNode() {
+        return node;
+    }
+
+    public OFPort getInPort() {
+        return in;
+    }
+
+    public OFPort getOutPort() {
+        return out;
+    }
+
+    public int getHopId() {
+        return hopId;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + hopId;
+        result = prime * result + ((in == null) ? 0 : in.hashCode());
+        result = prime * result + ((node == null) ? 0 : node.hashCode());
+        result = prime * result + ((out == null) ? 0 : out.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        PathNode other = (PathNode) obj;
+        if (hopId != other.hopId)
+            return false;
+        if (in == null) {
+            if (other.in != null)
+                return false;
+        } else if (!in.equals(other.in))
+            return false;
+        if (node == null) {
+            if (other.node != null)
+                return false;
+        } else if (!node.equals(other.node))
+            return false;
+        if (out == null) {
+            if (other.out != null)
+                return false;
+        } else if (!out.equals(other.out))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "PathNode [node=" + node + ", in=" + in + ", out=" + out + ", hopId=" + hopId + "]";
+    }
+
+    public static class LinkedPathNode extends PathNode {
+        private LinkedPathNode prev;
+        private LinkedPathNode next;
+
+        private LinkedPathNode() { 
+            super(); 
+        }
+
+        private LinkedPathNode(DatapathId node, OFPort in, OFPort out, 
+                int hopId, LinkedPathNode prev, LinkedPathNode next) {
+            super(node, in, out, hopId);
+            this.prev = prev;
+            this.next = next;
+        }
+
+        public static LinkedPathNode of(DatapathId node, OFPort in, OFPort out, 
+                int hopId, LinkedPathNode prev, LinkedPathNode next) {
+            return new LinkedPathNode(node, in, out, hopId, prev, next);
+        }
+
+        public static LinkedPathNode of(PathNode n, LinkedPathNode prev, LinkedPathNode next) {
+            return new LinkedPathNode(n.node, n.in, n.out, n.hopId, prev, next);
+        }
+
+        public LinkedPathNode getPrevious() {
+            return prev;
+        }
+
+        public LinkedPathNode getNext() {
+            return next;
+        }
+
+        public boolean isStart() {
+            if (prev == null && next != null) {
+                return true;
+            }
+            return false;
+        }
+
+        public boolean isEnd() {
+            if (prev != null && next == null) {
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + ((next == null) ? 0 : next.hashCode());
+            result = prime * result + ((prev == null) ? 0 : prev.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (!super.equals(obj))
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            LinkedPathNode other = (LinkedPathNode) obj;
+            if (next == null) {
+                if (other.next != null)
+                    return false;
+            } else if (!next.equals(other.next))
+                return false;
+            if (prev == null) {
+                if (other.prev != null)
+                    return false;
+            } else if (!prev.equals(other.prev))
+                return false;
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "LinkedPathNode [prev=" + prev + ", " 
+                    + super.toString() + ", next=" + next + "]";
+        }
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/JsonObjectWrapperSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/JsonObjectWrapperSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b3906bcdd5ad367d95bf166ecba3f7664f65437
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/JsonObjectWrapperSerializer.java
@@ -0,0 +1,46 @@
+/**
+*    Copyright 2011,2012 Big Switch Networks, Inc. 
+*    Originally created by David Erickson, Stanford University
+* 
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package net.floodlightcontroller.core.web.serializers;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import net.floodlightcontroller.core.types.JsonObjectWrapper;
+
+/**
+ * Serialize a NodePortTupleSerializer
+ */
+public class JsonObjectWrapperSerializer extends JsonSerializer<JsonObjectWrapper> {
+
+    @Override
+    public void serialize(JsonObjectWrapper o, JsonGenerator jGen,
+                          SerializerProvider serializer)
+                                  throws IOException, JsonProcessingException {
+        serialize(o, jGen);
+    }
+    
+    public static void serialize(JsonObjectWrapper o, JsonGenerator jGen) throws IOException {
+        jGen.writeStartObject();
+        jGen.writeObjectField("results", o.getObject());
+        jGen.writeEndObject();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/NodePortTupleSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/NodePortTupleSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..6d2d2e7ad792d8a3591349637640e139effa9815
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/core/web/serializers/NodePortTupleSerializer.java
@@ -0,0 +1,47 @@
+/**
+*    Copyright 2011,2012 Big Switch Networks, Inc. 
+*    Originally created by David Erickson, Stanford University
+* 
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package net.floodlightcontroller.core.web.serializers;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import net.floodlightcontroller.core.types.NodePortTuple;
+
+/**
+ * Serialize a NodePortTupleSerializer
+ */
+public class NodePortTupleSerializer extends JsonSerializer<NodePortTuple> {
+
+    @Override
+    public void serialize(NodePortTuple npt, JsonGenerator jGen,
+                          SerializerProvider serializer)
+                                  throws IOException, JsonProcessingException {
+        serialize(npt, jGen);
+    }
+    
+    public static void serialize(NodePortTuple npt, JsonGenerator jGen) throws IOException {
+        jGen.writeStartObject();
+        jGen.writeStringField("switch", npt.getNodeId().toString());
+        jGen.writeStringField("port", npt.getPortId().toString());
+        jGen.writeEndObject();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
index 3fe2b492e86cbed718d2089055ab15b60758f114..7d62a6c2812a5560d31bdcff0a600f2379c73e75 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
@@ -282,7 +282,7 @@ public class Device implements IDevice {
 			if (!deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort()))
 				continue;
 
-			DatapathId id = deviceManager.topology.getOpenflowDomainId(ap.getSw());
+			DatapathId id = deviceManager.topology.getClusterId(ap.getSw());
 			apMap.put(id, ap);
 		}
 
@@ -345,7 +345,7 @@ public class Device implements IDevice {
 		Set<DatapathId> visitedIslands = new HashSet<DatapathId>();
 			
 		for (AttachmentPoint ap : oldAPList) {
-			DatapathId id = topology.getOpenflowDomainId(ap.getSw());
+			DatapathId id = topology.getClusterId(ap.getSw());
 			AttachmentPoint trueAP = apMap.get(id);
 
 			if (trueAP == null) {
@@ -367,7 +367,7 @@ public class Device implements IDevice {
 		 * has not expired, add them as duplicates to the list.
 		 */
 		for (AttachmentPoint ap : oldAPList) {				
-			DatapathId id = topology.getOpenflowDomainId(ap.getSw());
+			DatapathId id = topology.getClusterId(ap.getSw());
 			if (visitedIslands.contains(id)) {
 				if (ap.getLastSeen().getTime() > timeThreshold) {
 					dupAPs.add(ap);
@@ -472,7 +472,7 @@ public class Device implements IDevice {
 			return true;
 		}
 
-		DatapathId id = topology.getOpenflowDomainId(sw);
+		DatapathId id = topology.getClusterId(sw);
 		AttachmentPoint oldAP = apMap.get(id);
 
 		if (oldAP == null) { // No attachment on this L2 domain.
@@ -507,8 +507,7 @@ public class Device implements IDevice {
 				oldAPList.addAll(oldAPs);
 			oldAPList.add(oldAP);
 			this.oldAPs = oldAPList;
-			if (!topology.isInSameBroadcastDomain(oldAP.getSw(),
-					oldAP.getPort(), newAP.getSw(), newAP.getPort()))
+			if (!topology.isInSameArchipelago(oldAP.getSw(), newAP.getSw())) /* different network */
 				return true; // attachment point changed.
 		} else if (oldAPFlag) {
 			// retain oldAP as is. Put the newAP in oldAPs for flagging
@@ -710,9 +709,6 @@ public class Device implements IDevice {
 
 	@Override
 	public IPv4Address[] getIPv4Addresses() {
-		// XXX - TODO we can cache this result. Let's find out if this
-		// is really a performance bottleneck first though.
-
 		TreeSet<IPv4Address> vals = new TreeSet<IPv4Address>();
 		for (Entity e : entities) {
 			if (e.getIpv4Address().equals(IPv4Address.NONE))
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
index 7fffeeb3edaa109d93ba7d561e38fd893454135d..95b662c440f477c7dc64e5b68a86875d8bab3035 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
@@ -340,13 +340,13 @@ public class DeviceManagerImpl implements IDeviceService, IOFMessageListener, IT
 
 			DatapathId oldSw = oldAP.getSw();
 			OFPort oldPort = oldAP.getPort();
-			DatapathId oldDomain = topology.getOpenflowDomainId(oldSw);
-			boolean oldBD = topology.isBroadcastDomainPort(oldSw, oldPort);
+			DatapathId oldDomain = topology.getClusterId(oldSw);
+			boolean oldBD = topology.isBroadcastPort(oldSw, oldPort);
 
 			DatapathId newSw = newAP.getSw();
 			OFPort newPort = newAP.getPort();
-			DatapathId newDomain = topology.getOpenflowDomainId(newSw);
-			boolean newBD = topology.isBroadcastDomainPort(newSw, newPort);
+			DatapathId newDomain = topology.getClusterId(newSw);
+			boolean newBD = topology.isBroadcastPort(newSw, newPort);
 
 			if (oldDomain.getLong() < newDomain.getLong()) return -1;
 			else if (oldDomain.getLong() > newDomain.getLong()) return 1;
diff --git a/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java b/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java
index 0278ab5545f444a03ee344d9121d83fee055def6..adb8498145385b3d30562467e45f0d5128aa0305 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/PortDownReconciliation.java
@@ -52,7 +52,7 @@ import net.floodlightcontroller.linkdiscovery.ILinkDiscovery;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.floodlightcontroller.linkdiscovery.internal.LinkInfo;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
-import net.floodlightcontroller.routing.Link;
+import net.floodlightcontroller.linkdiscovery.Link;
 import net.floodlightcontroller.topology.ITopologyListener;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.util.OFMatchWithSwDpid;
diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
index 87ffc5500174a7f7d96483be1ec4bb21fe0890f2..e2e40456ebd4478a621b2e95bcc26c566fdc5589 100644
--- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
@@ -52,7 +52,7 @@ import net.floodlightcontroller.routing.ForwardingBase;
 import net.floodlightcontroller.routing.IRoutingDecision;
 import net.floodlightcontroller.routing.IRoutingDecisionChangedListener;
 import net.floodlightcontroller.routing.IRoutingService;
-import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.Path;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.util.FlowModUtils;
 import net.floodlightcontroller.util.OFDPAUtils;
@@ -245,7 +245,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
 
 
     protected void doDropFlow(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
-        OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
+        OFPort inPort = OFMessageUtils.getInPort(pi);
         Match m = createMatchFromPacket(sw, inPort, cntx);
         OFFlowMod.Builder fmb = sw.getOFFactory().buildFlowAdd(); // this will be a drop-flow; a flow that will not output to any ports
         List<OFAction> actions = new ArrayList<OFAction>(); // set no action to drop
@@ -274,7 +274,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
     }
 
     protected void doForwardFlow(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx, boolean requestFlowRemovedNotifn) {
-        OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
+        OFPort inPort = OFMessageUtils.getInPort(pi);
         IDevice dstDevice = IDeviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE);
         DatapathId source = sw.getId();
 
@@ -336,7 +336,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
              * of a link.
              */
             if (dstDap == null) {
-                log.warn("Could not locate edge attachment point for device {}. Flooding packet");
+                log.debug("Could not locate edge attachment point for device {}. Flooding packet");
                 doFlood(sw, pi, decision, cntx);
                 return; 
             }
@@ -349,38 +349,38 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
             }				
 
             U64 cookie = makeForwardingCookie(decision);
-            Route route = routingEngineService.getRoute(source, 
+            Path path = routingEngineService.getPath(source, 
                     inPort,
                     dstDap.getNodeId(),
-                    dstDap.getPortId(), cookie); // Cookie currently ignored. May carry useful info in the future.
+                    dstDap.getPortId());
 
             Match m = createMatchFromPacket(sw, inPort, cntx);
 
-            if (route != null) {
+            if (path != null) {
                 if (log.isDebugEnabled()) {
                     log.debug("pushRoute inPort={} route={} " +
                             "destination={}:{}",
-                            new Object[] { inPort, route,
+                            new Object[] { inPort, path,
                                     dstDap.getNodeId(),
                                     dstDap.getPortId()});
                 }
 
 
                 log.debug("Cretaing flow rules on the route, match rule: {}", m);
-                pushRoute(route, m, pi, sw.getId(), cookie, 
+                pushRoute(path, m, pi, sw.getId(), cookie, 
                         cntx, requestFlowRemovedNotifn,
                         OFFlowModCommand.ADD);	
             } else {
                 /* Route traverses no links --> src/dst devices on same switch */
                 log.debug("Could not compute route. Devices should be on same switch src={} and dst={}", srcDevice, dstDevice);
-                Route r = new Route(srcDevice.getAttachmentPoints()[0].getNodeId(), dstDevice.getAttachmentPoints()[0].getNodeId());
-                List<NodePortTuple> path = new ArrayList<NodePortTuple>(2);
-                path.add(new NodePortTuple(srcDevice.getAttachmentPoints()[0].getNodeId(),
+                Path p = new Path(srcDevice.getAttachmentPoints()[0].getNodeId(), dstDevice.getAttachmentPoints()[0].getNodeId());
+                List<NodePortTuple> npts = new ArrayList<NodePortTuple>(2);
+                npts.add(new NodePortTuple(srcDevice.getAttachmentPoints()[0].getNodeId(),
                         srcDevice.getAttachmentPoints()[0].getPortId()));
-                path.add(new NodePortTuple(dstDevice.getAttachmentPoints()[0].getNodeId(),
+                npts.add(new NodePortTuple(dstDevice.getAttachmentPoints()[0].getNodeId(),
                         dstDevice.getAttachmentPoints()[0].getPortId()));
-                r.setPath(path);
-                pushRoute(r, m, pi, sw.getId(), cookie,
+                p.setPath(npts);
+                pushRoute(p, m, pi, sw.getId(), cookie,
                         cntx, requestFlowRemovedNotifn,
                         OFFlowModCommand.ADD);
             }
@@ -503,15 +503,13 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule, IOF
      * @param cntx The FloodlightContext associated with this OFPacketIn
      */
     protected void doFlood(IOFSwitch sw, OFPacketIn pi, IRoutingDecision decision, FloodlightContext cntx) {
-        OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
-        // Set Action to flood
+        OFPort inPort = OFMessageUtils.getInPort(pi);
         OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
         List<OFAction> actions = new ArrayList<OFAction>();
         Set<OFPort> broadcastPorts = this.topologyService.getSwitchBroadcastPorts(sw.getId());
 
         if (broadcastPorts.isEmpty()) {
-            log.warn("No broadcast ports found. Using FLOOD output action");
-            /* Must be a single-switch w/no links */
+            log.debug("No broadcast ports found. Using FLOOD output action");
             broadcastPorts = Collections.singleton(OFPort.FLOOD);
         }
 
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
index ed0d4a4db9fe46f07db1fb0af5260d8d24e86173..0c1e0d07ead47688b3e3a8e324a7cb8caa26f436 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
@@ -29,7 +29,6 @@ import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.types.NodePortTuple;
 import net.floodlightcontroller.linkdiscovery.internal.LinkInfo;
-import net.floodlightcontroller.routing.Link;
 
 
 public interface ILinkDiscoveryService extends IFloodlightService {
diff --git a/src/main/java/net/floodlightcontroller/routing/Link.java b/src/main/java/net/floodlightcontroller/linkdiscovery/Link.java
similarity index 98%
rename from src/main/java/net/floodlightcontroller/routing/Link.java
rename to src/main/java/net/floodlightcontroller/linkdiscovery/Link.java
index 349fb3c81841a16d799c7db208f73174df475539..9b8ffa6148012f27cb3885923c452e83e014c3f9 100755
--- a/src/main/java/net/floodlightcontroller/routing/Link.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/Link.java
@@ -15,7 +15,7 @@
 *    under the License.
 **/
 
-package net.floodlightcontroller.routing;
+package net.floodlightcontroller.linkdiscovery;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index a4b835724baf922e6acbe14dd03e8a829f0aee67..9899a935985e00e472ef19b81830eab5305f084a 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -69,13 +69,13 @@ import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.SwitchType;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.UpdateOperation;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
+import net.floodlightcontroller.linkdiscovery.Link;
 import net.floodlightcontroller.linkdiscovery.web.LinkDiscoveryWebRoutable;
 import net.floodlightcontroller.packet.BSN;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.LLDP;
 import net.floodlightcontroller.packet.LLDPTLV;
 import net.floodlightcontroller.restserver.IRestApiService;
-import net.floodlightcontroller.routing.Link;
 import net.floodlightcontroller.storage.IResultSet;
 import net.floodlightcontroller.storage.IStorageSourceListener;
 import net.floodlightcontroller.storage.IStorageSourceService;
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/DirectedLinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/DirectedLinksResource.java
index c6262ef6f3d959d0f2f60bb1a504cdbff7563188..50c4f9f837b82d0cc7113412c762e84fbad09f16 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/DirectedLinksResource.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/DirectedLinksResource.java
@@ -25,7 +25,7 @@ import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkDirection;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
 import net.floodlightcontroller.linkdiscovery.internal.LinkInfo;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
-import net.floodlightcontroller.routing.Link;
+import net.floodlightcontroller.linkdiscovery.Link;
 
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java
index d25c693466947caa352ad522cb0d516f234564d5..63e388594d7a822b45c3f5d5d53eadf631299e45 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/ExternalLinksResource.java
@@ -25,7 +25,7 @@ import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkDirection;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
 import net.floodlightcontroller.linkdiscovery.internal.LinkInfo;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
-import net.floodlightcontroller.routing.Link;
+import net.floodlightcontroller.linkdiscovery.Link;
 
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
index 81b5094ddb2f5debff234a779bb4e2596781fc1a..e02180290928aac7a6960ad9faf86d23ef30d858 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
@@ -16,20 +16,21 @@
 
 package net.floodlightcontroller.linkdiscovery.web;
 
-import java.io.IOException;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
-
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
+import net.floodlightcontroller.linkdiscovery.Link;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkDirection;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
-import net.floodlightcontroller.routing.Link;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
+
+import java.io.IOException;
 
 /**
  * This class is both the datastructure and the serializer
@@ -44,6 +45,7 @@ public class LinkWithType extends JsonSerializer<LinkWithType> {
     public OFPort dstPort;
     public LinkType type;
     public LinkDirection direction;
+    public U64 latency;
 
     // Do NOT delete this, it's required for the serializer
     public LinkWithType() {}
@@ -57,6 +59,7 @@ public class LinkWithType extends JsonSerializer<LinkWithType> {
         this.dstPort = link.getDstPort();
         this.type = type;
         this.direction = direction;
+        this.latency = link.getLatency();
     }
 
     @Override
@@ -70,6 +73,7 @@ public class LinkWithType extends JsonSerializer<LinkWithType> {
         jgen.writeNumberField("dst-port", lwt.dstPort.getPortNumber());
         jgen.writeStringField("type", lwt.type.toString());
         jgen.writeStringField("direction", lwt.direction.toString());
+        jgen.writeNumberField("latency", lwt.latency.getValue()); // Might be an issue if value exceed what unsigned long can hold
         jgen.writeEndObject();
     }
 
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
index aa52be4a7138746bdaf38b95a4be06de5a91bea0..ee55538c31d2f7f935a3297233d546397085d378 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
@@ -25,7 +25,7 @@ import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkDirection;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
 import net.floodlightcontroller.linkdiscovery.internal.LinkInfo;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
-import net.floodlightcontroller.routing.Link;
+import net.floodlightcontroller.linkdiscovery.Link;
 
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
index a4a0435f4af08955aa09a0cecff177d856448655..13abba29ffacfdd2402a2f3e2b3a56defc0b8a44 100644
--- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
@@ -72,7 +72,7 @@ import net.floodlightcontroller.packet.TCP;
 import net.floodlightcontroller.packet.UDP;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.routing.IRoutingService;
-import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.Path;
 import net.floodlightcontroller.staticentry.IStaticEntryPusherService;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.util.FlowModUtils;
@@ -128,8 +128,8 @@ public class LoadBalancer implements IFloodlightModule,
             new Comparator<SwitchPort>() {
                 @Override
                 public int compare(SwitchPort d1, SwitchPort d2) {
-                    DatapathId d1ClusterId = topologyService.getOpenflowDomainId(d1.getNodeId());
-                    DatapathId d2ClusterId = topologyService.getOpenflowDomainId(d2.getNodeId());
+                    DatapathId d1ClusterId = topologyService.getClusterId(d1.getNodeId());
+                    DatapathId d2ClusterId = topologyService.getClusterId(d2.getNodeId());
                     return d1ClusterId.compareTo(d2ClusterId);
                 }
             };
@@ -384,7 +384,7 @@ public class LoadBalancer implements IFloodlightModule,
         // srcDevice and/or dstDevice is null, no route can be pushed
         if (srcDevice == null || dstDevice == null) return;
         
-        DatapathId srcIsland = topologyService.getOpenflowDomainId(sw.getId());
+        DatapathId srcIsland = topologyService.getClusterId(sw.getId());
 
         if (srcIsland == null) {
             log.debug("No openflow island found for source {}/{}", 
@@ -398,7 +398,7 @@ public class LoadBalancer implements IFloodlightModule,
         boolean on_same_if = false;
         for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) {
             DatapathId dstSwDpid = dstDap.getNodeId();
-            DatapathId dstIsland = topologyService.getOpenflowDomainId(dstSwDpid);
+            DatapathId dstIsland = topologyService.getClusterId(dstSwDpid);
             if ((dstIsland != null) && dstIsland.equals(srcIsland)) {
                 on_same_island = true;
                 if ((sw.getId().equals(dstSwDpid)) && OFMessageUtils.getInPort(pi).equals(dstDap.getPortId())) {
@@ -442,25 +442,25 @@ public class LoadBalancer implements IFloodlightModule,
             SwitchPort srcDap = srcDaps[iSrcDaps];
             SwitchPort dstDap = dstDaps[iDstDaps];
             DatapathId srcCluster = 
-                    topologyService.getOpenflowDomainId(srcDap.getNodeId());
+                    topologyService.getClusterId(srcDap.getNodeId());
             DatapathId dstCluster = 
-                    topologyService.getOpenflowDomainId(dstDap.getNodeId());
+                    topologyService.getClusterId(dstDap.getNodeId());
 
             int srcVsDest = srcCluster.compareTo(dstCluster);
             if (srcVsDest == 0) {
                 if (!srcDap.equals(dstDap) && 
                         (srcCluster != null) && 
                         (dstCluster != null)) {
-                    Route routeIn = 
-                            routingEngineService.getRoute(srcDap.getNodeId(),
+                    Path routeIn = 
+                            routingEngineService.getPath(srcDap.getNodeId(),
                                                    srcDap.getPortId(),
                                                    dstDap.getNodeId(),
-                                                   dstDap.getPortId(), U64.of(0));
-                    Route routeOut = 
-                            routingEngineService.getRoute(dstDap.getNodeId(),
+                                                   dstDap.getPortId());
+                    Path routeOut = 
+                            routingEngineService.getPath(dstDap.getNodeId(),
                                                    dstDap.getPortId(),
                                                    srcDap.getNodeId(),
-                                                   srcDap.getPortId(), U64.of(0));
+                                                   srcDap.getPortId());
 
                     // use static flow entry pusher to push flow mod along in and out path
                     // in: match src client (ip, port), rewrite dest from vip ip/port to member ip/port, forward
@@ -489,12 +489,12 @@ public class LoadBalancer implements IFloodlightModule,
     /**
      * used to push given route using static flow entry pusher
      * @param boolean inBound
-     * @param Route route
+     * @param Path route
      * @param IPClient client
      * @param LBMember member
      * @param long pinSwitch
      */
-    public void pushStaticVipRoute(boolean inBound, Route route, IPClient client, LBMember member, IOFSwitch pinSwitch) {
+    public void pushStaticVipRoute(boolean inBound, Path route, IPClient client, LBMember member, IOFSwitch pinSwitch) {
         List<NodePortTuple> path = route.getPath();
         if (path.size() > 0) {
            for (int i = 0; i < path.size(); i+=2) {
diff --git a/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java b/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java
index 28ca79f843a5f4984ab25eb012e95141c062c2bb..1862ba3f9ee3ca179cb7ea39507da4adf8d8bb05 100644
--- a/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java
+++ b/src/main/java/net/floodlightcontroller/routing/BroadcastTree.java
@@ -18,10 +18,10 @@
 package net.floodlightcontroller.routing;
 import java.util.HashMap;
 
-import net.floodlightcontroller.routing.Link;
-
 import org.projectfloodlight.openflow.types.DatapathId;
 
+import net.floodlightcontroller.linkdiscovery.Link;
+
 public class BroadcastTree {
     protected HashMap<DatapathId, Link> links;
     protected HashMap<DatapathId, Integer> costs;
diff --git a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
index fa88fd069ca4c700fd41f2df999923b4504dd286..194ce547421a5f0de9d40b9199def1646183dafa 100644
--- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
+++ b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
@@ -39,7 +39,7 @@ import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.floodlightcontroller.packet.IPacket;
 import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.IRoutingDecision;
-import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.Path;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.util.FlowModUtils;
 import net.floodlightcontroller.util.MatchUtils;
@@ -128,8 +128,8 @@ public abstract class ForwardingBase implements IOFMessageListener {
             new Comparator<SwitchPort>() {
         @Override
         public int compare(SwitchPort d1, SwitchPort d2) {
-            DatapathId d1ClusterId = topologyService.getOpenflowDomainId(d1.getNodeId());
-            DatapathId d2ClusterId = topologyService.getOpenflowDomainId(d2.getNodeId());
+            DatapathId d1ClusterId = topologyService.getClusterId(d1.getNodeId());
+            DatapathId d2ClusterId = topologyService.getClusterId(d2.getNodeId());
             return d1ClusterId.compareTo(d2ClusterId);
         }
     };
@@ -193,7 +193,7 @@ public abstract class ForwardingBase implements IOFMessageListener {
      *        OFFlowMod.OFPFC_MODIFY etc.
      * @return true if a packet out was sent on the first-hop switch of this route
      */
-    public boolean pushRoute(Route route, Match match, OFPacketIn pi,
+    public boolean pushRoute(Path route, Match match, OFPacketIn pi,
             DatapathId pinSwitch, U64 cookie, FloodlightContext cntx,
             boolean requestFlowRemovedNotification, OFFlowModCommand flowModCommand) {
 
diff --git a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
index c773cdfcf153cb05e70bef454fcfe9fbfe041bd4..a2af40ba7745c1f48de3656ff4199409a2f6c5ab 100644
--- a/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
+++ b/src/main/java/net/floodlightcontroller/routing/IRoutingService.java
@@ -1,23 +1,23 @@
 /**
-*    Copyright 2011, Big Switch Networks, Inc.
-*    Originally created by David Erickson, Stanford University
-*
-*    Licensed under the Apache License, Version 2.0 (the "License"); you may
-*    not use this file except in compliance with the License. You may obtain
-*    a copy of the License at
-*
-*         http://www.apache.org/licenses/LICENSE-2.0
-*
-*    Unless required by applicable law or agreed to in writing, software
-*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-*    License for the specific language governing permissions and limitations
-*    under the License.
-**/
+ *    Copyright 2011, Big Switch Networks, Inc.
+ *    Originally created by David Erickson, Stanford University
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
 
 package net.floodlightcontroller.routing;
 
-import java.util.ArrayList;
+import java.util.List;
 
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.Masked;
@@ -25,76 +25,61 @@ import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.U64;
 
 import net.floodlightcontroller.core.module.IFloodlightService;
-import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.Path;
 
 public interface IRoutingService extends IFloodlightService {
 
     /**
-     * Provides a route between src and dst that allows tunnels. The cookie is provisioned
-     * for callers of getRoute to provide additional information to influence the route
-     * to be returned, if the underlying routing implementation supports choice among
-     * multiple routes.
-     * @param src Source switch DPID.
-     * @param dst Destination switch DPID.
-     * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
+     * The metric used to compute paths across the topology
+     * 
+     * @author rizard
      */
-    public Route getRoute(DatapathId src, DatapathId dst, U64 cookie);
+    public enum PATH_METRIC { 
+        LATENCY("latency"), 
+        HOPCOUNT("hopcount"), 
+        HOPCOUNT_AVOID_TUNNELS("hopcount_avoid_tunnels"), 
+        UTILIZATION("utilization"), 
+        LINK_SPEED("link_speed");
+        
+        String name;
 
-    /**
-     * Provides a route between src and dst, with option to allow or
-     *  not allow tunnels in the path.
-     * @param src Source switch DPID.
-     * @param dst Destination switch DPID.
-     * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
-     * @param tunnelEnabled boolean option.
-     */
-    public Route getRoute(DatapathId src, DatapathId dst, U64 cookie, boolean tunnelEnabled);
+        private PATH_METRIC(String s) {
+            name = s;
+        }
+        
+        public String getMetricName() {
+            return name;
+        }
+    };
 
     /**
-     * Provides a route between srcPort on src and dstPort on dst.
-     * @param src Source switch DPID.
-     * @param srcPort Source port on source switch.
-     * @param dst Destination switch DPID.
-     * @param dstPort dstPort on Destination switch.
-     * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
+     * Set the metric used when computing paths
+     * across the topology.
+     * @param metric
      */
-    public Route getRoute(DatapathId srcId, OFPort srcPort, DatapathId dstId, OFPort dstPort, U64 cookie);
-
+    public void setPathMetric(PATH_METRIC metric);
+    
     /**
-     * Provides a route between srcPort on src and dstPort on dst.
-     * @param src Source switch DPID.
-     * @param srcPort Source port on source switch.
-     * @param dst Destination switch DPID.
-     * @param dstPort dstPort on Destination switch.
-     * @param cookie cookie (usage determined by implementation; ignored by topology instance now).
-     * @param tunnelEnabled boolean option.
-     */
-    public Route getRoute(DatapathId srcId, OFPort srcPort, DatapathId dstId, OFPort dstPort, U64 cookie, boolean tunnelEnabled);
-
-    /** return all routes, if available */
-    public ArrayList<Route> getRoutes(DatapathId longSrcDpid, DatapathId longDstDpid, boolean tunnelEnabled);
-
-    /** Check if a route exists between src and dst, including tunnel links
-     *  in the path.
-     */
-    public boolean routeExists(DatapathId src, DatapathId dst);
-
-    /** Check if a route exists between src and dst, with option to have
-     *  or not have tunnels as part of the path.
+     * Get the metric being used to compute paths
+     * across the topology.
+     * @return
      */
-    public boolean routeExists(DatapathId src, DatapathId dst, boolean tunnelEnabled);
+    public PATH_METRIC getPathMetric();
     
-    /** Register the RDCListener 
+    /** 
+     * Register the RDCListener 
      * @param listener - The module that wants to listen for events
      */
     public void addRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener);
     
-    /** Remove the RDCListener
+    /** 
+     * Remove the RDCListener
      * @param listener - The module that wants to stop listening for events
      */
     public void removeRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener);
     
-    /** Notifies listeners that routing logic has changed, requiring certain past routing decisions
+    /** 
+     * Notifies listeners that routing logic has changed, requiring certain past routing decisions
      * to become invalid.  The caller provides a sequence of masked values that match against
      * past values of IRoutingDecision.getDescriptor().  Services that have operated on past
      * routing decisions are then able to remove the results of past decisions, normally by deleting
@@ -104,4 +89,88 @@ public interface IRoutingService extends IFloodlightService {
      */
     public void handleRoutingDecisionChange(Iterable<Masked<U64>> changedDecisions);
 
+    /**
+     * Do not compute more than max paths by default (fast).
+     * @param max
+     */
+    public void setMaxPathsToCompute(int max);
+
+    /**
+     * Get the max paths that are computed by default (fast).
+     * @return
+     */
+    public int getMaxPathsToCompute();
+    
+    /** 
+     * Check if a path exists between src and dst
+     * @param src source switch
+     * @param dst destination switch
+     * @return true if a path exists; false otherwise
+     */
+    public boolean pathExists(DatapathId src, DatapathId dst);
+
+    /**
+     * Locates a path between src and dst
+     * @param src source switch
+     * @param dst destination switch
+     * @return the lowest cost path
+     */
+    public Path getPath(DatapathId src, DatapathId dst);
+
+    /**
+     * Provides a path between srcPort on src and dstPort on dst.
+     * @param src source switch
+     * @param srcPort source port on source switch
+     * @param dst destination switch
+     * @param dstPort destination port on destination switch
+     * @return the lowest cost path
+     */
+    public Path getPath(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort);
+
+    /**
+     * Return all possible paths up to quantity of the globally configured max.
+     * @param src source switch
+     * @param dst destination switch
+     * @return list of paths ordered least to greatest cost
+     */
+    public List<Path> getPathsFast(DatapathId src, DatapathId dst);
+
+    /**
+     * This function returns K number of paths between a source and destination 
+     * **if they exist in the pathcache**. If the caller requests more paths than 
+     * available, only the paths already stored in memory will be returned.
+     * 
+     * See {@link #getPathsSlow(DatapathId, DatapathId, int)} to compute 
+     * additional paths in real-time.
+     * 
+     * The number of paths returned will be the min(numReqPaths, maxConfig),
+     * where maxConfig is the configured ceiling on paths to precompute.
+     *
+     * @param src source switch
+     * @param dst destination switch
+     * @param numReqPaths the requested quantity of paths
+     * @return list of paths ordered least to greatest cost
+     */
+    public List<Path> getPathsFast(DatapathId src, DatapathId dst, int numReqPaths);
+
+    /**
+     * This function returns K number of paths between a source and destination.
+     * It will attempt to retrieve these paths from the pathcache. If the caller 
+     * requests more paths than are stored, Yen's algorithm will be re-run in an
+     * attempt to located the desired quantity of paths (which can be expensive).
+     * 
+     * See {@link #getPathsFast(DatapathId, DatapathId, int)} or  
+     * {@link #getPathsFast(DatapathId, DatapathId)} to retrieve the
+     * precomputed paths without the risk of additional overhead.
+     * 
+     * The number of paths returned will be the min(numReqPaths, availablePaths),
+     * where availablePaths is the permutation of all possible paths in the topology
+     * from src to dst.
+     * 
+     * @param src source switch
+     * @param dst destination switch
+     * @param numReqPaths the requested quantity of paths
+     * @return list of paths ordered least to greatest cost
+     */
+    public List<Path> getPathsSlow(DatapathId src, DatapathId dst, int numReqPaths);
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/Route.java b/src/main/java/net/floodlightcontroller/routing/Path.java
similarity index 68%
rename from src/main/java/net/floodlightcontroller/routing/Route.java
rename to src/main/java/net/floodlightcontroller/routing/Path.java
index 13f6266924b7c989bad9130760e3eee9efbefeda..365a33aece0466aff5d1857e621c7a50263bb082 100755
--- a/src/main/java/net/floodlightcontroller/routing/Route.java
+++ b/src/main/java/net/floodlightcontroller/routing/Path.java
@@ -17,48 +17,55 @@
 
 package net.floodlightcontroller.routing;
 
-import java.util.ArrayList;
-import java.util.List;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import net.floodlightcontroller.core.types.NodePortTuple;
+import net.floodlightcontroller.routing.web.serializers.PathSerializer;
 
 import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.U64;
 
-import net.floodlightcontroller.core.types.NodePortTuple;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Represents a route between two switches
  *
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
-public class Route implements Comparable<Route> {
-    protected RouteId id;
+@JsonSerialize(using=PathSerializer.class)
+public class Path implements Comparable<Path> {
+    protected PathId id;
     protected List<NodePortTuple> switchPorts;
-    protected int routeCount;
+    protected int pathIndex;
+    protected int hopCount;
+    protected U64 latency;
 
-    public Route(RouteId id, List<NodePortTuple> switchPorts) {
+    public Path(PathId id, List<NodePortTuple> switchPorts) {
         super();
         this.id = id;
         this.switchPorts = switchPorts;
-        this.routeCount = 0; // useful if multipath routing available
+        this.pathIndex = 0; // useful if multipath routing available
     }
 
-    public Route(DatapathId src, DatapathId dst) {
+    public Path(DatapathId src, DatapathId dst) {
         super();
-        this.id = new RouteId(src, dst);
+        this.id = new PathId(src, dst);
         this.switchPorts = new ArrayList<NodePortTuple>();
-        this.routeCount = 0;
+        this.pathIndex = 0;
     }
 
     /**
      * @return the id
      */
-    public RouteId getId() {
+    public PathId getId() {
         return id;
     }
 
     /**
      * @param id the id to set
      */
-    public void setId(RouteId id) {
+    public void setId(PathId id) {
         this.id = id;
     }
 
@@ -77,17 +84,33 @@ public class Route implements Comparable<Route> {
     }
 
     /**
-     * @param routeCount routeCount set by (ECMP) buildRoute method 
+     * @param pathIndex pathIndex
      */
-    public void setRouteCount(int routeCount) {
-        this.routeCount = routeCount;
+    public void setPathIndex(int pathIndex) {
+        this.pathIndex = pathIndex;
     }
     
     /**
-     * @return routeCount return routeCount set by (ECMP) buildRoute method 
+     * @return pathIndex
      */
-    public int getRouteCount() {
-        return routeCount;
+    public int getPathIndex() {
+        return pathIndex;
+    }
+
+    public void setHopCount(int hopCount) { 
+        this.hopCount = hopCount; 
+    }
+
+    public int getHopCount() { 
+        return this.hopCount;
+    }
+
+    public void setLatency(U64 latency) { 
+        this.latency = latency; 
+    }
+
+    public U64 getLatency() { 
+        return this.latency; 
     }
     
     @Override
@@ -107,7 +130,7 @@ public class Route implements Comparable<Route> {
             return false;
         if (getClass() != obj.getClass())
             return false;
-        Route other = (Route) obj;
+        Path other = (Path) obj;
         if (id == null) {
             if (other.id != null)
                 return false;
@@ -127,10 +150,10 @@ public class Route implements Comparable<Route> {
     }
 
     /**
-     * Compares the path lengths between Routes.
+     * Compares the path lengths.
      */
     @Override
-    public int compareTo(Route o) {
+    public int compareTo(Path o) {
         return ((Integer)switchPorts.size()).compareTo(o.switchPorts.size());
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/RouteId.java b/src/main/java/net/floodlightcontroller/routing/PathId.java
similarity index 74%
rename from src/main/java/net/floodlightcontroller/routing/RouteId.java
rename to src/main/java/net/floodlightcontroller/routing/PathId.java
index dce125111fc4baaf20342c07d5a991a9a8539b57..7f6a90f71b9026b91647ee74731dc426963ee904 100755
--- a/src/main/java/net/floodlightcontroller/routing/RouteId.java
+++ b/src/main/java/net/floodlightcontroller/routing/PathId.java
@@ -18,30 +18,20 @@
 package net.floodlightcontroller.routing;
 
 import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.U64;
 
 /**
- * Stores the endpoints of a route, in this case datapath ids
+ * Stores the endpoints of a path, in this case datapath ids
  *
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
-public class RouteId implements Cloneable, Comparable<RouteId> {
+public class PathId implements Cloneable, Comparable<PathId> {
     protected DatapathId src;
     protected DatapathId dst;
-    protected U64 cookie;
 
-    public RouteId(DatapathId src, DatapathId dst) {
+    public PathId(DatapathId src, DatapathId dst) {
         super();
         this.src = src;
         this.dst = dst;
-        this.cookie = U64.of(0);
-    }
-
-    public RouteId(DatapathId src, DatapathId dst, U64 cookie) {
-        super();
-        this.src = src;
-        this.dst = dst;
-        this.cookie = cookie;
     }
 
     public DatapathId getSrc() {
@@ -60,23 +50,12 @@ public class RouteId implements Cloneable, Comparable<RouteId> {
         this.dst = dst;
     }
 
-    public U64 getCookie() {
-        return cookie;
-    }
-
-    public void setCookie(int cookie) {
-        this.cookie = U64.of(cookie);
-    }
-
     @Override
     public int hashCode() {
         final int prime = 2417;
         Long result = new Long(1);
         result = prime * result + ((dst == null) ? 0 : dst.hashCode());
         result = prime * result + ((src == null) ? 0 : src.hashCode());
-        result = prime * result + cookie.getValue(); 
-        // To cope with long cookie, use Long to compute hash then use Long's 
-        // built-in hash to produce int hash code
         return result.hashCode(); 
     }
 
@@ -88,7 +67,7 @@ public class RouteId implements Cloneable, Comparable<RouteId> {
             return false;
         if (getClass() != obj.getClass())
             return false;
-        RouteId other = (RouteId) obj;
+        PathId other = (PathId) obj;
         if (dst == null) {
             if (other.dst != null)
                 return false;
@@ -114,7 +93,7 @@ public class RouteId implements Cloneable, Comparable<RouteId> {
     }
 
     @Override
-    public int compareTo(RouteId o) {
+    public int compareTo(PathId o) {
         int result = src.compareTo(o.getSrc());
         if (result != 0)
             return result;
diff --git a/src/main/java/net/floodlightcontroller/routing/RoutingManager.java b/src/main/java/net/floodlightcontroller/routing/RoutingManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..8268cee5395794637ac79b61d52d63913bac88d4
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/routing/RoutingManager.java
@@ -0,0 +1,161 @@
+package net.floodlightcontroller.routing;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.Masked;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.topology.ITopologyManagerBackend;
+import net.floodlightcontroller.topology.ITopologyService;
+
+/**
+ * Separate path-finding and routing functionality from the 
+ * topology package. It makes sense to keep much of the core
+ * code in the TopologyInstance, but the TopologyManger is
+ * too confusing implementing so many interfaces and doing
+ * so many tasks. This is a cleaner approach IMHO.
+ * 
+ * All routing and path-finding functionality is visible to
+ * the rest of the controller via the IRoutingService implemented
+ * by the RoutingManger (this). The RoutingManger performs
+ * tasks it can perform locally, such as the handling of
+ * IRoutingDecisionChangedListeners, while it defers to the
+ * current TopologyInstance (exposed via the ITopologyManagerBackend
+ * interface) for tasks best performed by the topology
+ * package, such as path-finding.
+ * 
+ * @author rizard
+ */
+public class RoutingManager implements IFloodlightModule, IRoutingService {
+    private Logger log = LoggerFactory.getLogger(RoutingManager.class);
+    
+    private static ITopologyManagerBackend tm;
+    
+    private List<IRoutingDecisionChangedListener> decisionChangedListeners;
+    
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        return ImmutableSet.of(IRoutingService.class);
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+        return ImmutableMap.of(IRoutingService.class, this);
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+        return ImmutableSet.of(ITopologyService.class);
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+        log.debug("RoutingManager starting up");
+        tm = (ITopologyManagerBackend) context.getServiceImpl(ITopologyService.class);
+        decisionChangedListeners = new ArrayList<IRoutingDecisionChangedListener>();
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context) throws FloodlightModuleException { }
+
+    @Override
+    public void setPathMetric(PATH_METRIC metric) {
+        tm.setPathMetric(metric);
+    }
+
+    @Override
+    public PATH_METRIC getPathMetric() {
+        return tm.getPathMetric();
+    }
+
+
+    @Override
+    public void setMaxPathsToCompute(int max) {
+        tm.setMaxPathsToCompute(max);
+    }
+
+    @Override
+    public int getMaxPathsToCompute() {
+        return tm.getMaxPathsToCompute();
+    }
+
+    @Override
+    public Path getPath(DatapathId src, DatapathId dst) {
+        return tm.getCurrentTopologyInstance().getPath(src, dst);
+    }
+
+    @Override
+    public Path getPath(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort) {
+        return tm.getCurrentTopologyInstance().getPath(src, srcPort, dst, dstPort);
+    }
+
+    @Override
+    public List<Path> getPathsFast(DatapathId src, DatapathId dst) {
+        return tm.getCurrentTopologyInstance().getPathsFast(src, dst, tm.getMaxPathsToCompute());
+    }
+
+    @Override
+    public List<Path> getPathsFast(DatapathId src, DatapathId dst, int numReqPaths) {
+        return tm.getCurrentTopologyInstance().getPathsFast(src, dst, numReqPaths);
+    }
+
+    @Override
+    public List<Path> getPathsSlow(DatapathId src, DatapathId dst, int numReqPaths) {
+        return tm.getCurrentTopologyInstance().getPathsSlow(src, dst, numReqPaths);
+    }
+
+    @Override
+    public boolean pathExists(DatapathId src, DatapathId dst) {
+        return tm.getCurrentTopologyInstance().pathExists(src, dst);
+    }
+
+    /** 
+     * Registers an IRoutingDecisionChangedListener.
+     *   
+     * @param listener
+     * @return 
+     */
+    @Override
+    public void addRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener) {
+        decisionChangedListeners.add(listener);
+    }
+    
+    /** 
+     * Deletes an IRoutingDecisionChangedListener.
+     *   
+     * @param listener 
+     * @return
+     */
+    @Override
+    public void removeRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener) {
+        decisionChangedListeners.remove(listener);
+    }
+
+    /** 
+     * Listens for the event to the IRoutingDecisionChanged listener and calls routingDecisionChanged().
+     *   
+     * @param changedDecisions
+     * @return
+     */
+    @Override
+    public void handleRoutingDecisionChange(Iterable<Masked<U64>> changedDecisions) {
+        for (IRoutingDecisionChangedListener listener : decisionChangedListeners) {
+            listener.routingDecisionChanged(changedDecisions);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/routing/web/PathMetricsResource.java b/src/main/java/net/floodlightcontroller/routing/web/PathMetricsResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf032a135520f0395eefa7a405409f673af901d8
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/routing/web/PathMetricsResource.java
@@ -0,0 +1,70 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+package net.floodlightcontroller.routing.web;
+
+import net.floodlightcontroller.routing.IRoutingService;
+import net.floodlightcontroller.routing.IRoutingService.PATH_METRIC;
+import org.restlet.resource.Post;
+import org.restlet.resource.Put;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class PathMetricsResource extends ServerResource {
+    private static final Logger log = LoggerFactory.getLogger(PathMetricsResource.class);
+
+    @Put
+    @Post
+    public Map<String, String> changeMetric() {
+        IRoutingService routing =
+                (IRoutingService)getContext().getAttributes().
+                        get(IRoutingService.class.getCanonicalName());
+
+        String metric = (String) getRequestAttributes().get("metric");
+        metric = metric.trim().toLowerCase();
+
+        PATH_METRIC type;
+
+        switch (metric) {
+            case "latency":
+                type = PATH_METRIC.LATENCY;
+                break;
+            case "utilization":
+                type = PATH_METRIC.UTILIZATION;
+                break;
+            case "hopcount":
+                type = PATH_METRIC.HOPCOUNT;
+                break;
+            case "hopcount_avoid_tunnels":
+                type = PATH_METRIC.HOPCOUNT_AVOID_TUNNELS;
+                break;
+            case "link_speed":
+                type = PATH_METRIC.LINK_SPEED;
+                break;
+            default:
+                log.error("Invalid input {}", metric);
+                return Collections.singletonMap("error", "invalid path metric " + metric);
+        }
+
+        log.debug("Setting path metric to {}", type.getMetricName());
+        routing.setPathMetric(type);
+        return Collections.singletonMap("success", "path metric set to " + type.getMetricName());
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/routing/web/PathResource.java b/src/main/java/net/floodlightcontroller/routing/web/PathResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..a04a4674510052a7931fd7621f7f790bfcb4c020
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/routing/web/PathResource.java
@@ -0,0 +1,73 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+package net.floodlightcontroller.routing.web;
+
+import net.floodlightcontroller.core.types.JsonObjectWrapper;
+import net.floodlightcontroller.routing.IRoutingService;
+import net.floodlightcontroller.routing.Path;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.python.google.common.collect.ImmutableList;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+public class PathResource extends ServerResource {
+
+    protected static Logger log = LoggerFactory.getLogger(PathResource.class);
+
+    @Get("json")
+    public Object retrieve() {
+        IRoutingService routing = 
+                (IRoutingService)getContext().getAttributes().
+                    get(IRoutingService.class.getCanonicalName());
+        
+        DatapathId srcDpid;
+        DatapathId dstDpid;
+        try {
+            srcDpid = DatapathId.of((String) getRequestAttributes().get("src-dpid"));
+            dstDpid = DatapathId.of((String) getRequestAttributes().get("dst-dpid"));
+        } catch (Exception e) {
+            return ImmutableMap.of("ERROR", "Could not parse source or destination DPID from URI");
+        }     
+        log.debug("Asking for paths from {} to {}", srcDpid, dstDpid);
+        
+        OFPort srcPort;
+        OFPort dstPort;
+        try {
+            srcPort = OFPort.of(Integer.parseInt((String) getRequestAttributes().get("src-port")));
+            dstPort = OFPort.of(Integer.parseInt((String) getRequestAttributes().get("dst-port")));
+        } catch (Exception e) {
+            return ImmutableMap.of("ERROR", "Could not parse source or destination port from URI");
+        }     
+        log.debug("Asking for paths from {} to {}", srcPort, dstPort);
+        
+        Path result = routing.getPath(srcDpid, srcPort, dstDpid, dstPort);
+        
+        if (result != null) {
+            return JsonObjectWrapper.of(routing.getPath(srcDpid, srcPort, dstDpid, dstPort).getPath());
+        }
+        else {
+            log.debug("ERROR! no path found");
+            return JsonObjectWrapper.of(ImmutableList.of());
+        }
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/routing/web/PathsResource.java b/src/main/java/net/floodlightcontroller/routing/web/PathsResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7899d234a4eeca994ac4cc3bbb4359e7dfb5fd4
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/routing/web/PathsResource.java
@@ -0,0 +1,90 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+package net.floodlightcontroller.routing.web;
+
+import net.floodlightcontroller.core.types.JsonObjectWrapper;
+import net.floodlightcontroller.routing.IRoutingService;
+import net.floodlightcontroller.routing.Path;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.python.google.common.collect.ImmutableList;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.List;
+
+public class PathsResource extends ServerResource {
+
+    protected static Logger log = LoggerFactory.getLogger(PathsResource.class);
+
+    @Get("json")
+    public Object retrieve() {
+        IRoutingService routing =
+                (IRoutingService)getContext().getAttributes().
+                        get(IRoutingService.class.getCanonicalName());
+
+        String url = getRequest().getResourceRef().toString();
+
+        DatapathId srcDpid;
+        DatapathId dstDpid;
+        try {
+            srcDpid = DatapathId.of((String) getRequestAttributes().get("src-dpid"));
+            dstDpid = DatapathId.of((String) getRequestAttributes().get("dst-dpid"));
+        } catch (Exception e) {
+            return ImmutableMap.of("ERROR", "Could not parse source or destination DPID from URI");
+        }     
+        log.debug("Asking for paths from {} to {}", srcDpid, dstDpid);
+        
+        Integer numRoutes;
+        try {
+            numRoutes = Integer.parseInt((String) getRequestAttributes().get("num-paths"));
+        } catch (NumberFormatException e) {
+            return ImmutableMap.of("ERROR", "Could not parse number of paths from URI");
+        }
+        log.debug("Asking for {} paths", numRoutes);
+
+        List<Path> results = null;
+        try {
+            if (url.contains("fast")) {
+                results = routing.getPathsFast(srcDpid, dstDpid, numRoutes);
+            } else if (url.contains("slow")) {
+                results = routing.getPathsSlow(srcDpid, dstDpid, numRoutes);
+            } else {
+                results = routing.getPathsFast(srcDpid, dstDpid);
+            }
+        } catch (Exception e) {
+            return JsonObjectWrapper.of(ImmutableList.of());
+        }
+
+        if (results == null || results.isEmpty()) {
+            log.debug("No routes found in request for routes from {} to {}", srcDpid, dstDpid);
+        } else {
+            if (log.isDebugEnabled()) {
+                log.debug("Got {} routes from {} to {}", new Object[] { results.size(), srcDpid, dstDpid });
+                log.debug("These are the routes ---------------------------");
+                log.debug("{}", results);
+                log.debug("------------------------------------------------");
+            }
+
+            return JsonObjectWrapper.of(results);
+        }
+        return JsonObjectWrapper.of(ImmutableList.of());
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/routing/web/RoutingWebRoutable.java b/src/main/java/net/floodlightcontroller/routing/web/RoutingWebRoutable.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9901f0fbb82a133030703847bddb88d60708345
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/routing/web/RoutingWebRoutable.java
@@ -0,0 +1,50 @@
+/**
+ *    Copyright 2013, Big Switch Networks, Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+package net.floodlightcontroller.routing.web;
+
+import org.restlet.Context;
+import org.restlet.routing.Router;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+import net.floodlightcontroller.routing.web.PathMetricsResource;
+import net.floodlightcontroller.routing.web.PathResource;
+import net.floodlightcontroller.routing.web.PathsResource;
+
+public class RoutingWebRoutable implements RestletRoutable {
+    /**
+     * Create the Restlet router and bind to the proper resources.
+     */
+    @Override
+    public Router getRestlet(Context context) {
+        Router router = new Router(context);
+        router.attach("/path/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", PathResource.class);
+        router.attach("/paths/{src-dpid}/{dst-dpid}/{num-paths}/json", PathsResource.class);
+        router.attach("/paths/fast/{src-dpid}/{dst-dpid}/{num-paths}/json", PathsResource.class);
+        router.attach("/paths/slow/{src-dpid}/{dst-dpid}/{num-paths}/json", PathsResource.class);
+        router.attach("/setpathmetric/{metric}/json", PathMetricsResource.class);
+
+        return router;
+    }
+
+    /**
+     * Set the base path for routing service
+     */
+    @Override
+    public String basePath() {
+        return "/wm/routing";
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/routing/web/serializers/PathSerializer.java b/src/main/java/net/floodlightcontroller/routing/web/serializers/PathSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..e234af87fd6e3885bd563c310ef0761c03d7d167
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/routing/web/serializers/PathSerializer.java
@@ -0,0 +1,54 @@
+/**
+ *    Copyright 2011,2012 Big Switch Networks, Inc. 
+ *    Originally created by David Erickson, Stanford University
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+package net.floodlightcontroller.routing.web.serializers;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonGenerator.Feature;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import net.floodlightcontroller.routing.Path;
+import net.floodlightcontroller.core.types.NodePortTuple;
+
+import java.io.IOException;
+
+public class PathSerializer extends JsonSerializer<Path> {
+
+    @Override
+    public void serialize(Path path, JsonGenerator jGen, SerializerProvider serializer)
+            throws IOException, JsonProcessingException {
+        jGen.configure(Feature.WRITE_NUMBERS_AS_STRINGS, true);
+
+        jGen.writeStartObject();
+        jGen.writeStringField("src_dpid", path.getId().getSrc().toString());
+        jGen.writeStringField("dst_dpid", path.getId().getDst().toString());
+        jGen.writeStringField("hop_count", Integer.toString(path.getHopCount()));
+        jGen.writeNumberField("latency", path.getLatency().getValue()); // Might be an issue if value exceed what unsigned long can hold
+        jGen.writeNumberField("path_index", path.getPathIndex());
+        jGen.writeFieldName("path");
+        jGen.writeStartArray();
+        for (NodePortTuple npt : path.getPath()) {
+            jGen.writeStartObject();
+            jGen.writeStringField("dpid", npt.getNodeId().toString());
+            jGen.writeNumberField("port", npt.getPortId().getPortNumber());
+            jGen.writeEndObject();
+        }
+        jGen.writeEndArray();
+        jGen.writeEndObject();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/statistics/IStatisticsService.java b/src/main/java/net/floodlightcontroller/statistics/IStatisticsService.java
index 884e163bc3253b7616c1b8c197046ae589b312a6..7cc047233312e8ca492b1556403ac7a811bd527f 100644
--- a/src/main/java/net/floodlightcontroller/statistics/IStatisticsService.java
+++ b/src/main/java/net/floodlightcontroller/statistics/IStatisticsService.java
@@ -1,18 +1,19 @@
 package net.floodlightcontroller.statistics;
 
-import java.util.Map;
-
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.core.types.NodePortTuple;
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
 
-import net.floodlightcontroller.core.module.IFloodlightService;
-import net.floodlightcontroller.core.types.NodePortTuple;
+import java.util.Map;
 
 public interface IStatisticsService extends IFloodlightService {
 
 	public SwitchPortBandwidth getBandwidthConsumption(DatapathId dpid, OFPort p);
 		
 	public Map<NodePortTuple, SwitchPortBandwidth> getBandwidthConsumption();
+
+	public long getLinkSpeed(NodePortTuple npt);
 	
 	public void collectStatistics(boolean collect);
 }
diff --git a/src/main/java/net/floodlightcontroller/statistics/StatisticsCollector.java b/src/main/java/net/floodlightcontroller/statistics/StatisticsCollector.java
index fca59051d08d87a2bf987a735a9000f0f4043731..50f441bd52b3a61a6ad6c3fcb06361cd8f6ce7df 100644
--- a/src/main/java/net/floodlightcontroller/statistics/StatisticsCollector.java
+++ b/src/main/java/net/floodlightcontroller/statistics/StatisticsCollector.java
@@ -1,35 +1,7 @@
 package net.floodlightcontroller.statistics;
 
-import java.lang.Thread.State;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
-import org.projectfloodlight.openflow.protocol.OFPortStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsReply;
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFStatsType;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.protocol.ver13.OFMeterSerializerVer13;
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.TableId;
-import org.projectfloodlight.openflow.types.U64;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import com.google.common.primitives.UnsignedLong;
 import com.google.common.util.concurrent.ListenableFuture;
-
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
@@ -40,6 +12,21 @@ import net.floodlightcontroller.core.types.NodePortTuple;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.statistics.web.SwitchStatisticsWebRoutable;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
+import org.projectfloodlight.openflow.protocol.*;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.ver13.OFMeterSerializerVer13;
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TableId;
+import org.projectfloodlight.openflow.types.U64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.Thread.State;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 
 public class StatisticsCollector implements IFloodlightModule, IStatisticsService {
 	private static final Logger log = LoggerFactory.getLogger(StatisticsCollector.class);
@@ -254,7 +241,11 @@ public class StatisticsCollector implements IFloodlightModule, IStatisticsServic
 	public Map<NodePortTuple, SwitchPortBandwidth> getBandwidthConsumption() {
 		return Collections.unmodifiableMap(portStats);
 	}
-	
+
+	public long getLinkSpeed(NodePortTuple npt) {
+		return portStats.get(npt).getLinkSpeedBitsPerSec().getValue();
+	}
+
 	@Override
 	public synchronized void collectStatistics(boolean collect) {
 		if (collect && !isEnabled) {
diff --git a/src/main/java/net/floodlightcontroller/topology/Archipelago.java b/src/main/java/net/floodlightcontroller/topology/Archipelago.java
index 7b80fd614179dfd966ef0e737e0db0ec23ac048c..9a8f8c98ceb94609c42280984457bf45ca950b03 100644
--- a/src/main/java/net/floodlightcontroller/topology/Archipelago.java
+++ b/src/main/java/net/floodlightcontroller/topology/Archipelago.java
@@ -54,6 +54,16 @@ public class Archipelago {
             id = a.getId();
         }
     }
+    
+    Set<DatapathId> getSwitches() {
+        Set<DatapathId> allSwitches = new HashSet<DatapathId>();
+        for (Cluster c : clusters) {
+            for (DatapathId d : c.getNodes()) {
+                allSwitches.add(d);
+            }
+        }
+        return allSwitches;
+    }
 
     BroadcastTree getBroadcastTree() {
         return destinationRootedFullTree;
diff --git a/src/main/java/net/floodlightcontroller/topology/Cluster.java b/src/main/java/net/floodlightcontroller/topology/Cluster.java
index a9be8a36c1bdd73d900073717e7a73e0a635bf23..8156f16fce310b4987cf0661fdb13d23a0cee860 100644
--- a/src/main/java/net/floodlightcontroller/topology/Cluster.java
+++ b/src/main/java/net/floodlightcontroller/topology/Cluster.java
@@ -21,10 +21,10 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
-import net.floodlightcontroller.routing.Link;
-
 import org.projectfloodlight.openflow.types.DatapathId;
 
+import net.floodlightcontroller.linkdiscovery.Link;
+
 public class Cluster {
     protected DatapathId id; // the lowest id of the nodes
     protected Map<DatapathId, Set<Link>> links; // set of links connected to a node.
diff --git a/src/main/java/net/floodlightcontroller/topology/ITopologyManagerBackend.java b/src/main/java/net/floodlightcontroller/topology/ITopologyManagerBackend.java
new file mode 100644
index 0000000000000000000000000000000000000000..64c4e06a2abcf3581fa23e5a99a96503d92d727d
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/topology/ITopologyManagerBackend.java
@@ -0,0 +1,13 @@
+package net.floodlightcontroller.topology;
+
+import net.floodlightcontroller.routing.IRoutingService.PATH_METRIC;
+
+public interface ITopologyManagerBackend {
+    public TopologyInstance getCurrentTopologyInstance();
+    
+    public PATH_METRIC getPathMetric();
+    public void setPathMetric(PATH_METRIC metric);
+    
+    public int getMaxPathsToCompute();
+    public void setMaxPathsToCompute(int max);
+}
\ 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 e687ecf253f9a7337466fa8e39362b1c9bd0dbdf..35f66eb48a6851d11649b54ece1921c4878eb00f 100644
--- a/src/main/java/net/floodlightcontroller/topology/ITopologyService.java
+++ b/src/main/java/net/floodlightcontroller/topology/ITopologyService.java
@@ -18,7 +18,8 @@ package net.floodlightcontroller.topology;
 
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.core.types.NodePortTuple;
-import net.floodlightcontroller.routing.Link;
+import net.floodlightcontroller.linkdiscovery.Link;
+
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
 
@@ -27,7 +28,7 @@ import java.util.Map;
 import java.util.Set;
 
 public interface ITopologyService extends IFloodlightService  {
-	
+
 	/*******************************************************
 	 * GENERAL TOPOLOGY FUNCTIONS
 	 *******************************************************/
@@ -37,6 +38,12 @@ public interface ITopologyService extends IFloodlightService  {
 	 * @param listener
 	 */
 	public void addListener(ITopologyListener listener);
+	
+	/**
+     * Remove a listener to stop receiving topology events.
+     * @param listener
+     */
+    public void removeListener(ITopologyListener listener);
 
 	/**
 	 * Retrieve the last time the topology was computed.
@@ -55,14 +62,6 @@ public interface ITopologyService extends IFloodlightService  {
 	 * @return
 	 */
 	public boolean isAttachmentPointPort(DatapathId switchid, OFPort port);
-	
-	/**
-	 * Determines if a device can be learned/located on this switch+port.
-	 * @param switchid
-	 * @param port
-	 * @return
-	 */
-	public boolean isAttachmentPointPort(DatapathId switchid, OFPort port, boolean tunnelEnabled);
 
 	/**
 	 * Determines whether or not a switch+port is a part of
@@ -86,35 +85,7 @@ public interface ITopologyService extends IFloodlightService  {
 	 * @param port
 	 * @return
 	 */
-	public boolean isBroadcastDomainPort(DatapathId sw, OFPort port);
-	
-	/**
-	 * Checks if the switch+port is in the broadcast tree.
-	 * @param sw
-	 * @param port
-	 * @param tunnelEnabled
-	 * @return
-	 */
-	public boolean isBroadcastDomainPort(DatapathId sw, OFPort port, boolean tunnelEnabled);
-
-	/**
-	 * Determines if the switch+port is blocked. If blocked, it
-	 * should not be allowed to send/receive any traffic.
-	 * @param sw
-	 * @param portId
-	 * @return
-	 */
-	public boolean isAllowed(DatapathId sw, OFPort portId);
-	
-	/**
-	 * Determines if the switch+port is blocked. If blocked, it
-	 * should not be allowed to send/receive any traffic.
-	 * @param sw
-	 * @param portId
-	 * @param tunnelEnabled
-	 * @return
-	 */
-	public boolean isAllowed(DatapathId sw, OFPort portId, boolean tunnelEnabled);
+	public boolean isBroadcastPort(DatapathId sw, OFPort port);
 
 	/**
 	 * Indicates if an attachment point on the new switch port is consistent
@@ -127,45 +98,6 @@ public interface ITopologyService extends IFloodlightService  {
 	 */
 	public boolean isConsistent(DatapathId oldSw, OFPort oldPort, 
 			DatapathId newSw, OFPort newPort);
-	
-	/**
-	 * Indicates if an attachment point on the new switch port is consistent
-	 * with the attachment point on the old switch port or not.
-	 * @param oldSw
-	 * @param oldPort
-	 * @param newSw
-	 * @param newPort
-	 * @param tunnelEnabled
-	 * @return
-	 */
-	public boolean isConsistent(DatapathId oldSw, OFPort oldPort,
-			DatapathId newSw, OFPort newPort, boolean tunnelEnabled);
-
-	/**
-	 * 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 boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1,
-			DatapathId s2, OFPort p2);
-	
-	/**
-	 * Indicates if the two switch ports are connected to the same
-	 * broadcast domain or not.
-	 * @param s1
-	 * @param p1
-	 * @param s2
-	 * @param p2
-	 * @param tunnelEnabled
-	 * @return
-	 */
-	public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1,
-			DatapathId s2, OFPort p2,
-			boolean tunnelEnabled);
 
 	/** 
 	 * Get broadcast ports on a target switch for a given attachment point
@@ -177,60 +109,27 @@ public interface ITopologyService extends IFloodlightService  {
 	 */
 	public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort);
 
-	/** 
-	 * Get broadcast ports on a target switch for a given attachment point
-	 * point port.
-	 * @param targetSw
-	 * @param src
-	 * @param srcPort
-	 * @param tunnelEnabled
-	 * @return
-	 */
-	public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort, boolean tunnelEnabled);
-
 	/**
-	 * Checks if the given switch+port is allowed to receive broadcast packets.
+	 * Checks if the given switch+port is allowed to send or receive broadcast packets.
 	 * @param sw
 	 * @param portId
 	 * @return
 	 */
-	public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId);
-	
-	/**
-	 * Checks if the given switch+port is allowed to receive broadcast packets.
-	 * @param sw
-	 * @param portId
-	 * @param tunnelEnabled
-	 * @return
-	 */
-	public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId, boolean tunnelEnabled);
-	
-	/**
-	 * 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 srcPort
-	 * @return
-	 */
-	public NodePortTuple getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort);
+	public boolean isBroadcastAllowed(DatapathId sw, OFPort portId);
 
 	/**
-	 * 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 srcPort
-	 * @param tunnelEnabled
+	 * Gets the set of ports that participate in the broadcast within each archipelago
 	 * @return
 	 */
-	public NodePortTuple getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort, boolean tunnelEnabled);
-
+	public Set<NodePortTuple> getAllBroadcastPorts();
+	
 	/**
-	 * Gets the set of ports that belong to a broadcast domain.
-	 * @return
-	 */
-	public Set<NodePortTuple> getBroadcastDomainPorts();
+     * Gets the set of ports that participate in the broadcast trees for the
+     * archipelago in which the swtich belongs
+     * @param sw
+     * @return
+     */
+    public Set<NodePortTuple> getBroadcastPortsInArchipelago(DatapathId sw);
 	
 	/**
 	 * Gets the set of ports that belong to tunnels.
@@ -245,6 +144,15 @@ public interface ITopologyService extends IFloodlightService  {
 	 * @return
 	 */
 	public Set<NodePortTuple> getBlockedPorts();
+	
+	/**
+     * Determines if the switch+port is blocked. If blocked, it
+     * should not be allowed to send/receive any traffic.
+     * @param sw
+     * @param portId
+     * @return
+     */
+    public boolean isNotBlocked(DatapathId sw, OFPort portId);
 
 	/**
 	 * Returns the enabled, non quarantined ports of the given switch. Returns
@@ -254,7 +162,7 @@ public interface ITopologyService extends IFloodlightService  {
 	public Set<OFPort> getPorts(DatapathId sw);
 	
 	/*******************************************************
-	 * ISLAND/DOMAIN/CLUSTER FUNCTIONS
+	 * CLUSTER AND ARCHIPELAGO FUNCTIONS
 	 *******************************************************/
 	
 	/**
@@ -263,47 +171,52 @@ public interface ITopologyService extends IFloodlightService  {
 	 * @param switchId
 	 * @return
 	 */
-	public DatapathId getOpenflowDomainId(DatapathId switchId);
+	public DatapathId getClusterId(DatapathId switchId);
 	
 	/**
-	 * Return the ID of the domain/island/cluster this switch is
-	 * a part of. The ID is the lowest switch DPID within the domain.
-	 * @param switchId
-	 * @return
-	 */
-	public DatapathId getOpenflowDomainId(DatapathId switchId, boolean tunnelEnabled);
+     * Return the ID of the archipelago this switch is
+     * a part of. The ID is the lowest cluster DPID within the archipelago.
+     * @param switchId
+     * @return
+     */
+    public DatapathId getArchipelagoId(DatapathId switchId);
+    
+    /**
+     * Return all archipelagos
+     * @return
+     */
+    public Set<DatapathId> getArchipelagoIds();
 	
 	/**
 	 * Determines if two switches are in the same domain/island/cluster.
-	 * @param switch1
-	 * @param switch2
+	 * @param s1
+	 * @param s2
 	 * @return true if the switches are in the same cluster
 	 */
-	public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2);
+	public boolean isInSameCluster(DatapathId s1, DatapathId s2);
 	
 	/**
-	 * Determines if two switches are in the same domain/island/cluster.
-	 * @param switch1
-	 * @param switch2
-	 * @param tunnelEnabled
-	 * @return true if the switches are in the same cluster
-	 */
-	public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2, boolean tunnelEnabled);
+     * Determines if two switches are in the same archipelago.
+     * @param s1
+     * @param s2
+     * @return true if the switches are in the same archipelago
+     */
+    public boolean isInSameArchipelago(DatapathId s1, DatapathId s2);
 
 	/**
 	 * Gets all switches in the same domain/island/cluster as the switch provided.
-	 * @param switchDPID
+	 * @param sw
 	 * @return
 	 */
-	public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID);
+	public Set<DatapathId> getSwitchesInCluster(DatapathId sw);
 	
 	/**
-	 * Gets all switches in the same domain/island/cluster as the switch provided.
-	 * @param switchDPID
-	 * @param tunnelEnabled
-	 * @return
-	 */
-	public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID, boolean tunnelEnabled);
+     * Gets all cluster IDs in the same archipelago as the switch provided.
+     * @param sw
+     * @return
+     */
+    public Set<DatapathId> getClusterIdsInArchipelago(DatapathId sw);
+    
 	
 	/*******************************************************
 	 * LINK FUNCTIONS
@@ -324,81 +237,20 @@ public interface ITopologyService extends IFloodlightService  {
 	public Set<OFPort> getPortsWithLinks(DatapathId sw);
 	
 	/**
-	 * Gets a list of ports on a given switch that are part of known links.
-	 * @param sw
-	 * @param tunnelEnabled
+	 * Get all links that are:
+	 * --external
+	 * --detected via BDDP
+	 * --connect two clusters
 	 * @return
 	 */
-	public Set<OFPort> getPortsWithLinks(DatapathId sw, boolean tunnelEnabled);
-
-	/*******************************************************
-	 * ROUTING FUNCTIONS
-	 *******************************************************/
-	
-	/**
-	 * If trying to route a packet ingress a source switch+port to a destination
-	 * switch+port, retrieve the egress source switch+port leading to the destination.
-	 * @param src
-	 * @param srcPort
-	 * @param dst
-	 * @param dstPort
-	 * @return
-	 */
-	public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort);
-
-	/**
-	 * If trying to route a packet ingress a source switch+port to a destination
-	 * switch+port, retrieve the egress source switch+port leading to the destination.
-	 * @param src
-	 * @param srcPort
-	 * @param dst
-	 * @param dstPort
-	 * @param tunnelEnabled
-	 * @return
-	 */
-	public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort dstPort, boolean tunnelEnabled);
-
-	/**
-	 * If trying to route a packet ingress a source switch+port to a destination
-	 * switch+port, retrieve the ingress destination switch+port leading to the destination.
-	 * @param src
-	 * @param srcPort
-	 * @param dst
-	 * @param dstPort
-	 * @return
-	 */
-	public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort);
-	
-	/**
-	 * If trying to route a packet ingress a source switch+port to a destination
-	 * switch+port, retrieve the ingress destination switch+port leading to the destination.
-	 * @param src
-	 * @param srcPort
-	 * @param dst
-	 * @param dstPort
-	 * @param tunnelEnabled
-	 * @return
-	 */
-	public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort dstPort, boolean tunnelEnabled);
-
-	/**
-	 * 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(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort);
+	public Set<Link> getExternalInterClusterLinks();
 	
 	/**
-	 * If the dst is not allowed by the higher-level topology,
-	 * this method provides the topologically equivalent broadcast port.
-	 * @param src
-	 * @param dst
-	 * @param tunnelEnabled
-	 * @return the allowed broadcast port
-	 */
-	public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort, boolean tunnelEnabled);
+     * Get all links that are:
+     * --internal
+     * --detected via LLDP
+     * --connect two clusters
+     * @return
+     */
+    public Set<Link> getInternalInterClusterLinks();
 }
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
index 76b8af2e75466c7149c9536381ea6ebaf23f751c..fbd6bf8a4208cfa2a554f59cd66fcc2d3341a0c1 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyInstance.java
@@ -16,25 +16,27 @@
 
 package net.floodlightcontroller.topology;
 
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
 import net.floodlightcontroller.core.types.NodePortTuple;
+import net.floodlightcontroller.linkdiscovery.Link;
 import net.floodlightcontroller.routing.BroadcastTree;
-import net.floodlightcontroller.routing.Link;
-import net.floodlightcontroller.routing.Route;
-import net.floodlightcontroller.routing.RouteId;
+import net.floodlightcontroller.routing.Path;
+import net.floodlightcontroller.routing.PathId;
 import net.floodlightcontroller.util.ClusterDFS;
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.U64;
+import org.python.google.common.collect.ImmutableList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableSet;
+
 import java.util.*;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
 
 /**
- * A representation of a network topology.  Used internally by
+ * A representation of a network topology. Used internally by
  * {@link TopologyManager}
  */
 public class TopologyInstance {
@@ -47,232 +49,191 @@ public class TopologyInstance {
     public static final int MAX_PATH_WEIGHT = Integer.MAX_VALUE - MAX_LINK_WEIGHT - 1;
     public static final int PATH_CACHE_SIZE = 1000;
 
-    protected static Logger log = LoggerFactory.getLogger(TopologyInstance.class);
+    private static final Logger log = LoggerFactory.getLogger(TopologyInstance.class);
+
+    /* Global: general switch, port, link */
+    private Set<DatapathId>                 switches;
+    private Map<DatapathId, Set<OFPort>>    portsWithLinks; /* only ports with links */
+    private Map<DatapathId, Set<OFPort>>    portsPerSwitch; /* every port on the switch */
+    private Set<NodePortTuple>              portsTunnel; /* all tunnel ports in topology */
+    private Set<NodePortTuple>              portsBroadcastAll; /* all broadcast ports in topology */
+    private Map<DatapathId, Set<OFPort>>    portsBroadcastPerSwitch; /* broadcast ports mapped per DPID */
+    private Set<NodePortTuple>              portsWithMoreThanTwoLinks; /* a.k.a. "broadcast domain" non-P2P ports */
+    private Map<NodePortTuple, Set<Link>>   links; /* every link in entire topology */
+    private Map<NodePortTuple, Set<Link>>   linksNonBcastNonTunnel; /* only non-broadcast and non-tunnel links */
+    private Map<NodePortTuple, Set<Link>>   linksExternal; /* BDDP links b/t clusters */
+    private Set<Link>                       linksNonExternalInterCluster;
+
+    /* Blocked */
+    private Set<NodePortTuple>  portsBlocked;
+    private Set<Link>           linksBlocked;
+
+    /* Per-cluster */
+    private Set<Cluster>                        clusters;
+    private Map<DatapathId, Set<NodePortTuple>> clusterPorts; /* ports in the cluster ID */
+    private Map<DatapathId, Cluster>            clusterFromSwitch; /* cluster for each switch */
+
+    /* Per-archipelago */
+    private Set<Archipelago>                    archipelagos; /* connected clusters */
+    private Map<Cluster, Archipelago>           archipelagoFromCluster;
+    private Map<DatapathId, Set<NodePortTuple>> portsBroadcastPerArchipelago; /* broadcast ports in each archipelago ID */
+    private Map<PathId, List<Path>>             pathcache; /* contains computed paths ordered best to worst */
+
+    protected TopologyInstance(Map<DatapathId, Set<OFPort>> portsWithLinks,
+            Set<NodePortTuple> portsBlocked,
+            Map<NodePortTuple, Set<Link>> linksNonBcastNonTunnel,
+            Set<NodePortTuple> portsWithMoreThanTwoLinks,
+            Set<NodePortTuple> portsTunnel, 
+            Map<NodePortTuple, Set<Link>> links,
+            Map<DatapathId, Set<OFPort>> portsPerSwitch,
+            Map<NodePortTuple, Set<Link>> linksExternal) {
+
+        this.switches = new HashSet<DatapathId>(portsWithLinks.keySet());
+        this.portsWithLinks = new HashMap<DatapathId, Set<OFPort>>();
+        for (DatapathId sw : portsWithLinks.keySet()) {
+            this.portsWithLinks.put(sw, new HashSet<OFPort>(portsWithLinks.get(sw)));
+        }
 
-    protected Map<DatapathId, Set<OFPort>> 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<DatapathId> switches;
-    protected Set<NodePortTuple> broadcastDomainPorts;
-    protected Set<NodePortTuple> tunnelPorts;
-
-    protected Set<Cluster> clusters;  // set of openflow domains
-    protected Map<DatapathId, Cluster> switchClusterMap; // switch to OF domain map
-
-    // States for routing
-    protected Map<DatapathId, BroadcastTree> destinationRootedTrees;
-  
-    protected Map<DatapathId, Set<NodePortTuple>> clusterPorts;
-    protected Map<DatapathId, BroadcastTree> clusterBroadcastTrees;
- 
-    protected Map<DatapathId, Set<NodePortTuple>> clusterBroadcastNodePorts;
-	//Broadcast tree over whole topology which may be consisted of multiple clusters
-    protected BroadcastTree finiteBroadcastTree;
-	//Set of NodePortTuples of the finiteBroadcastTree
-    protected Set<NodePortTuple> broadcastNodePorts;  
-	//destinationRootedTrees over whole topology (not only intra-cluster tree)
-    protected Map<DatapathId, BroadcastTree> destinationRootedFullTrees;
-	//Set of all links organized by node port tuple. Note that switchPortLinks does not contain all links of multi-cluster topology.
-    protected Map<NodePortTuple, Set<Link>> allLinks;
-	//Set of all ports organized by DatapathId. Note that switchPorts map contains only ports with links.
-	protected Map<DatapathId, Set<OFPort>> allPorts;
-    //Set of all the inter-island or "external" links. Also known as portBroadcastDomainLinks in TopologyManager.
-    protected Map<NodePortTuple, Set<Link>> externalLinks;
-	// Maps broadcast ports to DatapathId
-    protected Map<DatapathId, Set<OFPort>> broadcastPortMap;
-
-    protected Set<Archipelago> archipelagos;
-
-    protected class PathCacheLoader extends CacheLoader<RouteId, Route> {
-        TopologyInstance ti;
-        PathCacheLoader(TopologyInstance ti) {
-            this.ti = ti;
+        this.portsPerSwitch = new HashMap<DatapathId, Set<OFPort>>();
+        for (DatapathId sw : portsPerSwitch.keySet()) {
+            this.portsPerSwitch.put(sw, new HashSet<OFPort>(portsPerSwitch.get(sw)));
         }
 
-        @Override
-        public Route load(RouteId rid) {
-            return ti.buildroute(rid);
+        this.portsBlocked = new HashSet<NodePortTuple>(portsBlocked);
+        this.linksNonBcastNonTunnel = new HashMap<NodePortTuple, Set<Link>>();
+        for (NodePortTuple npt : linksNonBcastNonTunnel.keySet()) {
+            this.linksNonBcastNonTunnel.put(npt, new HashSet<Link>(linksNonBcastNonTunnel.get(npt)));
         }
-    }
 
-    // Path cache loader is defined for loading a path when it not present
-    // in the cache.
-    private final PathCacheLoader pathCacheLoader = new PathCacheLoader(this);
-    protected LoadingCache<RouteId, Route> pathcache;
-	
-    public TopologyInstance(Map<DatapathId, Set<OFPort>> switchPorts,
-                            Set<NodePortTuple> blockedPorts,
-                            Map<NodePortTuple, Set<Link>> switchPortLinks,
-                            Set<NodePortTuple> broadcastDomainPorts,
-                            Set<NodePortTuple> tunnelPorts, 
-                            Map<NodePortTuple, Set<Link>> allLinks,
-                            Map<DatapathId, Set<OFPort>> allPorts,
-                            Map<NodePortTuple, Set<Link>> externalLinks) {
-	
-        this.switches = new HashSet<DatapathId>(switchPorts.keySet());
-        this.switchPorts = new HashMap<DatapathId, Set<OFPort>>();
-        for (DatapathId sw : switchPorts.keySet()) {
-            this.switchPorts.put(sw, new HashSet<OFPort>(switchPorts.get(sw)));
-        }
-		
-		this.allPorts = new HashMap<DatapathId, Set<OFPort>>();
-		for (DatapathId sw : allPorts.keySet()) {
-            this.allPorts.put(sw, new HashSet<OFPort>(allPorts.get(sw)));
-        }
-
-        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.allLinks = new HashMap<NodePortTuple, Set<Link>>();
-        for (NodePortTuple npt : allLinks.keySet()) {
-            this.allLinks.put(npt, new HashSet<Link>(allLinks.get(npt)));
-        }
-
-        this.externalLinks = new HashMap<NodePortTuple, Set<Link>>();
-        for (NodePortTuple npt : externalLinks.keySet()) {
-            this.externalLinks.put(npt, new HashSet<Link>(externalLinks.get(npt)));
+        this.links = new HashMap<NodePortTuple, Set<Link>>();
+        for (NodePortTuple npt : links.keySet()) {
+            this.links.put(npt, new HashSet<Link>(links.get(npt)));
         }
 
+        this.linksExternal = new HashMap<NodePortTuple, Set<Link>>();
+        for (NodePortTuple npt : linksExternal.keySet()) {
+            this.linksExternal.put(npt, new HashSet<Link>(linksExternal.get(npt)));
+        }
+
+        this.linksNonExternalInterCluster = new HashSet<Link>();
         this.archipelagos = new HashSet<Archipelago>();
-        
-        this.broadcastDomainPorts = new HashSet<NodePortTuple>(broadcastDomainPorts);
-        this.tunnelPorts = new HashSet<NodePortTuple>(tunnelPorts);
 
-        this.blockedLinks = new HashSet<Link>();
-       
+        this.portsWithMoreThanTwoLinks = new HashSet<NodePortTuple>(portsWithMoreThanTwoLinks);
+        this.portsTunnel = new HashSet<NodePortTuple>(portsTunnel);
+
+        this.linksBlocked = new HashSet<Link>();
+
         this.clusters = new HashSet<Cluster>();
-        this.switchClusterMap = new HashMap<DatapathId, Cluster>();
-        this.destinationRootedTrees = new HashMap<DatapathId, BroadcastTree>();
-        this.destinationRootedFullTrees= new HashMap<DatapathId, BroadcastTree>();
-		this.broadcastNodePorts= new HashSet<NodePortTuple>();
-		this.broadcastPortMap = new HashMap<DatapathId,Set<OFPort>>();
-        this.clusterBroadcastTrees = new HashMap<DatapathId, BroadcastTree>();
-        this.clusterBroadcastNodePorts = new HashMap<DatapathId, Set<NodePortTuple>>();
-
-        pathcache = CacheBuilder.newBuilder().concurrencyLevel(4)
-                    .maximumSize(1000L)
-                    .build(
-                            new CacheLoader<RouteId, Route>() {
-                                public Route load(RouteId rid) {
-                                    return pathCacheLoader.load(rid);
-                                }
-                            });
+        this.clusterFromSwitch = new HashMap<DatapathId, Cluster>();
+        this.portsBroadcastAll= new HashSet<NodePortTuple>();
+        this.portsBroadcastPerSwitch = new HashMap<DatapathId,Set<OFPort>>();
+
+        this.pathcache = new HashMap<PathId, List<Path>>();
+
+        this.portsBroadcastPerArchipelago = new HashMap<DatapathId, Set<NodePortTuple>>();
+
+        this.archipelagoFromCluster = new HashMap<Cluster, Archipelago>();
     }
-	
-    public void compute() {
-        // Step 1: Compute clusters ignoring broadcast domain links
-        // Create nodes for clusters in the higher level topology
-        // Must ignore blocked links.
-        identifyOpenflowDomains();
-
-        // Step 1.1: Add links to clusters
-        // 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.
-        // Cost for tunnel links and direct links are the same.
-        calculateShortestPathTreeInClusters();
-		
-		// Step 3. Compute broadcast tree in each cluster.
-        // Cost for tunnel links are high to discourage use of
-        // tunnel links.  The cost is set to the number of nodes
-        // in the cluster + 1, to use as minimum number of
-        // clusters as possible.
-        calculateBroadcastNodePortsInClusters();
-        
-        // Step 4. Compute e2e shortest path trees on entire topology for unicast routing.
-		// The trees are rooted at the destination.
-        // Cost for tunnel links and direct links are the same.
-		calculateAllShortestPaths();
-
-        // Compute the archipelagos (def: cluster of islands). An archipelago will
-        // simply be a group of connected islands. Each archipelago will have its own
-        // finiteBroadcastTree which will be randomly chosen.
-        calculateArchipelagos();
-		
-		// Step 5. Compute broadcast tree for the whole topology (needed to avoid loops).
-        // Cost for tunnel links are high to discourage use of
-        // tunnel links.  The cost is set to the number of nodes
-        // in the cluster + 1, to use as minimum number of
-        // clusters as possible.
-        calculateAllBroadcastNodePorts();
-
-		// Step 6. Compute set of ports for broadcasting. Edge ports are included.
-       	calculateBroadcastPortMap();
-       	
-        // Step 7. print topology.
+
+    protected void compute() {
+        /*
+         * Step 1: Compute clusters ignoring ports with > 2 links and 
+         * blocked links.
+         */
+        identifyClusters();
+
+        /*
+         * Step 2: Associate non-blocked links within clusters to the cluster
+         * in which they reside. The remaining links are inter-cluster links.
+         */
+        identifyIntraClusterLinks();
+
+        /* 
+         * Step 3: Compute the archipelagos. (Def: group of conneccted clusters)
+         * Each archipelago will have its own broadcast tree, chosen by running 
+         * dijkstra's algorithm from the archipelago ID switch (lowest switch 
+         * DPID). We need a broadcast tree per archipelago since each 
+         * archipelago is by definition isolated from all other archipelagos.
+         */
+        identifyArchipelagos();
+
+        /*
+         * Step 4: Use Yens algorithm to permute through each node combination
+         * within each archipelago and compute multiple paths. The shortest
+         * path located (i.e. first run of dijkstra's algorithm) will be used 
+         * as the broadcast tree for the archipelago.
+         */
+        computeOrderedPaths();
+
+        /*
+         * Step 5: Determine the broadcast ports for each archipelago. These are
+         * the ports that reside on the broadcast tree computed and saved when
+         * performing path-finding. These are saved into multiple data structures
+         * to aid in quick lookup per archipelago, per-switch, and topology-global.
+         */
+        computeBroadcastPortsPerArchipelago();
+
+        /*
+         * Step 6: Optionally, print topology to log for added verbosity or when debugging.
+         */
         printTopology();
     }
 
-	/*
-	 * Checks if OF port is edge port
-	 */
+    /*
+     * Checks if OF port is edge port
+     */
     public boolean isEdge(DatapathId sw, OFPort portId) { 
-		NodePortTuple np = new NodePortTuple(sw, portId);
-		if (allLinks.get(np) == null || allLinks.get(np).isEmpty()) {
-			return true;
-		}
-		else {
-			return false;
-		}
+        NodePortTuple np = new NodePortTuple(sw, portId);
+        if (links.get(np) == null || links.get(np).isEmpty()) {
+            return true;
+        }
+        else {
+            return false;
+        }
     }   
 
-	/*
-	 * Returns broadcast ports for the given DatapathId
-	 */
+    /*
+     * Returns broadcast ports for the given DatapathId
+     */
     public Set<OFPort> swBroadcastPorts(DatapathId sw) {
-    	if (!broadcastPortMap.containsKey(sw) || broadcastPortMap.get(sw) == null) {
-    		log.debug("Could not locate broadcast ports for switch {}", sw);
-    		return Collections.emptySet();
-    	} else {
-    		if (log.isDebugEnabled()) {
-    			log.debug("Found broadcast ports {} for switch {}", broadcastPortMap.get(sw), sw);
-    		}
-    		return broadcastPortMap.get(sw);
-    	}
+        if (!portsBroadcastPerSwitch.containsKey(sw) || portsBroadcastPerSwitch.get(sw) == null) {
+            log.debug("Could not locate broadcast ports for switch {}", sw);
+            return Collections.emptySet();
+        } else {
+            if (log.isDebugEnabled()) {
+                log.debug("Found broadcast ports {} for switch {}", portsBroadcastPerSwitch.get(sw), sw);
+            }
+            return portsBroadcastPerSwitch.get(sw);
+        }
     }
 
-    public void printTopology() {
+    private void printTopology() {
         log.debug("-----------------Topology-----------------------");
-        log.debug("All Links: {}", allLinks);
-		log.debug("Cluser Broadcast Trees: {}", clusterBroadcastTrees);
-        log.debug("Cluster Ports: {}", clusterPorts);
-        log.debug("Tunnel Ports: {}", tunnelPorts);
+        log.debug("All Links: {}", links);
+        log.debug("Tunnel Ports: {}", portsTunnel);
         log.debug("Clusters: {}", clusters);
-        log.debug("Destination Rooted Full Trees: {}", destinationRootedFullTrees);
-        log.debug("Cluser Broadcast Node Ports: {}", clusterBroadcastNodePorts);
-        log.debug("Broadcast Ports Per Node (!!): {}", broadcastPortMap);
-        log.debug("Broadcast Domain Ports: {}", broadcastDomainPorts);
-        log.debug("Broadcast Node Ports: {}", broadcastDomainPorts);
+        log.debug("Broadcast Ports Per Node (!!): {}", portsBroadcastPerSwitch);
+        log.debug("3+ Link Ports: {}", portsWithMoreThanTwoLinks);
         log.debug("Archipelagos: {}", archipelagos);
         log.debug("-----------------------------------------------");  
     }
 
-    protected void addLinksToOpenflowDomains() {
-        for(DatapathId s: switches) {
-            if (switchPorts.get(s) == null) continue;
-            for (OFPort p: switchPorts.get(s)) {
+    private void identifyIntraClusterLinks() {
+        for (DatapathId s : switches) {
+            if (portsWithLinks.get(s) == null) continue;
+            for (OFPort p : portsWithLinks.get(s)) {
                 NodePortTuple np = new NodePortTuple(s, p);
-                if (switchPortLinks.get(np) == null) continue;
-                if (isBroadcastDomainPort(np)) continue;
-                for(Link l: switchPortLinks.get(np)) {
+                if (linksNonBcastNonTunnel.get(np) == null) continue;
+                if (isBroadcastPort(np)) continue;
+                for (Link l : linksNonBcastNonTunnel.get(np)) {
                     if (isBlockedLink(l)) continue;
-                    if (isBroadcastDomainLink(l)) continue;
-                    Cluster c1 = switchClusterMap.get(l.getSrc());
-                    Cluster c2 = switchClusterMap.get(l.getDst());
-                    if (c1 ==c2) {
-                        c1.addLink(l);
+                    if (isBroadcastLink(l)) continue;
+                    Cluster c1 = clusterFromSwitch.get(l.getSrc());
+                    Cluster c2 = clusterFromSwitch.get(l.getDst());
+                    if (c1 == c2) {
+                        c1.addLink(l); /* link is within cluster */
+                    } else {
+                        linksNonExternalInterCluster.add(l);
                     }
                 }
             }
@@ -293,7 +254,7 @@ public class TopologyInstance {
      *
      * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
      */
-    public void identifyOpenflowDomains() {
+    private void identifyClusters() {
         Map<DatapathId, ClusterDFS> dfsList = new HashMap<DatapathId, ClusterDFS>();
 
         if (switches == null) return;
@@ -302,7 +263,7 @@ public class TopologyInstance {
             ClusterDFS cdfs = new ClusterDFS();
             dfsList.put(key, cdfs);
         }
-        
+
         Set<DatapathId> currSet = new HashSet<DatapathId>();
 
         for (DatapathId sw : switches) {
@@ -344,7 +305,7 @@ public class TopologyInstance {
      * @return long: DSF index to be used when a new node is visited
      */
     private long dfsTraverse (long parentIndex, long currIndex, DatapathId currSw,
-                              Map<DatapathId, ClusterDFS> dfsList, Set<DatapathId> currSet) {
+            Map<DatapathId, ClusterDFS> dfsList, Set<DatapathId> currSet) {
 
         //Get the DFS object corresponding to the current switch
         ClusterDFS currDFS = dfsList.get(currSw);
@@ -359,9 +320,9 @@ public class TopologyInstance {
         currIndex++;
 
         // Traverse the graph through every outgoing link.
-        if (switchPorts.get(currSw) != null){
-            for (OFPort p : switchPorts.get(currSw)) {
-                Set<Link> lset = switchPortLinks.get(new NodePortTuple(currSw, p));
+        if (portsWithLinks.get(currSw) != null){
+            for (OFPort p : portsWithLinks.get(currSw)) {
+                Set<Link> lset = linksNonBcastNonTunnel.get(new NodePortTuple(currSw, p));
                 if (lset == null) continue;
                 for (Link l : lset) {
                     DatapathId dstSw = l.getDst();
@@ -371,13 +332,13 @@ public class TopologyInstance {
 
                     // ignore if the destination is already added to
                     // another cluster
-                    if (switchClusterMap.get(dstSw) != null) continue;
+                    if (clusterFromSwitch.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;
+                    if (isBroadcastLink(l)) continue;
 
                     // Get the DFS object corresponding to the dstSw
                     ClusterDFS dstDFS = dfsList.get(dstSw);
@@ -390,9 +351,9 @@ public class TopologyInstance {
                     } else if (!dstDFS.isVisited()) {
                         // make a DFS visit
                         currIndex = dfsTraverse(
-                        		currDFS.getDfsIndex(), 
-                        		currIndex, dstSw, 
-                        		dfsList, myCurrSet);
+                                currDFS.getDfsIndex(), 
+                                currIndex, dstSw, 
+                                dfsList, myCurrSet);
 
                         if (currIndex < 0) return -1;
 
@@ -424,7 +385,7 @@ public class TopologyInstance {
             Cluster sc = new Cluster();
             for (DatapathId sw : currSet) {
                 sc.add(sw);
-                switchClusterMap.put(sw, sc);
+                clusterFromSwitch.put(sw, sc);
             }
             // delete all the nodes in the current set.
             currSet.clear();
@@ -436,11 +397,11 @@ public class TopologyInstance {
     }
 
     public Set<NodePortTuple> getBlockedPorts() {
-        return this.blockedPorts;
+        return this.portsBlocked;
     }
 
-    protected Set<Link> getBlockedLinks() {
-        return this.blockedLinks;
+    public Set<Link> getBlockedLinks() {
+        return this.linksBlocked;
     }
 
     /** Returns true if a link has either one of its switch ports
@@ -448,37 +409,37 @@ public class TopologyInstance {
      * @param l
      * @return
      */
-    protected boolean isBlockedLink(Link l) {
+    public 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);
+    public boolean isBlockedPort(NodePortTuple npt) {
+        return portsBlocked.contains(npt);
     }
 
-    protected boolean isTunnelPort(NodePortTuple npt) {
-        return tunnelPorts.contains(npt);
+    public boolean isTunnelPort(NodePortTuple npt) {
+        return portsTunnel.contains(npt);
     }
 
-    protected boolean isTunnelLink(Link l) {
+    public 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) {
+    public boolean isBroadcastLink(Link l) {
         NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
         NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort());
-        return (isBroadcastDomainPort(n1) || isBroadcastDomainPort(n2));
+        return (isBroadcastPort(n1) || isBroadcastPort(n2));
     }
 
-    public boolean isBroadcastDomainPort(NodePortTuple npt) {
-        return broadcastDomainPorts.contains(npt);
+    public boolean isBroadcastPort(NodePortTuple npt) {
+        return portsBroadcastAll.contains(npt);
     }
 
-    protected class NodeDist implements Comparable<NodeDist> {
+    private class NodeDist implements Comparable<NodeDist> {
         private final DatapathId node;
         public DatapathId getNode() {
             return node;
@@ -524,7 +485,7 @@ public class TopologyInstance {
         @Override
         public int hashCode() {
             assert false : "hashCode not designed";
-            return 42;
+        return 42;
         }
 
         private TopologyInstance getOuterType() {
@@ -532,43 +493,113 @@ public class TopologyInstance {
         }
     }
 
-	//calculates the broadcast tree in cluster. Old version of code.
-    protected BroadcastTree clusterDijkstra(Cluster c, DatapathId root,
-                                     Map<Link, Integer> linkCost,
-                                     boolean isDstRooted) {
-    	
+    private void identifyArchipelagos() {
+        // Iterate through each external link and create/merge archipelagos based on the
+        // islands that each link is connected to
+        Cluster srcCluster = null;
+        Cluster dstCluster = null;
+        Archipelago srcArchipelago = null;
+        Archipelago dstArchipelago = null;
+        Set<Link> links = new HashSet<Link>();
+
+        for (Set<Link> linkset : linksExternal.values()) {
+            links.addAll(linkset);
+        }
+        links.addAll(linksNonExternalInterCluster);
+
+        /* Base case of 1:1 mapping b/t clusters and archipelagos */
+        if (links.isEmpty()) {
+            if (!clusters.isEmpty()) {
+                clusters.forEach(c -> archipelagos.add(new Archipelago().add(c)));
+            }
+        } else { /* Only for two or more adjacent clusters that form archipelagos */
+            for (Link l : links) {
+                for (Cluster c : clusters) {
+                    if (c.getNodes().contains(l.getSrc())) srcCluster = c;
+                    if (c.getNodes().contains(l.getDst())) dstCluster = c;
+                }
+                for (Archipelago a : archipelagos) {
+                    // Is source cluster a part of an existing archipelago?
+                    if (a.isMember(srcCluster)) srcArchipelago = a;
+                    // Is destination cluster a part of an existing archipelago?
+                    if (a.isMember(dstCluster)) dstArchipelago = a;
+                }
+
+                // Are they both found in an archipelago? If so, then merge the two.
+                if (srcArchipelago != null && dstArchipelago != null && !srcArchipelago.equals(dstArchipelago)) {
+                    srcArchipelago.merge(dstArchipelago);
+                    archipelagos.remove(dstArchipelago);
+                    archipelagoFromCluster.put(dstCluster, srcArchipelago);
+                }
+
+                // If neither were found in an existing, then form a new archipelago.
+                else if (srcArchipelago == null && dstArchipelago == null) {
+                    Archipelago a = new Archipelago().add(srcCluster).add(dstCluster);
+                    archipelagos.add(a);
+                    archipelagoFromCluster.put(srcCluster, a);
+                    archipelagoFromCluster.put(dstCluster, a);
+                }
+
+                // If only one is found in an existing, then add the one not found to the existing.
+                else if (srcArchipelago != null && dstArchipelago == null) {
+                    srcArchipelago.add(dstCluster);
+                    archipelagoFromCluster.put(dstCluster, srcArchipelago);
+                }
+
+                else if (srcArchipelago == null && dstArchipelago != null) {
+                    dstArchipelago.add(srcCluster);
+                    archipelagoFromCluster.put(srcCluster, dstArchipelago);
+                }
+
+                srcCluster = null;
+                dstCluster = null;
+                srcArchipelago = null;
+                dstArchipelago = null;
+            }
+        }
+    }
+
+    /*
+     * Dijkstra that calculates destination rooted trees over the entire topology.
+     */
+    private BroadcastTree dijkstra(Map<DatapathId, Set<Link>> links, DatapathId root,
+            Map<Link, Integer> linkCost,
+            boolean isDstRooted) {
         HashMap<DatapathId, Link> nexthoplinks = new HashMap<DatapathId, Link>();
         HashMap<DatapathId, Integer> cost = new HashMap<DatapathId, Integer>();
         int w;
 
-        for (DatapathId node : c.links.keySet()) {
+        for (DatapathId node : links.keySet()) {
             nexthoplinks.put(node, null);
             cost.put(node, MAX_PATH_WEIGHT);
+            //log.debug("Added max cost to {}", node);
         }
 
         HashMap<DatapathId, Boolean> seen = new HashMap<DatapathId, Boolean>();
         PriorityQueue<NodeDist> nodeq = new PriorityQueue<NodeDist>();
-        
         nodeq.add(new NodeDist(root, 0));
         cost.put(root, 0);
-        
+
+        //log.debug("{}", links);
+
         while (nodeq.peek() != null) {
             NodeDist n = nodeq.poll();
             DatapathId cnode = n.getNode();
-            
             int cdist = n.getDist();
+
             if (cdist >= MAX_PATH_WEIGHT) break;
             if (seen.containsKey(cnode)) continue;
-            
             seen.put(cnode, true);
 
-            for (Link link : c.links.get(cnode)) {
+            //log.debug("cnode {} and links {}", cnode, links.get(cnode));
+            if (links.get(cnode) == null) continue;
+            for (Link link : links.get(cnode)) {
                 DatapathId neighbor;
 
                 if (isDstRooted == true) {
-                	neighbor = link.getSrc();
+                    neighbor = link.getSrc();
                 } else {
-                	neighbor = link.getDst();
+                    neighbor = link.getDst();
                 }
 
                 // links directed toward cnode will result in this condition
@@ -577,16 +608,20 @@ public class TopologyInstance {
                 if (seen.containsKey(neighbor)) continue;
 
                 if (linkCost == null || linkCost.get(link) == null) {
-                	w = 1;
+                    w = 1;
                 } else {
-                	w = linkCost.get(link);
+                    w = linkCost.get(link);
                 }
 
                 int ndist = cdist + w; // the weight of the link, always 1 in current version of floodlight.
+                log.debug("Neighbor: {}", neighbor);
+                log.debug("Cost: {}", cost);
+                log.debug("Neighbor cost: {}", cost.get(neighbor));
+
                 if (ndist < cost.get(neighbor)) {
                     cost.put(neighbor, ndist);
                     nexthoplinks.put(neighbor, link);
-                    
+
                     NodeDist ndTemp = new NodeDist(neighbor, ndist);
                     // Remove an object that's already in there.
                     // Note that the comparison is based on only the node id,
@@ -599,310 +634,163 @@ public class TopologyInstance {
         }
 
         BroadcastTree ret = new BroadcastTree(nexthoplinks, cost);
+
         return ret;
     }
 
-    private void calculateArchipelagos() {
-        // Iterate through each external link and create/merge archipelagos based on the
-        // islands that each link is connected to
-        Cluster srcCluster = null;
-        Cluster dstCluster = null;
-        Archipelago srcArchipelago = null;
-        Archipelago dstArchipelago = null;
-        Set<Link> links = new HashSet<Link>();
-
-        for (Set<Link> linkset : externalLinks.values()) {
-            links.addAll(linkset);
-        }
-        
-        /* Base case of 1:1 mapping b/t clusters and archipelagos */
-        if (links.isEmpty()) {
-        	if (!clusters.isEmpty()) {
-        		clusters.forEach(c -> archipelagos.add(new Archipelago().add(c)));
-        	}
-        } else { /* Only for two or more adjacent clusters that form archipelagos */
-            for (Link l : links) {
-                for (Cluster c : clusters) {
-                    if (c.getNodes().contains(l.getSrc())) srcCluster = c;
-                    if (c.getNodes().contains(l.getDst())) dstCluster = c;
-                }
-                for (Archipelago a : archipelagos) {
-                    // Is source cluster a part of an existing archipelago?
-                    if (a.isMember(srcCluster)) srcArchipelago = a;
-                    // Is destination cluster a part of an existing archipelago?
-                    if (a.isMember(dstCluster)) dstArchipelago = a;
-                }
-
-                // Are they both found in an archipelago? If so, then merge the two.
-                if (srcArchipelago != null && dstArchipelago != null && !srcArchipelago.equals(dstArchipelago)) {
-                    srcArchipelago.merge(dstArchipelago);
-                    archipelagos.remove(dstArchipelago);
-                }
-
-                // If neither were found in an existing, then form a new archipelago.
-                else if (srcArchipelago == null && dstArchipelago == null) {
-                    archipelagos.add(new Archipelago().add(srcCluster).add(dstCluster));
-                }
-
-                // If only one is found in an existing, then add the one not found to the existing.
-                else if (srcArchipelago != null && dstArchipelago == null) {
-                    srcArchipelago.add(dstCluster);
-                }
-
-                else if (srcArchipelago == null && dstArchipelago != null) {
-                    dstArchipelago.add(srcCluster);
+    /*
+     * Creates a map of links and the cost associated with each link
+     */
+    public Map<Link,Integer> initLinkCostMap() {
+        Map<Link, Integer> linkCost = new HashMap<Link, Integer>();
+        long rawLinkSpeed;
+        int linkSpeedMBps;
+        int tunnel_weight = portsWithLinks.size() + 1;
+
+        /* pathMetrics:
+         *  1: Hop Count (Default Metrics)
+         *  2: Hop Count (Treat Tunnels same as link)
+         *  3: Latency
+         *  4: Link Speed
+         */
+        switch (TopologyManager.getPathMetricInternal()){
+        case HOPCOUNT_AVOID_TUNNELS:
+            if(TopologyManager.collectStatistics == true){
+                TopologyManager.statisticsService.collectStatistics(false);
+                TopologyManager.collectStatistics = false;
+            }
+            log.debug("Using Default: Hop Count with Tunnel Bias for Metrics");
+            for (NodePortTuple npt : portsTunnel) {
+                if (links.get(npt) == null) continue;
+                for (Link link : links.get(npt)) {
+                    if (link == null) continue;
+                    linkCost.put(link, tunnel_weight);
                 }
+            }
+            return linkCost;
 
-                srcCluster = null;
-                dstCluster = null;
-                srcArchipelago = null;
-                dstArchipelago = null;
+        case HOPCOUNT:
+            if(TopologyManager.collectStatistics == true){
+                TopologyManager.statisticsService.collectStatistics(false);
+                TopologyManager.collectStatistics = false;
             }
-        }
-        
-        // Choose a broadcast tree for each archipelago
-        for (Archipelago a : archipelagos) {
-            for (DatapathId id : destinationRootedFullTrees.keySet()) {
-                if (a.isMember(id)) {
-                    a.setBroadcastTree(destinationRootedFullTrees.get(id));
-                    break;
+            log.debug("Using Hop Count without Tunnel Bias for Metrics");
+            for (NodePortTuple npt : links.keySet()) {
+                if (links.get(npt) == null) continue;
+                for (Link link : links.get(npt)) {
+                    if (link == null) continue;
+                    linkCost.put(link,1);
                 }
             }
-        }
-    }
-    
-	/*
-	 * Dijkstra that calculates destination rooted trees over the entire topology.
-	*/
-    protected BroadcastTree dijkstra(Map<DatapathId, Set<Link>> links, DatapathId root,
-            Map<Link, Integer> linkCost,
-            boolean isDstRooted) {
-    	HashMap<DatapathId, Link> nexthoplinks = new HashMap<DatapathId, Link>();
-    	HashMap<DatapathId, Integer> cost = new HashMap<DatapathId, Integer>();
-    	int w;
-    	
-    	for (DatapathId node : links.keySet()) {
-    		nexthoplinks.put(node, null);
-    		cost.put(node, MAX_PATH_WEIGHT);
-    	}
-		
-    	HashMap<DatapathId, Boolean> seen = new HashMap<DatapathId, Boolean>();
-    	PriorityQueue<NodeDist> nodeq = new PriorityQueue<NodeDist>();
-    	nodeq.add(new NodeDist(root, 0));
-    	cost.put(root, 0);
-    	
-    	while (nodeq.peek() != null) {
-    		NodeDist n = nodeq.poll();
-    		DatapathId cnode = n.getNode();
-    		int cdist = n.getDist();
-    		
-    		if (cdist >= MAX_PATH_WEIGHT) break;
-    		if (seen.containsKey(cnode)) continue;
-    		seen.put(cnode, true);
-
-    		for (Link link : links.get(cnode)) {
-    			DatapathId neighbor;
-
-    			if (isDstRooted == true) {
-    				neighbor = link.getSrc();
-    			} else {
-    				neighbor = link.getDst();
-    			}
-        
-    			// links directed toward cnode will result in this condition
-    			if (neighbor.equals(cnode)) continue;
-
-    			if (seen.containsKey(neighbor)) continue;
-
-    			if (linkCost == null || linkCost.get(link) == null) {
-    				w = 1;
-    			} else {
-    				w = linkCost.get(link);
-    			}
-    			
-    			int ndist = cdist + w; // the weight of the link, always 1 in current version of floodlight.
-    			if (ndist < cost.get(neighbor)) {
-    				cost.put(neighbor, ndist);
-    				nexthoplinks.put(neighbor, link);
-    				
-    				NodeDist ndTemp = new NodeDist(neighbor, ndist);
-    				// Remove an object that's already in there.
-    				// Note that the comparison is based on only the node id,
-    				// and not node id and distance.
-    				nodeq.remove(ndTemp);
-    				// add the current object to the queue.
-    				nodeq.add(ndTemp);
-    			}
-    		}
-    	}
-
-    	BroadcastTree ret = new BroadcastTree(nexthoplinks, cost);
-
-		return ret;
-	}
-	
-    /*
-	 * Modification of the calculateShortestPathTreeInClusters (dealing with whole topology, not individual clusters)
-	 */
-    public void calculateAllShortestPaths() {
-    	this.broadcastNodePorts.clear();
-    	this.destinationRootedFullTrees.clear();
-    	Map<Link, Integer> linkCost = new HashMap<Link, Integer>();
-        int tunnel_weight = switchPorts.size() + 1;
-		
-        for (NodePortTuple npt : tunnelPorts) {
-            if (allLinks.get(npt) == null) continue;
-            for (Link link : allLinks.get(npt)) {
-                if (link == null) continue;
-                linkCost.put(link, tunnel_weight);
+            return linkCost;
+
+        case LATENCY:
+            if(TopologyManager.collectStatistics == true){
+                TopologyManager.statisticsService.collectStatistics(false);
+                TopologyManager.collectStatistics = false;
             }
-        }
-        
-        Map<DatapathId, Set<Link>> linkDpidMap = new HashMap<DatapathId, Set<Link>>();
-        for (DatapathId s : switches) {
-            if (switchPorts.get(s) == null) continue;
-            for (OFPort p : switchPorts.get(s)) {
-                NodePortTuple np = new NodePortTuple(s, p);
-                if (allLinks.get(np) == null) continue;
-                for (Link l : allLinks.get(np)) {
-                	if (linkDpidMap.containsKey(s)) {
-                		linkDpidMap.get(s).add(l);
-                	}
-                	else {
-                		linkDpidMap.put(s, new HashSet<Link>(Arrays.asList(l)));
-                	}
+            log.debug("Using Latency for Route Metrics");
+            for (NodePortTuple npt : links.keySet()) {
+                if (links.get(npt) == null) continue;
+                for (Link link : links.get(npt)) {
+                    if (link == null) continue;
+                    if((int)link.getLatency().getValue() < 0 || (int)link.getLatency().getValue() > MAX_LINK_WEIGHT)
+                        linkCost.put(link, MAX_LINK_WEIGHT);
+                    else
+                        linkCost.put(link,(int)link.getLatency().getValue());
                 }
             }
-        }   
-        
-        for (DatapathId node : linkDpidMap.keySet()) {
-        	BroadcastTree tree = dijkstra(linkDpidMap, node, linkCost, true);
-            destinationRootedFullTrees.put(node, tree);
-        }
-        
-		//finiteBroadcastTree is randomly chosen in this implementation
-//        if (this.destinationRootedFullTrees.size() > 0) {
-//			this.finiteBroadcastTree = destinationRootedFullTrees.values().iterator().next();
-//        }
-    }
-
-    protected void calculateShortestPathTreeInClusters() {
-        pathcache.invalidateAll();
-        destinationRootedTrees.clear();
-
-        Map<Link, Integer> linkCost = new HashMap<Link, Integer>();
-        int tunnel_weight = switchPorts.size() + 1;
+            return linkCost;
 
-        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);
+        case LINK_SPEED:
+            if(TopologyManager.collectStatistics == false){
+                TopologyManager.statisticsService.collectStatistics(true);
+                TopologyManager.collectStatistics = true;
             }
-        }
-
-        for (Cluster c : clusters) {
-            for (DatapathId node : c.links.keySet()) {
-                BroadcastTree tree = clusterDijkstra(c, node, linkCost, true);
-                destinationRootedTrees.put(node, tree);
+            log.debug("Using Link Speed for Route Metrics");
+            for (NodePortTuple npt : links.keySet()) {
+                if (links.get(npt) == null) continue;
+                rawLinkSpeed = TopologyManager.statisticsService.getLinkSpeed(npt);
+                for (Link link : links.get(npt)) {
+                    if (link == null) continue;
+
+                    if((rawLinkSpeed / 10^6) / 8 > 1){
+                        linkSpeedMBps = (int)(rawLinkSpeed / 10^6) / 8;
+                        linkCost.put(link, (1/linkSpeedMBps)*1000);
+                    }
+                    else
+                        linkCost.put(link, MAX_LINK_WEIGHT);
+                }
             }
-        }
-    }
+            return linkCost;
 
-    protected void calculateBroadcastTreeInClusters() {
-        for (Cluster c : clusters) {
-            // c.id is the smallest node that's in the cluster
-            BroadcastTree tree = destinationRootedTrees.get(c.id);
-            clusterBroadcastTrees.put(c.id, tree);
-        }
-    }
-    
-	protected Set<NodePortTuple> getAllBroadcastNodePorts() {
-		return this.broadcastNodePorts;
-	}
-
-    protected void calculateAllBroadcastNodePorts() {
-        if (this.destinationRootedFullTrees.size() > 0) {
-            //this.finiteBroadcastTree = destinationRootedFullTrees.values().iterator().next();
-            for (Archipelago a : archipelagos) {
-                Map<DatapathId, Link> links = a.getBroadcastTree().getLinks();
-                if (links == null) return;
-                for (DatapathId nodeId : links.keySet()) {
-                    Link l = links.get(nodeId);
-                    if (l == null) continue;
-                    NodePortTuple npt1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
-                    NodePortTuple npt2 = new NodePortTuple(l.getDst(), l.getDstPort());
-                    this.broadcastNodePorts.add(npt1);
-                    this.broadcastNodePorts.add(npt2);
+        default:
+            if(TopologyManager.collectStatistics == true){
+                TopologyManager.statisticsService.collectStatistics(false);
+                TopologyManager.collectStatistics = false;
+            }
+            log.debug("Invalid Selection: Using Default Hop Count with Tunnel Bias for Metrics");
+            for (NodePortTuple npt : portsTunnel) {
+                if (links.get(npt) == null) continue;
+                for (Link link : links.get(npt)) {
+                    if (link == null) continue;
+                    linkCost.put(link, tunnel_weight);
                 }
             }
+            return linkCost;
         }
     }
 
-    protected void calculateBroadcastPortMap(){
-		this.broadcastPortMap.clear();
-
-		for (DatapathId sw : this.switches) {
-			for (OFPort p : this.allPorts.get(sw)){
-				NodePortTuple npt = new NodePortTuple(sw, p);
-				if (isEdge(sw, p) || broadcastNodePorts.contains(npt)) { 
-					if (broadcastPortMap.containsKey(sw)) {
-                		broadcastPortMap.get(sw).add(p);
-                	} else {
-                		broadcastPortMap.put(sw, new HashSet<OFPort>(Arrays.asList(p)));
-                	}
-				}      		
-			}
-		}
-    }
-	
-    protected void calculateBroadcastNodePortsInClusters() {
-        clusterBroadcastTrees.clear();
-        
-        calculateBroadcastTreeInClusters();
-
-        for (Cluster c : clusters) {
-            // c.id is the smallest node that's in the cluster
-            BroadcastTree tree = clusterBroadcastTrees.get(c.id);
-            //log.info("Broadcast Tree {}", tree);
-
-            Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
-            Map<DatapathId, Link> links = tree.getLinks();
-            if (links == null) continue;
-            for (DatapathId nodeId : links.keySet()) {
-                Link l = links.get(nodeId);
-                if (l == null) continue;
-                NodePortTuple npt1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
-                NodePortTuple npt2 = new NodePortTuple(l.getDst(), l.getDstPort());
-                nptSet.add(npt1);
-                nptSet.add(npt2);
+    /*
+     * Calculates and stores n possible paths  using Yen's algorithm,
+     * looping through every switch. These lists of routes are stored 
+     * in the pathcache.
+     */
+    private void computeOrderedPaths() {
+        List<Path> paths;
+        PathId pathId;
+        pathcache.clear();
+
+        for (Archipelago a : archipelagos) { /* for each archipelago */
+            Set<DatapathId> srcSws = a.getSwitches();
+            Set<DatapathId> dstSws = a.getSwitches();
+            log.debug("SRC {}", srcSws);
+            log.debug("DST {}", dstSws);
+
+            for (DatapathId src : srcSws) { /* permute all member switches */
+                for (DatapathId dst : dstSws) {
+                    log.debug("Calling Yens {} {}", src, dst);
+                    paths = yens(src, dst, TopologyManager.getMaxPathsToComputeInternal(),
+                            getArchipelago(src), getArchipelago(dst));
+                    pathId = new PathId(src, dst);
+                    pathcache.put(pathId, paths);
+                    log.debug("Adding paths {}", paths);
+                }
             }
-            clusterBroadcastNodePorts.put(c.id, nptSet);
         }
     }
 
-    protected Route buildroute(RouteId id) {
+    private Path buildPath(PathId id, BroadcastTree tree) {
         NodePortTuple npt;
         DatapathId srcId = id.getSrc();
         DatapathId dstId = id.getDst();
-		//set of NodePortTuples on the route
+        //set of NodePortTuples on the route
         LinkedList<NodePortTuple> sPorts = new LinkedList<NodePortTuple>();
 
-        if (destinationRootedFullTrees == null) return null;
-        if (destinationRootedFullTrees.get(dstId) == null) return null;
+        if (tree == null) return new Path(id, ImmutableList.of()); /* empty route */
 
-        Map<DatapathId, Link> nexthoplinks = destinationRootedFullTrees.get(dstId).getLinks();
+        Map<DatapathId, Link> nexthoplinks = tree.getLinks();
 
         if (!switches.contains(srcId) || !switches.contains(dstId)) {
             // This is a switch that is not connected to any other switch
             // hence there was no update for links (and hence it is not
             // in the network)
-            log.info("buildroute: Standalone switch: {}", srcId);
+            log.debug("buildpath: Standalone switch: {}", srcId);
 
             // The only possible non-null path for this case is
             // if srcId equals dstId --- and that too is an 'empty' path []
 
-        } else if ((nexthoplinks!=null) && (nexthoplinks.get(srcId) != null)) {
+        } else if ((nexthoplinks != null) && (nexthoplinks.get(srcId) != null)) {
             while (!srcId.equals(dstId)) {
                 Link l = nexthoplinks.get(srcId);
                 npt = new NodePortTuple(l.getSrc(), l.getSrcPort());
@@ -914,43 +802,367 @@ public class TopologyInstance {
         }
         // else, no path exists, and path equals null
 
-        Route result = null;
+        Path result = null;
         if (sPorts != null && !sPorts.isEmpty()) {
-            result = new Route(id, sPorts);
-        }
-        if (log.isTraceEnabled()) {
-            log.trace("buildroute: {}", result);
+            result = new Path(id, sPorts);
+
         }
-        return result;
+        log.trace("buildpath: {}", result);
+        return result == null ? new Path(id, ImmutableList.of()) : result;
     }
 
     /*
      * Getter Functions
      */
 
-    protected int getCost(DatapathId srcId, DatapathId dstId) {
-        BroadcastTree bt = destinationRootedTrees.get(dstId);
-        if (bt == null) return -1;
-        return bt.getCost(srcId);
-    }
-    
-    protected Set<Cluster> getClusters() {
-        return clusters;
-    }
+    public boolean pathExists(DatapathId srcId, DatapathId dstId) {
+        Archipelago srcA = getArchipelago(srcId);
+        Archipelago dstA = getArchipelago(dstId);
+        if (!srcA.getId().equals(dstA.getId())) {
+            return false;
+        }
+
+        BroadcastTree bt = srcA.getBroadcastTree();
+        if (bt == null) {
+            return false;
+        }
 
-    protected boolean routeExists(DatapathId srcId, DatapathId dstId) {
-        BroadcastTree bt = destinationRootedTrees.get(dstId);
-        if (bt == null) return false;
         Link link = bt.getLinks().get(srcId);
-        if (link == null) return false;
+        if (link == null) {
+            return false;
+        }
         return true;
     }
 
-	/*
-	* Calculates E2E route
-	*/
-    protected Route getRoute(DatapathId srcId, OFPort srcPort,
-            DatapathId dstId, OFPort dstPort, U64 cookie) {
+    private Map<DatapathId, Set<Link>> buildLinkDpidMap(Set<DatapathId> switches, Map<DatapathId,
+            Set<OFPort>> portsWithLinks, Map<NodePortTuple, Set<Link>> links) {
+
+        Map<DatapathId, Set<Link>> linkDpidMap = new HashMap<DatapathId, Set<Link>>();
+        for (DatapathId s : switches) {
+            if (portsWithLinks.get(s) == null) continue;
+            for (OFPort p : portsWithLinks.get(s)) {
+                NodePortTuple np = new NodePortTuple(s, p);
+                if (links.get(np) == null) continue;
+                for (Link l : links.get(np)) {
+                    if (switches.contains(l.getSrc()) && switches.contains(l.getDst())) {
+                        if (linkDpidMap.containsKey(s)) {
+                            linkDpidMap.get(s).add(l);
+                        } else {
+                            linkDpidMap.put(s, new HashSet<Link>(Arrays.asList(l)));
+                        }
+                    }
+                }
+            }
+        }
+
+        return linkDpidMap;
+    }
+
+    /**
+     *
+     * This function returns K number of routes between a source and destination IF THEY EXIST IN THE ROUTECACHE.
+     * If the user requests more routes than available, only the routes already stored in memory will be returned.
+     * This value can be adjusted in floodlightdefault.properties.
+     *
+     *
+     * @param src: DatapathId of the route source.
+     * @param dst: DatapathId of the route destination.
+     * @param k: The number of routes that you want. Must be positive integer.
+     * @return ArrayList of Routes or null if bad parameters
+     */
+    public List<Path> getPathsFast(DatapathId src, DatapathId dst, int k) {
+        PathId routeId = new PathId(src, dst);
+        List<Path> routes = pathcache.get(routeId);
+
+        if (routes == null || k < 1) {
+            return ImmutableList.of();
+        }
+
+        if (k >= TopologyManager.getMaxPathsToComputeInternal() || k >= routes.size()) {
+            return routes;
+        } else {
+            return routes.subList(0, k);
+        }
+    }
+
+    /**
+     *
+     * This function returns K number of paths between a source and destination. It will attempt to retrieve
+     * these paths from the pathcache. If the user requests more paths than are stored, Yen's algorithm will be
+     * run using the K value passed in.
+     *
+     *
+     * @param src: DatapathId of the path source.
+     * @param dst: DatapathId of the path destination.
+     * @param k: The number of path that you want. Must be positive integer.
+     * @return list of paths or empty
+     */
+    public List<Path> getPathsSlow(DatapathId src, DatapathId dst, int k) {
+        PathId pathId = new PathId(src, dst);
+        List<Path> paths = pathcache.get(pathId);
+
+        if (paths == null || k < 1) return ImmutableList.of();
+
+        if (k >= TopologyManager.getMaxPathsToComputeInternal() || k >= paths.size()) {
+            return yens(src, dst, k, getArchipelago(src), getArchipelago(dst)); /* heavy computation */
+        }
+        else {
+            return new ArrayList<Path>(paths.subList(0, k));
+        }
+    }
+
+    private Archipelago getArchipelago(DatapathId d) {
+        for (Archipelago a : archipelagos) {
+            if (a.getSwitches().contains(d)) {
+                return a;
+            }
+        }
+        return null;
+    }
+
+    public void setPathCosts(Path p) {
+        U64 cost = U64.ZERO;
+
+        // Set number of hops. Assuming the list of NPTs is always even.
+        p.setHopCount(p.getPath().size()/2);
+
+        for (int i = 0; i <= p.getPath().size() - 2; i = i + 2) {
+            DatapathId src = p.getPath().get(i).getNodeId();
+            DatapathId dst = p.getPath().get(i + 1).getNodeId();
+            OFPort srcPort = p.getPath().get(i).getPortId();
+            OFPort dstPort = p.getPath().get(i + 1).getPortId();
+            for (Link l : links.get(p.getPath().get(i))) {
+                if (l.getSrc().equals(src) && l.getDst().equals(dst) &&
+                        l.getSrcPort().equals(srcPort) && l.getDstPort().equals(dstPort)) {
+                    log.debug("Matching link found: {}", l);
+                    cost = cost.add(l.getLatency());
+                }
+            }
+        }
+
+        p.setLatency(cost);
+        log.debug("Total cost is {}", cost);
+        log.debug(p.toString());
+
+    }
+
+    private List<Path> yens(DatapathId src, DatapathId dst, Integer K, Archipelago aSrc, Archipelago aDst) {
+
+        log.debug("YENS ALGORITHM -----------------");
+        log.debug("Asking for paths from {} to {}", src, dst);
+        log.debug("Asking for {} paths", K);
+
+        // Find link costs
+        Map<Link, Integer> linkCost = initLinkCostMap();
+
+        Map<DatapathId, Set<Link>> linkDpidMap = buildLinkDpidMap(switches, portsWithLinks, links);
+
+        Map<DatapathId, Set<Link>> copyOfLinkDpidMap = new HashMap<DatapathId, Set<Link>>(linkDpidMap);
+
+        // A is the list of shortest paths. The number in the list at the end should be less than or equal to K
+        // B is the list of possible shortest paths found in this function.
+        List<Path> A = new ArrayList<Path>();
+        List<Path> B = new ArrayList<Path>();
+
+        // The number of paths requested should never be less than 1.
+        if (K < 1) {
+            return A;
+        }
+
+        /* The switch is not a member of an archipelago. It must not be connected */
+        if (aSrc == null || aDst == null) {
+            log.warn("One or more switches not connected. Cannot compute path b/t {} and {}", src, dst);
+            return A;
+        }
+
+        if (!aSrc.equals(aDst)) {
+            log.warn("Switches {} and {} not in same archipelago. Cannot compute path", src, dst);
+            return A;
+        }
+
+        /* Use Dijkstra's to find the shortest path, which will also be the first path in A */
+        BroadcastTree bt = dijkstra(copyOfLinkDpidMap, dst, linkCost, true);
+        /* add this initial tree as our archipelago's broadcast tree (aSrc == aDst) */
+        aSrc.setBroadcastTree(bt);
+        /* now add the shortest path */
+        log.debug("src {} dst {} tree {}", new Object[] {src, dst, bt});
+        Path newroute = buildPath(new PathId(src, dst), bt); /* guaranteed to be in same tree */
+
+        if (newroute != null && !newroute.getPath().isEmpty()) { /* should never be null, but might be empty */
+            setPathCosts(newroute);
+            A.add(newroute);
+            log.debug("Found shortest path in Yens {}", newroute);
+        }
+        else {
+            log.debug("No paths found in Yen's!");
+            return A;
+        }
+
+        // Loop through K - 1 times to get other possible shortest paths
+        for (int k = 1; k < K; k++) {
+            log.trace("k: {}", k);
+            if (log.isTraceEnabled()){
+                log.trace("Path Length 'A.get(k-1).getPath().size()-2': {}", A.get(k - 1).getPath().size() - 2);
+            }
+            // Iterate through i, which is the number of links in the most recent path added to A
+            for (int i = 0; i <= A.get(k - 1).getPath().size() - 2; i = i + 2) {
+                log.trace("i: {}", i);
+                List<NodePortTuple> path = A.get(k - 1).getPath();
+                //log.debug("A(k-1): {}", A.get(k - 1).getPath());
+                // The spur node is the point in the topology where Dijkstra's is called again to find another path
+                DatapathId spurNode = path.get(i).getNodeId();
+                // rootPath is the path along the previous shortest path that is before the spur node
+                Path rootPath = new Path(new PathId(path.get(0).getNodeId(), path.get(i).getNodeId()),
+                        path.subList(0, i));
+
+
+                Map<NodePortTuple, Set<Link>> allLinksCopy = new HashMap<NodePortTuple, Set<Link>>(links);
+                // Remove the links after the spur node that are part of other paths in A so that new paths
+                // found are unique
+                for (Path r : A) {
+                    if (r.getPath().size() > (i + 1) && r.getPath().subList(0, i).equals(rootPath.getPath())) {
+                        allLinksCopy.remove(r.getPath().get(i));
+                        allLinksCopy.remove(r.getPath().get(i+1));
+                    }
+                }
+
+                // Removes the root path so Dijkstra's doesn't try to go through it to find a path
+                Set<DatapathId> switchesCopy = new HashSet<DatapathId>(switches);
+                for (NodePortTuple npt : rootPath.getPath()) {
+                    if (!npt.getNodeId().equals(spurNode)) {
+                        switchesCopy.remove(npt.getNodeId());
+                    }
+                }
+
+                // Builds the new topology without the parts we want removed
+                copyOfLinkDpidMap = buildLinkDpidMap(switchesCopy, portsWithLinks, allLinksCopy);
+
+                // Uses Dijkstra's to try to find a shortest path from the spur node to the destination
+                Path spurPath = buildPath(new PathId(spurNode, dst), dijkstra(copyOfLinkDpidMap, dst, linkCost, true));
+                if (spurPath == null || spurPath.getPath().isEmpty()) {
+                    log.debug("spurPath is null");
+                    continue;
+                }
+
+                // Adds the root path and spur path together to get a possible shortest path
+                List<NodePortTuple> totalNpt = new LinkedList<NodePortTuple>();
+                totalNpt.addAll(rootPath.getPath());
+                totalNpt.addAll(spurPath.getPath());
+                Path totalPath = new Path(new PathId(src, dst), totalNpt);
+                setPathCosts(totalPath);
+
+                log.trace("Spur Node: {}", spurNode);
+                log.trace("Root Path: {}", rootPath);
+                log.trace("Spur Path: {}", spurPath);
+                log.trace("Total Path: {}", totalPath);
+                // Adds the new path into B
+                int flag = 0;
+                for (Path r_B : B) {
+                    for (Path r_A : A) {
+                        if (r_B.getPath().equals(totalPath.getPath()) || r_A.getPath().equals(totalPath.getPath())) {
+                            flag = 1;
+                        }
+                    }
+                }
+                if (flag == 0) {
+                    B.add(totalPath);
+                }
+
+                // Restore edges and nodes to graph
+            }
+
+            // If we get out of the loop and there isn't a path in B to add to A, all possible paths have been
+            // found and return A
+            if (B.isEmpty()) {
+                //log.debug("B list is empty in Yen's");
+                break;
+            }
+
+            log.debug("Removing shortest path from {}", B);
+            // Find the shortest path in B, remove it, and put it in A
+            log.debug("--------------BEFORE------------------------");
+            for (Path r : B) {
+                log.debug(r.toString());
+            }
+            log.debug("--------------------------------------------");
+            Path shortestPath = removeShortestPath(B, linkCost);
+            log.debug("--------------AFTER------------------------");
+            for (Path r : B) {
+                log.debug(r.toString());
+            }
+            log.debug("--------------------------------------------");
+
+            if (shortestPath != null) {
+                log.debug("Adding new shortest path to {} in Yen's", shortestPath);
+                A.add(shortestPath);
+                log.debug("A: {}", A);
+            }
+            else {
+                log.debug("removeShortestPath returned {}", shortestPath);
+            }
+        }
+
+        // Set the route counts
+        for (Path path : A) {
+            path.setPathIndex(A.indexOf(path));
+        }
+        //log.debug("END OF YEN'S --------------------");
+        return A;
+    }
+
+    private Path removeShortestPath(List<Path> routes, Map<Link, Integer> linkCost) {
+        log.debug("REMOVE SHORTEST PATH -------------");
+        // If there is nothing in B, return
+        if(routes == null){
+            log.debug("Routes == null");
+            return null;
+        }
+        Path shortestPath = null;
+        // Set the default shortest path to the max value
+        Integer shortestPathCost = Integer.MAX_VALUE;
+
+        // Iterate through B and find the shortest path
+        for (Path r : routes) {
+            Integer pathCost = 0;
+            // Add up the weights of each link in the path
+            // TODO Get the path cost from the route object
+            for (NodePortTuple npt : r.getPath()) {
+                if (links.get(npt) == null || linkCost.get(links.get(npt).iterator().next()) == null) {
+                    pathCost++;
+                }
+                else {
+                    pathCost += linkCost.get(links.get(npt).iterator().next());
+                }
+            }
+            log.debug("Path {} with cost {}", r, pathCost);
+            // If it is smaller than the current smallest, replace variables with the path just found
+            if (pathCost < shortestPathCost) {
+                log.debug("New shortest path {} with cost {}", r, pathCost);
+                shortestPathCost = pathCost;
+                shortestPath = r;
+            }
+        }
+
+        log.debug("Remove {} from {}", shortestPath, routes);
+        // Remove the route from B and return it
+        routes.remove(shortestPath);
+
+        log.debug("Shortest path: {}", shortestPath);
+        return shortestPath;
+    }
+
+    /**
+     * Computes end-to-end path including src/dst switch
+     * ports in addition to the switches. This chains into
+     * {@link #getPath(DatapathId, DatapathId)} below.
+     * @param srcId
+     * @param srcPort
+     * @param dstId
+     * @param dstPort
+     * @return
+     */
+    public Path getPath(DatapathId srcId, OFPort srcPort,
+            DatapathId dstId, OFPort dstPort) {
         // Return null if the route source and destination are the
         // same switch ports.
         if (srcId.equals(dstId) && srcPort.equals(dstPort)) {
@@ -959,9 +1171,9 @@ public class TopologyInstance {
 
         List<NodePortTuple> nptList;
         NodePortTuple npt;
-        Route r = getRoute(srcId, dstId, U64.of(0));
+        Path r = getPath(srcId, dstId);
         if (r == null && !srcId.equals(dstId)) {
-        	return null;
+            return null;
         }
 
         if (r != null) {
@@ -974,144 +1186,132 @@ public class TopologyInstance {
         npt = new NodePortTuple(dstId, dstPort);
         nptList.add(npt); // add dst port to the end
 
-        RouteId id = new RouteId(srcId, dstId);
-        r = new Route(id, nptList);
+        PathId id = new PathId(srcId, dstId);
+        r = new Path(id, nptList);
         return r;
     }
-    
 
-    // NOTE: Return a null route if srcId equals dstId.  The null route
-    // need not be stored in the cache.  Moreover, the LoadingCache will
-    // throw an exception if null route is returned.
-    protected Route getRoute(DatapathId srcId, DatapathId dstId, U64 cookie) {
+
+    /**
+     * Get the fastest path from the pathcache.
+     * @param srcId
+     * @param dstId
+     * @return
+     */
+
+    public Path getPath(DatapathId srcId, DatapathId dstId) {
         // Return null route if srcId equals dstId
         if (srcId.equals(dstId)) return null;
 
-        RouteId id = new RouteId(srcId, dstId);
-        Route result = null;
+        PathId id = new PathId(srcId, dstId);
+        Path result = null;
 
         try {
-            result = pathcache.get(id);
+            if (!pathcache.get(id).isEmpty()) {
+                result = pathcache.get(id).get(0);
+            }
         } catch (Exception e) {
             log.warn("Could not find route from {} to {}. If the path exists, wait for the topology to settle, and it will be detected", srcId, dstId);
         }
 
         if (log.isTraceEnabled()) {
-            log.trace("getRoute: {} -> {}", id, result);
+            log.trace("getPath: {} -> {}", id, result);
         }
-        return result;
-    }
-
-    protected BroadcastTree getBroadcastTreeForCluster(long clusterId){
-        Cluster c = switchClusterMap.get(clusterId);
-        if (c == null) return null;
-        return clusterBroadcastTrees.get(c.id);
+        return result == null ? new Path(id, ImmutableList.of()) : result; /* return empty route instead of null */
     }
 
     //
     //  ITopologyService interface method helpers.
     //
 
-    protected boolean isInternalToOpenflowDomain(DatapathId switchid, OFPort port) {
+    public boolean isInternalLinkInCluster(DatapathId switchid, OFPort port) {
         return !isAttachmentPointPort(switchid, port);
     }
 
     public boolean isAttachmentPointPort(DatapathId switchid, OFPort port) {
         NodePortTuple npt = new NodePortTuple(switchid, port);
-        if (switchPortLinks.containsKey(npt)) return false;
+        if (linksNonBcastNonTunnel.containsKey(npt)) {
+            return false;
+        }
         return true;
     }
 
-    protected DatapathId getOpenflowDomainId(DatapathId switchId) {
-        Cluster c = switchClusterMap.get(switchId);
-        if (c == null) return switchId;
-        return c.getId();
+    public DatapathId getClusterId(DatapathId switchId) {
+        Cluster c = clusterFromSwitch.get(switchId);
+        if (c != null) { 
+            return c.getId();
+        }
+        return switchId;
     }
 
-    protected DatapathId getL2DomainId(DatapathId switchId) {
-        return getOpenflowDomainId(switchId);
+    public DatapathId getArchipelagoId(DatapathId switchId) {
+        Cluster c = clusterFromSwitch.get(switchId);
+        if (c != null) {
+            return archipelagoFromCluster.get(c).getId();
+        }
+        return switchId;
     }
 
-    protected Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchId) {
-        Cluster c = switchClusterMap.get(switchId);
-        if (c == null) {
-            // The switch is not known to topology as there
-            // are no links connected to it.
-            Set<DatapathId> nodes = new HashSet<DatapathId>();
-            nodes.add(switchId);
-            return nodes;
+    public Set<DatapathId> getSwitchesInCluster(DatapathId switchId) {
+        Cluster c = clusterFromSwitch.get(switchId);
+        if (c != null) {
+            return c.getNodes();
         }
-        return (c.getNodes());
+        /* The switch is not known to topology as there are no links connected to it. */
+        return ImmutableSet.of(switchId);
     }
 
-    protected boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2) {
-        Cluster c1 = switchClusterMap.get(switch1);
-        Cluster c2 = switchClusterMap.get(switch2);
-        if (c1 != null && c2 != null)
-            return (c1.getId().equals(c2.getId()));
+    public boolean isInSameCluster(DatapathId switch1, DatapathId switch2) {
+        Cluster c1 = clusterFromSwitch.get(switch1);
+        Cluster c2 = clusterFromSwitch.get(switch2);
+        if (c1 != null && c2 != null) {
+            return c1.getId().equals(c2.getId());
+        }
         return (switch1.equals(switch2));
     }
 
-    public boolean isAllowed(DatapathId sw, OFPort portId) {
-        return true;
+    public boolean isNotBlocked(DatapathId sw, OFPort portId) {
+        return !isBlockedPort(new NodePortTuple(sw, portId));
     }
 
     /*
-	 * Takes finiteBroadcastTree into account to prevent loops in the network
-	 */
-    protected boolean isIncomingBroadcastAllowedOnSwitchPort(DatapathId sw, OFPort portId) {
+     * Takes finiteBroadcastTree into account to prevent loops in the network
+     */
+    public boolean isBroadcastAllowedOnSwitchPort(DatapathId sw, OFPort portId) {
         if (!isEdge(sw, portId)){       
             NodePortTuple npt = new NodePortTuple(sw, portId);
-            if (broadcastNodePorts.contains(npt))
+            if (portsBroadcastAll.contains(npt))
                 return true;
             else return false;
         }
         return true;
     }
 
-
     public boolean isConsistent(DatapathId oldSw, OFPort oldPort, DatapathId newSw, OFPort newPort) {
-        if (isInternalToOpenflowDomain(newSw, newPort)) return true;
+        if (isInternalLinkInCluster(newSw, newPort)) return true;
         return (oldSw.equals(newSw) && oldPort.equals(newPort));
     }
 
-    protected Set<NodePortTuple> getBroadcastNodePortsInCluster(DatapathId sw) {
-        DatapathId clusterId = getOpenflowDomainId(sw);
-        return clusterBroadcastNodePorts.get(clusterId);
-    }
-
-    public boolean inSameBroadcastDomain(DatapathId s1, OFPort p1, DatapathId s2, OFPort p2) {
+    public boolean isInSameArchipelago(DatapathId s1, DatapathId s2) {
+        for (Archipelago a : archipelagos) {
+            if (a.getSwitches().contains(s1) && a.getSwitches().contains(s2)) {
+                return true;
+            }
+        }
         return false;
     }
 
-    public boolean inSameL2Domain(DatapathId switch1, DatapathId switch2) {
-        return inSameOpenflowDomain(switch1, switch2);
-    }
-
-    public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
-            DatapathId dst, OFPort dstPort) {
-        // Use this function to redirect traffic if needed.
-        return new NodePortTuple(dst, dstPort);
-    }
-
-    public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
-            DatapathId dst, OFPort dstPort) {
-        // Use this function to reinject traffic from a
-        // different port if needed.
-        return new NodePortTuple(src, srcPort);
-    }
-
     public Set<DatapathId> getSwitches() {
         return switches;
     }
 
     public Set<OFPort> getPortsWithLinks(DatapathId sw) {
-        return switchPorts.get(sw);
+        return portsWithLinks.get(sw);
     }
 
     public Set<OFPort> getBroadcastPorts(DatapathId targetSw, DatapathId src, OFPort srcPort) {
         Set<OFPort> result = new HashSet<OFPort>();
-        DatapathId clusterId = getOpenflowDomainId(targetSw);
+        DatapathId clusterId = getClusterId(targetSw);
         for (NodePortTuple npt : clusterPorts.get(clusterId)) {
             if (npt.getNodeId().equals(targetSw)) {
                 result.add(npt.getPortId());
@@ -1120,11 +1320,93 @@ public class TopologyInstance {
         return result;
     }
 
-    public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort) {
-        return null;
+    public Set<Link> getInternalInterClusterLinks() {
+        return linksNonExternalInterCluster;
     }
 
-    public NodePortTuple getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort) {
-        return null;
+    public Set<NodePortTuple> getAllBroadcastPorts() {
+        return portsBroadcastAll;
+    }
+
+    public Set<DatapathId> getClusterIdsInArchipelago(DatapathId sw) {
+        Archipelago a = getArchipelago(sw);
+        if (a != null) {
+            return a.getClusters().stream().map(c -> c.getId()).collect(Collectors.toSet());
+        }
+        return ImmutableSet.of();
+    }
+
+    private void addBroadcastPortToPerSwitchMap(NodePortTuple npt) {
+        if (portsBroadcastPerSwitch.containsKey(npt.getNodeId())) {
+            portsBroadcastPerSwitch.get(npt.getNodeId()).add(npt.getPortId());
+        } else {
+            portsBroadcastPerSwitch.put(npt.getNodeId(), 
+                    new HashSet<OFPort>(Arrays.asList(npt.getPortId())));
+        }
+    }
+
+    private void computeBroadcastPortsPerArchipelago() {      
+        Set<NodePortTuple> s;
+        for (Archipelago a : archipelagos) {
+            s = new HashSet<NodePortTuple>();
+            for (Entry<DatapathId, Link> e : a.getBroadcastTree().getLinks().entrySet()) {
+                Link l = e.getValue();
+                if (l != null) { /* null indicates root node (leads nowhere "up") */
+                    NodePortTuple src = new NodePortTuple(l.getSrc(), l.getSrcPort());
+                    NodePortTuple dst = new NodePortTuple(l.getDst(), l.getDstPort());
+                    
+                    /* Accumulate for per-archipelago NPT map */
+                    s.add(src);
+                    s.add(dst);
+
+                    /* Add to global NPT set */
+                    this.portsBroadcastAll.add(src);
+                    this.portsBroadcastAll.add(dst);
+
+                    /* Add to per-switch NPT map */
+                    addBroadcastPortToPerSwitchMap(src);
+                    addBroadcastPortToPerSwitchMap(dst);
+                }
+            }
+
+            /* Set accumulated per-this-archipelago NPTs */
+            portsBroadcastPerArchipelago.put(a.getId(), s); /* guaranteed non-null set per archipelago */
+        }
+
+        /* Add ports that hosts connect to */
+        for (DatapathId sw : this.switches) {
+            for (OFPort p : this.portsPerSwitch.get(sw)) { /* includes edge and link ports */
+                NodePortTuple npt = new NodePortTuple(sw, p);
+                if (isEdge(sw, p)) {
+                    /* Add to per-archipelago NPT map */
+                    DatapathId aId = getArchipelago(sw).getId();
+                    if (portsBroadcastPerArchipelago.containsKey(aId)) {
+                        portsBroadcastPerArchipelago.get(aId).add(npt);
+                    } else {
+                        s = new HashSet<NodePortTuple>();
+                        s.add(npt);
+                        portsBroadcastPerArchipelago.put(aId, s);
+                    }
+
+                    /* Add to global NPT set */
+                    this.portsBroadcastAll.add(npt);
+
+                    /* Add to per-switch NPT map */
+                    addBroadcastPortToPerSwitchMap(npt);
+                }
+            }
+        }
+    }
+
+    public Set<NodePortTuple> getBroadcastPortsInArchipelago(DatapathId sw) {
+        Archipelago a = getArchipelago(sw);
+        if (a != null) {
+            return portsBroadcastPerArchipelago.get(a.getId());
+        }
+        return ImmutableSet.of();
+    }
+    
+    public Set<DatapathId> getArchipelagoIds() {
+        return archipelagos.stream().map(a -> a.getId()).collect(Collectors.toSet());
     }
-}
\ No newline at end of file
+} 
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
index 39211be7371b7729fbe75336c09111c4650948d4..ffeb928fda25e0826ee39b0ee0576026734901fe 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
@@ -28,27 +28,28 @@ import net.floodlightcontroller.debugcounter.IDebugCounter;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
+import net.floodlightcontroller.linkdiscovery.Link;
 import net.floodlightcontroller.packet.BSN;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.LLDP;
 import net.floodlightcontroller.restserver.IRestApiService;
-import net.floodlightcontroller.routing.IRoutingDecisionChangedListener;
-import net.floodlightcontroller.routing.IRoutingService;
-import net.floodlightcontroller.routing.Link;
-import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.IRoutingService.PATH_METRIC;
+import net.floodlightcontroller.routing.web.RoutingWebRoutable;
+import net.floodlightcontroller.statistics.IStatisticsService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.topology.web.TopologyWebRoutable;
 import org.projectfloodlight.openflow.protocol.*;
 import org.projectfloodlight.openflow.protocol.action.OFAction;
 import org.projectfloodlight.openflow.protocol.match.MatchField;
 import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.Masked;
 import org.projectfloodlight.openflow.types.OFBufferId;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.U64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableSet;
+
 import java.util.*;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -60,1229 +61,1077 @@ import java.util.concurrent.TimeUnit;
  * of the network graph, as well as implementing tools for finding routes
  * through the topology.
  */
-public class TopologyManager implements IFloodlightModule, ITopologyService, IRoutingService, ILinkDiscoveryListener, IOFMessageListener {
-	protected static Logger log = LoggerFactory.getLogger(TopologyManager.class);
-	public static final String MODULE_NAME = "topology";
-
-	/**
-	 * Role of the controller.
-	 */
-	private HARole role;
-
-	/**
-	 * Set of ports for each switch
-	 */
-	protected Map<DatapathId, Set<OFPort>> 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.
-	 */
-	protected Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks;
-
-	/**
-	 * set of tunnel links
-	 */
-	protected Set<NodePortTuple> tunnelPorts;
-
-	protected ILinkDiscoveryService linkDiscoveryService;
-	protected IThreadPoolService threadPoolService;
-	protected IFloodlightProviderService floodlightProviderService;
-	protected IOFSwitchService switchService;
-	protected IRestApiService restApiService;
-	protected IDebugCounterService debugCounterService;
-
-	// Modules that listen to our updates
-	protected ArrayList<ITopologyListener> topologyAware;
-
-	protected BlockingQueue<LDUpdate> ldUpdates;
-
-	// These must be accessed using getCurrentInstance(), not directly
-	protected TopologyInstance currentInstance;
-	protected TopologyInstance currentInstanceWithoutTunnels;
-
-	protected SingletonTask newInstanceTask;
-	private Date lastUpdateTime;
-
-	/**
-	 * Flag that indicates if links (direct/tunnel/multihop links) were
-	 * updated as part of LDUpdate.
-	 */
-	protected boolean linksUpdated;
-	/**
-	 * Flag that indicates if direct or tunnel links were updated as
-	 * part of LDUpdate.
-	 */
-	protected boolean dtLinksUpdated;
-
-	/** Flag that indicates if tunnel ports were updated or not
-	 */
-	protected boolean tunnelPortsUpdated;
-
-	protected int TOPOLOGY_COMPUTE_INTERVAL_MS = 500;
-
-	private IHAListener haListener;
-
-	/**
-	 *  Debug Counters
-	 */
-	protected static final String PACKAGE = TopologyManager.class.getPackage().getName();
-	protected IDebugCounter ctrIncoming;
-	
-	/** Array list that contains all of the decisionChangedListeners */
-	protected ArrayList<IRoutingDecisionChangedListener> decisionChangedListeners;
-
-	//  Getter/Setter methods
-	/**
-	 * Get the time interval for the period topology updates, if any.
-	 * The time returned is in milliseconds.
-	 * @return
-	 */
-	public int getTopologyComputeInterval() {
-		return TOPOLOGY_COMPUTE_INTERVAL_MS;
-	}
-
-	/**
-	 * Set the time interval for the period topology updates, if any.
-	 * The time is in milliseconds.
-	 * @return
-	 */
-	public void setTopologyComputeInterval(int time_ms) {
-		TOPOLOGY_COMPUTE_INTERVAL_MS = time_ms;
-	}
-
-	/**
-	 * Thread for recomputing topology.  The thread is always running,
-	 * however the function applyUpdates() has a blocking call.
-	 */
-	protected class UpdateTopologyWorker implements Runnable {
-		@Override
-		public void run() {
-			try {
-				if (ldUpdates.peek() != null) {
-					updateTopology();
-				}
-				handleMiscellaneousPeriodicEvents();
-			}
-			catch (Exception e) {
-				log.error("Error in topology instance task thread", e);
-			} finally {
-				if (floodlightProviderService.getRole() != HARole.STANDBY) {
-					newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, TimeUnit.MILLISECONDS);
-				}
-			}
-		}
-	}
-
-	// To be used for adding any periodic events that's required by topology.
-	protected void handleMiscellaneousPeriodicEvents() {
-		return;
-	}
-
-	public boolean updateTopology() {
-		boolean newInstanceFlag;
-		linksUpdated = false;
-		dtLinksUpdated = false;
-		tunnelPortsUpdated = false;
-		List<LDUpdate> appliedUpdates = applyUpdates();
-		newInstanceFlag = createNewInstance("link-discovery-updates");
-		lastUpdateTime = new Date();
-		informListeners(appliedUpdates);
-		return newInstanceFlag;
-	}
-
-	// **********************
-	// ILinkDiscoveryListener
-	// **********************
-
-	@Override
-	public void linkDiscoveryUpdate(List<LDUpdate> updateList) {
-		if (log.isTraceEnabled()) {
-			log.trace("Queuing update: {}", updateList);
-		}
-		ldUpdates.addAll(updateList);
-	}
-
-	// ****************
-	// ITopologyService
-	// ****************
-
-	@Override
-	public Map<DatapathId, Set<Link>> getAllLinks(){
-
-		Map<DatapathId, Set<Link>> dpidLinks = new HashMap<DatapathId, Set<Link>>();
-		TopologyInstance ti = getCurrentInstance(true);
-		Set<DatapathId> switches = ti.getSwitches();
-
-		for(DatapathId s: switches) {
-			if (this.switchPorts.get(s) == null) continue;
-			for (OFPort p: switchPorts.get(s)) {
-				NodePortTuple np = new NodePortTuple(s, p);
-				if (this.switchPortLinks.get(np) == null) continue;
-				for(Link l: this.switchPortLinks.get(np)) {
-					if(dpidLinks.containsKey(s)) {
-						dpidLinks.get(s).add(l);
-					}
-					else {
-						dpidLinks.put(s,new HashSet<Link>(Arrays.asList(l)));
-					}
-
-				}
-			}
-		}
+public class TopologyManager implements IFloodlightModule, ITopologyService, 
+    ITopologyManagerBackend, ILinkDiscoveryListener, IOFMessageListener {
 
-		return dpidLinks;
-	}
-
-	@Override
-	public boolean isEdge(DatapathId sw, OFPort p){
-		TopologyInstance ti = getCurrentInstance(true);
-		return ti.isEdge(sw, p);
-	}
-
-	@Override
-	public Set<OFPort> getSwitchBroadcastPorts(DatapathId sw){
-		TopologyInstance ti = getCurrentInstance(true);
-		return ti.swBroadcastPorts(sw);
-	}
-
-	@Override
-	public Date getLastUpdateTime() {
-		return lastUpdateTime;
-	}
-
-	@Override
-	public void addListener(ITopologyListener listener) {
-		topologyAware.add(listener);
-	}
-
-	@Override
-	public boolean isAttachmentPointPort(DatapathId switchid, OFPort port) {
-		return isAttachmentPointPort(switchid, port, true);
-	}
-
-	@Override
-	public boolean isAttachmentPointPort(DatapathId switchid, OFPort port, boolean tunnelEnabled) {
-
-		// If the switch port is 'tun-bsn' port, it is not
-		// an attachment point port, irrespective of whether
-		// a link is found through it or not.
-		if (linkDiscoveryService.isTunnelPort(switchid, port))
-			return false;
-
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-
-		// if the port is not attachment point port according to
-		// topology instance, then return false
-		if (ti.isAttachmentPointPort(switchid, port) == false)
-			return false;
-
-		// Check whether the port is a physical port. We should not learn
-		// attachment points on "special" ports.
-		if ((port.getShortPortNumber() & 0xff00) == 0xff00 && port.getShortPortNumber() != (short)0xfffe) return false;
-
-		// Make sure that the port is enabled.
-		IOFSwitch sw = switchService.getActiveSwitch(switchid);
-		if (sw == null) return false;
-		return (sw.portEnabled(port));
-	}
-
-	@Override
-	public DatapathId getOpenflowDomainId(DatapathId switchId) {
-		return getOpenflowDomainId(switchId, true);
-	}
-
-	@Override
-	public DatapathId getOpenflowDomainId(DatapathId switchId, boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.getOpenflowDomainId(switchId);
-	}
-
-	@Override
-	public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2) {
-		return inSameOpenflowDomain(switch1, switch2, true);
-	}
-
-	@Override
-	public boolean inSameOpenflowDomain(DatapathId switch1, DatapathId switch2,
-			boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.inSameOpenflowDomain(switch1, switch2);
-	}
-
-	@Override
-	public boolean isAllowed(DatapathId sw, OFPort portId) {
-		return isAllowed(sw, portId, true);
-	}
-
-	@Override
-	public boolean isAllowed(DatapathId sw, OFPort portId, boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.isAllowed(sw, portId);
-	}
-
-	////////////////////////////////////////////////////////////////////////
-	////////////////////////////////////////////////////////////////////////
-	@Override
-	public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId) {
-		return isIncomingBroadcastAllowed(sw, portId, true);
-	}
-
-	@Override
-	public boolean isIncomingBroadcastAllowed(DatapathId sw, OFPort portId,
-			boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.isIncomingBroadcastAllowedOnSwitchPort(sw, portId);
-	}
-
-	////////////////////////////////////////////////////////////////////////
-	////////////////////////////////////////////////////////////////////////
-	/** Get all the ports connected to the switch */
-	@Override
-	public Set<OFPort> getPortsWithLinks(DatapathId sw) {
-		return getPortsWithLinks(sw, true);
-	}
-
-	/** Get all the ports connected to the switch */
-	@Override
-	public Set<OFPort> getPortsWithLinks(DatapathId sw, boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.getPortsWithLinks(sw);
-	}
-
-	////////////////////////////////////////////////////////////////////////
-	////////////////////////////////////////////////////////////////////////
-	/** 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).
-	 */
-	@Override
-	public Set<OFPort> getBroadcastPorts(DatapathId targetSw,
-			DatapathId src, OFPort 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).
-	 */
-	@Override
-	public Set<OFPort> getBroadcastPorts(DatapathId targetSw,
-			DatapathId src, OFPort srcPort,
-			boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.getBroadcastPorts(targetSw, src, srcPort);
-	}
-
-	////////////////////////////////////////////////////////////////////////
-	////////////////////////////////////////////////////////////////////////
-	@Override
-	public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort dstPort) {
-		// Use this function to redirect traffic if needed.
-		return getOutgoingSwitchPort(src, srcPort, dst, dstPort, true);
-	}
-
-	@Override
-	public NodePortTuple getOutgoingSwitchPort(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort 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(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort dstPort) {
-		return getIncomingSwitchPort(src, srcPort, dst, dstPort, true);
-	}
-
-	@Override
-	public NodePortTuple getIncomingSwitchPort(DatapathId src, OFPort srcPort,
-			DatapathId dst, OFPort 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(DatapathId s1, OFPort p1, DatapathId s2,
-			OFPort p2) {
-		return isInSameBroadcastDomain(s1, p1, s2, p2, true);
-
-	}
-
-	@Override
-	public boolean isInSameBroadcastDomain(DatapathId s1, OFPort p1,
-			DatapathId s2, OFPort 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(DatapathId sw, OFPort port) {
-		return isBroadcastDomainPort(sw, port, true);
-	}
-
-	@Override
-	public boolean isBroadcastDomainPort(DatapathId sw, OFPort 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 isConsistent(DatapathId oldSw, OFPort oldPort,
-			DatapathId newSw, OFPort newPort) {
-		return isConsistent(oldSw, oldPort,
-				newSw, newPort, true);
-	}
-
-	@Override
-	public boolean isConsistent(DatapathId oldSw, OFPort oldPort,
-			DatapathId newSw, OFPort newPort,
-			boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.isConsistent(oldSw, oldPort, newSw, newPort);
-	}
-
-	////////////////////////////////////////////////////////////////////////
-	////////////////////////////////////////////////////////////////////////
-	@Override
-	public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src,
-			OFPort srcPort,
-			DatapathId dst,
-			OFPort dstPort) {
-		return getAllowedOutgoingBroadcastPort(src, srcPort,
-				dst, dstPort, true);
-	}
-
-	@Override
-	public NodePortTuple getAllowedOutgoingBroadcastPort(DatapathId src,
-			OFPort srcPort,
-			DatapathId dst,
-			OFPort dstPort,
-			boolean tunnelEnabled){
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.getAllowedOutgoingBroadcastPort(src, srcPort,
-				dst, dstPort);
-	}
-	////////////////////////////////////////////////////////////////////////
-	////////////////////////////////////////////////////////////////////////
-	@Override
-	public NodePortTuple
-	getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort) {
-		return getAllowedIncomingBroadcastPort(src,srcPort, true);
-	}
-
-	@Override
-	public NodePortTuple
-	getAllowedIncomingBroadcastPort(DatapathId src, OFPort srcPort,
-			boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.getAllowedIncomingBroadcastPort(src,srcPort);
-	}
-
-	////////////////////////////////////////////////////////////////////////
-	////////////////////////////////////////////////////////////////////////
-	@Override
-	public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID) {
-		return getSwitchesInOpenflowDomain(switchDPID, true);
-	}
-
-	@Override
-	public Set<DatapathId> getSwitchesInOpenflowDomain(DatapathId switchDPID,
-			boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.getSwitchesInOpenflowDomain(switchDPID);
-	}
-	////////////////////////////////////////////////////////////////////////
-	////////////////////////////////////////////////////////////////////////
-
-	@Override
-	public Set<NodePortTuple> getBroadcastDomainPorts() {
-		return portBroadcastDomainLinks.keySet();
-	}
-
-	@Override
-	public Set<NodePortTuple> getTunnelPorts() {
-		return tunnelPorts;
-	}
-
-	@Override
-	public Set<NodePortTuple> getBlockedPorts() {
-		Set<NodePortTuple> bp;
-		Set<NodePortTuple> blockedPorts =
-				new HashSet<NodePortTuple>();
-
-		// As we might have two topologies, simply get the union of
-		// both of them and send it.
-		bp = getCurrentInstance(true).getBlockedPorts();
-		if (bp != null)
-			blockedPorts.addAll(bp);
-
-		bp = getCurrentInstance(false).getBlockedPorts();
-		if (bp != null)
-			blockedPorts.addAll(bp);
-
-		return blockedPorts;
-	}
-	////////////////////////////////////////////////////////////////////////
-	////////////////////////////////////////////////////////////////////////
-
-	// ***************
-	// IRoutingService
-	// ***************
-
-	@Override
-	public Route getRoute(DatapathId src, DatapathId dst, U64 cookie) {
-		return getRoute(src, dst, cookie, true);
-	}
-
-	@Override
-	public Route getRoute(DatapathId src, DatapathId dst, U64 cookie, boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.getRoute(src, dst, cookie);
-	}
-
-	@Override
-	public Route getRoute(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort, U64 cookie) {
-		return getRoute(src, srcPort, dst, dstPort, cookie, true);
-	}
-
-	@Override
-	public Route getRoute(DatapathId src, OFPort srcPort, DatapathId dst, OFPort dstPort, U64 cookie,
-			boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.getRoute(src, srcPort, dst, dstPort, cookie);
-	}
-
-	@Override
-	public boolean routeExists(DatapathId src, DatapathId dst) {
-		return routeExists(src, dst, true);
-	}
-
-	@Override
-	public boolean routeExists(DatapathId src, DatapathId dst, boolean tunnelEnabled) {
-		TopologyInstance ti = getCurrentInstance(tunnelEnabled);
-		return ti.routeExists(src, dst);
-	}
-
-	@Override
-	public ArrayList<Route> getRoutes(DatapathId srcDpid, DatapathId dstDpid,
-			boolean tunnelEnabled) {
-		// Floodlight supports single path routing now
-
-		// return single path now
-		ArrayList<Route> result=new ArrayList<Route>();
-		result.add(getRoute(srcDpid, dstDpid, U64.of(0), tunnelEnabled));
-		return result;
-	}
-	
-    /** 
-     *  Registers an IRoutingDecisionChangedListener.
-     *   
-     *  @param {IRoutingDecisionChangedListener} listener - 
-     *  @return {void}
+    protected static Logger log = LoggerFactory.getLogger(TopologyManager.class);
+    public static final String MODULE_NAME = "topology";
+
+    protected static IStatisticsService statisticsService;
+
+    protected static volatile PATH_METRIC pathMetric = PATH_METRIC.HOPCOUNT_AVOID_TUNNELS; //default: compute paths on hop count
+    protected static boolean collectStatistics = false;
+
+    /**
+     * Maximum number of route entries stored in memory.
      */
-	@Override
-	public void addRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener) {
-		decisionChangedListeners.add(listener);
-	}
-	
-	/** 
-     *  Deletes an IRoutingDecisionChangedListener.
-     *   
-     *  @param {IRoutingDecisionChangedListener} listener - 
-     *  @return {void}
+    private static volatile int maxPathsToCompute = 3;
+
+    /**
+     * Role of the controller.
      */
-	@Override
-	public void removeRoutingDecisionChangedListener(IRoutingDecisionChangedListener listener) {
-		decisionChangedListeners.remove(listener);
-	}
-
-	/** 
-     *  Listens for the event to the IRoutingDecisionChanged listener and calls routingDecisionChanged().
-     *   
-     *  @param {Iterable<Masked<U64>>} - event
-     *  @return {void}
+    private HARole role;
+
+    /**
+     * Set of ports for each switch
      */
-	@Override
-	public void handleRoutingDecisionChange(Iterable<Masked<U64>> changedDecisions) {
-		for(IRoutingDecisionChangedListener listener : decisionChangedListeners) {
-			listener.routingDecisionChanged(changedDecisions);
-		}
-	}
-
-	// ******************
-	// IOFMessageListener
-	// ******************
-
-	@Override
-	public String getName() {
-		return MODULE_NAME;
-	}
-
-	@Override
-	public boolean isCallbackOrderingPrereq(OFType type, String name) {
-		return "linkdiscovery".equals(name);
-	}
-
-	@Override
-	public boolean isCallbackOrderingPostreq(OFType type, String name) {
-		return false;
-	}
-
-	@Override
-	public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
-		switch (msg.getType()) {
-		case PACKET_IN:
-			ctrIncoming.increment();
-			return this.processPacketInMessage(sw, (OFPacketIn) msg, cntx);
-		default:
-			break;
-		}
+    protected Map<DatapathId, Set<OFPort>> switchPorts;
 
-		return Command.CONTINUE;
-	}
-
-	// ***************
-	// IHAListener
-	// ***************
-
-	private class HAListenerDelegate implements IHAListener {
-		@Override
-		public void transitionToActive() {
-			role = HARole.ACTIVE;
-			log.debug("Re-computing topology due " +
-					"to HA change from STANDBY->ACTIVE");
-			newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
-					TimeUnit.MILLISECONDS);
-		}
+    /**
+     * Set of links organized by node port tuple
+     */
+    protected Map<NodePortTuple, Set<Link>> switchPortLinks;
 
-		@Override
-		public void controllerNodeIPsChanged(
-				Map<String, String> curControllerNodeIPs,
-				Map<String, String> addedControllerNodeIPs,
-				Map<String, String> removedControllerNodeIPs) {
-			// no-op
-		}
+    /**
+     * Set of direct links
+     */
+    protected Map<NodePortTuple, Set<Link>> directLinks;
 
-		@Override
-		public String getName() {
-			return TopologyManager.this.getName();
-		}
+    /**
+     * set of links that are broadcast domain links.
+     */
+    protected Map<NodePortTuple, Set<Link>> interClusterLinks;
 
-		@Override
-		public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
-				String name) {
-			return "linkdiscovery".equals(name);
-		}
+    /**
+     * set of tunnel links
+     */
+    protected Set<NodePortTuple> tunnelPorts;
 
-		@Override
-		public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
-				String name) {
-			// TODO Auto-generated method stub
-			return false;
-		}
+    protected ILinkDiscoveryService linkDiscoveryService;
+    protected IThreadPoolService threadPoolService;
+    protected IFloodlightProviderService floodlightProviderService;
+    protected IOFSwitchService switchService;
+    protected IRestApiService restApiService;
+    protected IDebugCounterService debugCounterService;
 
-		@Override
-		public void transitionToStandby() {
-			// TODO Auto-generated method stub
+    // Modules that listen to our updates
+    protected ArrayList<ITopologyListener> topologyAware;
 
-		}
-	}
-
-	// *****************
-	// IFloodlightModule
-	// *****************
-
-	@Override
-	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-		Collection<Class<? extends IFloodlightService>> l =
-				new ArrayList<Class<? extends IFloodlightService>>();
-		l.add(ITopologyService.class);
-		l.add(IRoutingService.class);
-		return l;
-	}
-
-	@Override
-	public Map<Class<? extends IFloodlightService>, IFloodlightService>
-	getServiceImpls() {
-		Map<Class<? extends IFloodlightService>,
-		IFloodlightService> m =
-		new HashMap<Class<? extends IFloodlightService>,
-		IFloodlightService>();
-		// We are the class that implements the service
-		m.put(ITopologyService.class, this);
-		m.put(IRoutingService.class, this);
-		return m;
-	}
-
-	@Override
-	public Collection<Class<? extends IFloodlightService>>
-	getModuleDependencies() {
-		Collection<Class<? extends IFloodlightService>> l =
-				new ArrayList<Class<? extends IFloodlightService>>();
-		l.add(ILinkDiscoveryService.class);
-		l.add(IThreadPoolService.class);
-		l.add(IFloodlightProviderService.class);
-		l.add(IOFSwitchService.class);
-		l.add(IDebugCounterService.class);
-		l.add(IRestApiService.class);
-		return l;
-	}
-
-	@Override
-	public void init(FloodlightModuleContext context)
-			throws FloodlightModuleException {
-		linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
-		threadPoolService = context.getServiceImpl(IThreadPoolService.class);
-		floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
-		switchService = context.getServiceImpl(IOFSwitchService.class);
-		restApiService = context.getServiceImpl(IRestApiService.class);
-		debugCounterService = context.getServiceImpl(IDebugCounterService.class);
-
-		switchPorts = new HashMap<DatapathId, Set<OFPort>>();
-		switchPortLinks = new HashMap<NodePortTuple, Set<Link>>();
-		directLinks = new HashMap<NodePortTuple, Set<Link>>();
-		portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>();
-		tunnelPorts = new HashSet<NodePortTuple>();
-		topologyAware = new ArrayList<ITopologyListener>();
-		ldUpdates = new LinkedBlockingQueue<LDUpdate>();
-		haListener = new HAListenerDelegate();
-		this.decisionChangedListeners = new ArrayList<IRoutingDecisionChangedListener>();
-		registerTopologyDebugCounters();
-	}
-
-	@Override
-	public void startUp(FloodlightModuleContext context) {
-		clearCurrentTopology();
-		// Initialize role to floodlight provider role.
-		this.role = floodlightProviderService.getRole();
-
-		ScheduledExecutorService ses = threadPoolService.getScheduledExecutor();
-		newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker());
-
-		if (role != HARole.STANDBY) {
-			newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, TimeUnit.MILLISECONDS);
-		}
+    protected BlockingQueue<LDUpdate> ldUpdates;
 
-		linkDiscoveryService.addListener(this);
-		floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
-		floodlightProviderService.addHAListener(this.haListener);
-		addRestletRoutable();
-	}
+    // These must be accessed using getCurrentInstance(), not directly
+    protected TopologyInstance currentInstance;
 
-	private void registerTopologyDebugCounters() throws FloodlightModuleException {
-		if (debugCounterService == null) {
-			log.error("debugCounterService should not be null. Has IDebugEventService been loaded previously?");
-		}
-		debugCounterService.registerModule(PACKAGE);
-		ctrIncoming = debugCounterService.registerCounter(
-				PACKAGE, "incoming",
-				"All incoming packets seen by this module");
-	}
-
-	protected void addRestletRoutable() {
-		restApiService.addRestletRoutable(new TopologyWebRoutable());
-	}
-
-	// ****************
-	// Internal methods
-	// ****************
-	/**
-	 * If the packet-in switch port is disabled for all data traffic, then
-	 * the packet will be dropped.  Otherwise, the packet will follow the
-	 * normal processing chain.
-	 * @param sw
-	 * @param pi
-	 * @param cntx
-	 * @return
-	 */
-	protected Command dropFilter(DatapathId sw, OFPacketIn pi,
-			FloodlightContext cntx) {
-		Command result = Command.CONTINUE;
-		OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
-
-		// If the input port is not allowed for data traffic, drop everything.
-		// BDDP packets will not reach this stage.
-		if (isAllowed(sw, inPort) == false) {
-			if (log.isTraceEnabled()) {
-				log.trace("Ignoring packet because of topology " +
-						"restriction on switch={}, port={}", sw.getLong(), inPort.getPortNumber());
-				result = Command.STOP;
-			}
-		}
-		return result;
-	}
-
-	/**
-	 * 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<OFPort> ports,
-			FloodlightContext cntx) {
-
-		if (ports == null) return;
-		if (packetData == null || packetData.length <= 0) return;
-
-		//OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
-		OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
-		List<OFAction> actions = new ArrayList<OFAction>();
-		for(OFPort p: ports) {
-			//actions.add(new OFActionOutput(p, (short) 0));
-			actions.add(sw.getOFFactory().actions().output(p, 0));
-		}
+    protected SingletonTask newInstanceTask;
+    private Date lastUpdateTime;
 
-		// set actions
-		pob.setActions(actions);
-		// set action length
-		//po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * ports.size()));
-		// set buffer-id to BUFFER_ID_NONE
-		pob.setBufferId(OFBufferId.NO_BUFFER);
-		// set in-port to OFPP_NONE
-		pob.setInPort(OFPort.ZERO);
+    /**
+     * Flag that indicates if links (direct/tunnel/multihop links) were
+     * updated as part of LDUpdate.
+     */
+    protected boolean linksUpdated;
+    /**
+     * Flag that indicates if direct or tunnel links were updated as
+     * part of LDUpdate.
+     */
+    protected boolean dtLinksUpdated;
 
-		// set packet data
-		pob.setData(packetData);
+    /** Flag that indicates if tunnel ports were updated or not
+     */
+    protected boolean tunnelPortsUpdated;
 
-		// compute and set packet length.
-		//short poLength = (short)(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + packetData.length);
+    protected int TOPOLOGY_COMPUTE_INTERVAL_MS = 500;
 
-		//po.setLength(poLength);
+    private IHAListener haListener;
 
-		//ctrIncoming.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, pob.build()});
-		}
-		sw.write(pob.build(), LogicalOFMessageCategory.MAIN);
-	}
-
-	/**
-	 * Get the set of ports to eliminate for sending out BDDP.  The method
-	 * returns all the ports that are suppressed for link discovery on the
-	 * switch.
-	 * packets.
-	 * @param sid
-	 * @return
-	 */
-	protected Set<OFPort> getPortsToEliminateForBDDP(DatapathId sid) {
-		Set<NodePortTuple> suppressedNptList = linkDiscoveryService.getSuppressLLDPsInfo();
-		if (suppressedNptList == null) return null;
-
-		Set<OFPort> resultPorts = new HashSet<OFPort>();
-		for(NodePortTuple npt: suppressedNptList) {
-			if (npt.getNodeId() == sid) {
-				resultPorts.add(npt.getPortId());
-			}
-		}
+    /**
+     *  Debug Counters
+     */
+    protected static final String PACKAGE = TopologyManager.class.getPackage().getName();
+    protected IDebugCounter ctrIncoming;
 
-		return resultPorts;
-	}
-
-	/**
-	 * 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(DatapathId pinSwitch, OFPacketIn pi,
-			FloodlightContext cntx) {
-
-		TopologyInstance ti = getCurrentInstance(false);
-
-		Set<DatapathId> switches = ti.getSwitchesInOpenflowDomain(pinSwitch);
-
-		if (switches == null)
-		{
-			// indicates no links are connected to the switches
-			switches = new HashSet<DatapathId>();
-			switches.add(pinSwitch);
-		}
+    //  Getter/Setter methods
+    /**
+     * Get the time interval for the period topology updates, if any.
+     * The time returned is in milliseconds.
+     * @return
+     */
+    public int getTopologyComputeInterval() {
+        return TOPOLOGY_COMPUTE_INTERVAL_MS;
+    }
 
-		for (DatapathId sid : switches) {
-			IOFSwitch sw = switchService.getSwitch(sid);
-			if (sw == null) continue;
-			Collection<OFPort> enabledPorts = sw.getEnabledPortNumbers();
-			if (enabledPorts == null)
-				continue;
-			Set<OFPort> ports = new HashSet<OFPort>();
-			ports.addAll(enabledPorts);
-
-			// 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<OFPort> portsKnownToTopo = ti.getPortsWithLinks(sid);
-
-			if (portsKnownToTopo != null) {
-				for (OFPort p : portsKnownToTopo) {
-					NodePortTuple npt =
-							new NodePortTuple(sid, p);
-					if (ti.isBroadcastDomainPort(npt) == false) {
-						ports.remove(p);
-					}
-				}
-			}
-
-			Set<OFPort> portsToEliminate = getPortsToEliminateForBDDP(sid);
-			if (portsToEliminate != null) {
-				ports.removeAll(portsToEliminate);
-			}
-
-			// remove the incoming switch port
-			if (pinSwitch == sid) {
-				ports.remove((pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
-			}
-
-			// we have all the switch ports to which we need to broadcast.
-			doMultiActionPacketOut(pi.getData(), sw, ports, cntx);
-		}
+    /**
+     * Set the time interval for the period topology updates, if any.
+     * The time is in milliseconds.
+     * @return
+     */
+    public void setTopologyComputeInterval(int time_ms) {
+        TOPOLOGY_COMPUTE_INTERVAL_MS = time_ms;
+    }
+
+    /**
+     * Thread for recomputing topology.  The thread is always running,
+     * however the function applyUpdates() has a blocking call.
+     */
+    protected class UpdateTopologyWorker implements Runnable {
+        @Override
+        public void run() {
+            try {
+                if (ldUpdates.peek() != null) {
+                    updateTopology();
+                }
+                handleMiscellaneousPeriodicEvents();
+            }
+            catch (Exception e) {
+                log.error("Error in topology instance task thread", e);
+            } finally {
+                if (floodlightProviderService.getRole() != HARole.STANDBY) {
+                    newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, TimeUnit.MILLISECONDS);
+                }
+            }
+        }
+    }
 
-	}
+    // To be used for adding any periodic events that's required by topology.
+    protected void handleMiscellaneousPeriodicEvents() {
+        return;
+    }
 
-	protected Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
-		// get the packet-in switch.
-		Ethernet eth =
-				IFloodlightProviderService.bcStore.
-				get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+    public boolean updateTopology() {
+        boolean newInstanceFlag;
+        linksUpdated = false;
+        dtLinksUpdated = false;
+        tunnelPortsUpdated = false;
+        List<LDUpdate> appliedUpdates = applyUpdates();
+        newInstanceFlag = createNewInstance("link-discovery-updates");
+        lastUpdateTime = new Date();
+        informListeners(appliedUpdates);
+        return newInstanceFlag;
+    }
 
-		if (eth.getPayload() instanceof BSN) {
-			BSN bsn = (BSN) eth.getPayload();
-			if (bsn == null) return Command.STOP;
-			if (bsn.getPayload() == null) return Command.STOP;
+    // **********************
+    // ILinkDiscoveryListener
+    // **********************
 
-			// It could be a packet other than BSN LLDP, therefore
-			// continue with the regular processing.
-			if (bsn.getPayload() instanceof LLDP == false)
-				return Command.CONTINUE;
+    @Override
+    public void linkDiscoveryUpdate(List<LDUpdate> updateList) {
+        if (log.isTraceEnabled()) {
+            log.trace("Queuing update: {}", updateList);
+        }
+        ldUpdates.addAll(updateList);
+    }
 
-			doFloodBDDP(sw.getId(), pi, cntx);
-			return Command.STOP;
-		} else {
-			return dropFilter(sw.getId(), pi, cntx);
-		}
-	}
-
-	/**
-	 * Updates concerning switch disconnect and port down are not processed.
-	 * LinkDiscoveryManager is expected to process those messages and send
-	 * multiple link removed messages.  However, all the updates from
-	 * LinkDiscoveryManager would be propagated to the listeners of topology.
-	 */
-	public List<LDUpdate> applyUpdates() {
-		List<LDUpdate> appliedUpdates = new ArrayList<LDUpdate>();
-		LDUpdate update = null;
-		while (ldUpdates.peek() != null) {
-			try {
-				update = ldUpdates.take();
-			} catch (Exception e) {
-				log.error("Error reading link discovery update.", e);
-			}
-			if (log.isDebugEnabled()) {
-				log.debug("Applying update: {}", update);
-			}
-
-			switch (update.getOperation()) {
-			case LINK_UPDATED:
-				addOrUpdateLink(update.getSrc(), update.getSrcPort(),
-						update.getDst(), update.getDstPort(),
-						update.getLatency(), update.getType());
-				break;
-			case LINK_REMOVED:
-				removeLink(update.getSrc(), update.getSrcPort(),
-						update.getDst(), update.getDstPort());
-				break;
-			case SWITCH_UPDATED:
-				addOrUpdateSwitch(update.getSrc());
-				break;
-			case SWITCH_REMOVED:
-				removeSwitch(update.getSrc());
-				break;
-			case TUNNEL_PORT_ADDED:
-				addTunnelPort(update.getSrc(), update.getSrcPort());
-				break;
-			case TUNNEL_PORT_REMOVED:
-				removeTunnelPort(update.getSrc(), update.getSrcPort());
-				break;
-			case PORT_UP: case PORT_DOWN:
-				break;
-			}
-			// Add to the list of applied updates.
-			appliedUpdates.add(update);
-		}
-		return (Collections.unmodifiableList(appliedUpdates));
-	}
+    // ****************
+    // ITopologyService
+    // ****************
+
+    @Override
+    public Map<DatapathId, Set<Link>> getAllLinks() {
+
+        Map<DatapathId, Set<Link>> dpidLinks = new HashMap<DatapathId, Set<Link>>();
+        TopologyInstance ti = getCurrentInstance();
+        Set<DatapathId> switches = ti.getSwitches();
+
+        for(DatapathId s: switches) {
+            if (this.switchPorts.get(s) == null) continue;
+            for (OFPort p: switchPorts.get(s)) {
+                NodePortTuple np = new NodePortTuple(s, p);
+                if (this.switchPortLinks.get(np) == null) continue;
+                for(Link l: this.switchPortLinks.get(np)) {
+                    if(dpidLinks.containsKey(s)) {
+                        dpidLinks.get(s).add(l);
+                    }
+                    else {
+                        dpidLinks.put(s,new HashSet<Link>(Arrays.asList(l)));
+                    }
+
+                }
+            }
+        }
+
+        return dpidLinks;
+    }
+
+    @Override
+    public boolean isEdge(DatapathId sw, OFPort p){
+        TopologyInstance ti = getCurrentInstance();
+        return ti.isEdge(sw, p);
+    }
+
+    @Override
+    public Set<OFPort> getSwitchBroadcastPorts(DatapathId sw){
+        TopologyInstance ti = getCurrentInstance();
+        return ti.swBroadcastPorts(sw);
+    }
+
+    @Override
+    public Date getLastUpdateTime() {
+        return lastUpdateTime;
+    }
+
+    @Override
+    public void addListener(ITopologyListener listener) {
+        topologyAware.add(listener);
+    }
+
+    @Override
+    public void removeListener(ITopologyListener listener) {
+        topologyAware.remove(listener);
+    }
+
+    @Override
+    public boolean isAttachmentPointPort(DatapathId switchid, OFPort port) {
 
-	protected void addOrUpdateSwitch(DatapathId sw) {
-		/*TODO react appropriately
+        // If the switch port is 'tun-bsn' port, it is not
+        // an attachment point port, irrespective of whether
+        // a link is found through it or not.
+        if (linkDiscoveryService.isTunnelPort(switchid, port))
+            return false;
+
+        TopologyInstance ti = getCurrentInstance();
+
+        // if the port is not attachment point port according to
+        // topology instance, then return false
+        if (ti.isAttachmentPointPort(switchid, port) == false)
+            return false;
+
+        // Check whether the port is a physical port. We should not learn
+        // attachment points on "special" ports.
+        if ((port.getShortPortNumber() & 0xff00) == 0xff00 && port.getShortPortNumber() != (short)0xfffe) return false;
+
+        // Make sure that the port is enabled.
+        IOFSwitch sw = switchService.getActiveSwitch(switchid);
+        if (sw == null) return false;
+        return (sw.portEnabled(port));
+    }
+
+    @Override
+    public DatapathId getClusterId(DatapathId switchId) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getClusterId(switchId);
+    }
+
+    @Override
+    public boolean isInSameCluster(DatapathId switch1, DatapathId switch2) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.isInSameCluster(switch1, switch2);
+    }
+
+    @Override
+    public boolean isNotBlocked(DatapathId sw, OFPort port) {
+        TopologyInstance ti = getCurrentInstance();
+        return !ti.isBlockedPort(new NodePortTuple(sw, port));
+    }
+
+    @Override
+    public void setPathMetric(PATH_METRIC metric) {
+        pathMetric = metric;
+    }
+
+    @Override
+    public PATH_METRIC getPathMetric() {
+        return pathMetric;
+    }
+
+    protected static PATH_METRIC getPathMetricInternal() {
+        return pathMetric;
+    }
+
+    protected static int getMaxPathsToComputeInternal() {
+        return maxPathsToCompute;
+    }
+
+    @Override
+    public int getMaxPathsToCompute() {
+        return maxPathsToCompute;
+    }
+
+    @Override
+    public void setMaxPathsToCompute(int max) {
+        maxPathsToCompute = max;
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public boolean isBroadcastAllowed(DatapathId sw, OFPort portId) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.isBroadcastAllowedOnSwitchPort(sw, portId);
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public Set<OFPort> getPortsWithLinks(DatapathId sw) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getPortsWithLinks(sw);
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////////////////
+
+    /** 
+     * 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).
+     */
+    @Override
+    public Set<OFPort> getBroadcastPorts(DatapathId targetSw,
+            DatapathId src, OFPort srcPort) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getBroadcastPorts(targetSw, src, srcPort);
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public boolean isInSameArchipelago(DatapathId s1, DatapathId s2) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.isInSameArchipelago(s1, s2);
+
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public boolean isBroadcastPort(DatapathId sw, OFPort port) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.isBroadcastPort(new NodePortTuple(sw, port));
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public boolean isConsistent(DatapathId oldSw, OFPort oldPort,
+            DatapathId newSw, OFPort newPort) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.isConsistent(oldSw, oldPort, newSw, newPort);
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public Set<DatapathId> getSwitchesInCluster(DatapathId switchDPID) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getSwitchesInCluster(switchDPID);
+    }
+    ////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public Set<Link> getExternalInterClusterLinks() {
+        ImmutableSet.Builder<Link> b = ImmutableSet.builder();
+        for (Collection<Link> c : interClusterLinks.values()) {
+            for (Link l : c) {
+                b.add(l);
+            }
+        }
+        return b.build();
+    }
+
+    @Override
+    public Set<Link> getInternalInterClusterLinks() {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getInternalInterClusterLinks();
+    }
+
+    @Override
+    public Set<NodePortTuple> getTunnelPorts() {
+        return tunnelPorts;
+    }
+
+    @Override
+    public Set<NodePortTuple> getBlockedPorts() {
+        Set<NodePortTuple> bp;
+        Set<NodePortTuple> blockedPorts =
+                new HashSet<NodePortTuple>();
+
+        bp = getCurrentInstance().getBlockedPorts();
+        if (bp != null)
+            blockedPorts.addAll(bp);
+
+        return blockedPorts;
+    }
+    ////////////////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////////////////
+
+    public Map<Link, Integer> getLinkCostMap() {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.initLinkCostMap();
+    }
+
+    // ******************
+    // IOFMessageListener
+    // ******************
+
+    @Override
+    public String getName() {
+        return MODULE_NAME;
+    }
+
+    @Override
+    public boolean isCallbackOrderingPrereq(OFType type, String name) {
+        return "linkdiscovery".equals(name);
+    }
+
+    @Override
+    public boolean isCallbackOrderingPostreq(OFType type, String name) {
+        return false;
+    }
+
+    @Override
+    public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+        switch (msg.getType()) {
+        case PACKET_IN:
+            ctrIncoming.increment();
+            return this.processPacketInMessage(sw, (OFPacketIn) msg, cntx);
+        default:
+            break;
+        }
+
+        return Command.CONTINUE;
+    }
+
+    // ***************
+    // IHAListener
+    // ***************
+
+    private class HAListenerDelegate implements IHAListener {
+        @Override
+        public void transitionToActive() {
+            role = HARole.ACTIVE;
+            log.debug("Re-computing topology due " +
+                    "to HA change from STANDBY->ACTIVE");
+            newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS,
+                    TimeUnit.MILLISECONDS);
+        }
+
+        @Override
+        public void controllerNodeIPsChanged(
+                Map<String, String> curControllerNodeIPs,
+                Map<String, String> addedControllerNodeIPs,
+                Map<String, String> removedControllerNodeIPs) {
+        }
+
+        @Override
+        public String getName() {
+            return TopologyManager.this.getName();
+        }
+
+        @Override
+        public boolean isCallbackOrderingPrereq(HAListenerTypeMarker type,
+                String name) {
+            return "linkdiscovery".equals(name);
+        }
+
+        @Override
+        public boolean isCallbackOrderingPostreq(HAListenerTypeMarker type,
+                String name) {
+            return false;
+        }
+
+        @Override
+        public void transitionToStandby() { }
+    }
+
+    // *****************
+    // IFloodlightModule
+    // *****************
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(ITopologyService.class);
+        return l;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService>
+    getServiceImpls() {
+        Map<Class<? extends IFloodlightService>,
+        IFloodlightService> m =
+        new HashMap<Class<? extends IFloodlightService>,
+        IFloodlightService>();
+        // We are the class that implements the service
+        m.put(ITopologyService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+    getModuleDependencies() {
+        Collection<Class<? extends IFloodlightService>> l =
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(ILinkDiscoveryService.class);
+        l.add(IThreadPoolService.class);
+        l.add(IFloodlightProviderService.class);
+        l.add(IOFSwitchService.class);
+        l.add(IDebugCounterService.class);
+        l.add(IRestApiService.class);
+        return l;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+        linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
+        threadPoolService = context.getServiceImpl(IThreadPoolService.class);
+        floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+        switchService = context.getServiceImpl(IOFSwitchService.class);
+        restApiService = context.getServiceImpl(IRestApiService.class);
+        debugCounterService = context.getServiceImpl(IDebugCounterService.class);
+        statisticsService = context.getServiceImpl(IStatisticsService.class);
+
+        switchPorts = new HashMap<DatapathId, Set<OFPort>>();
+        switchPortLinks = new HashMap<NodePortTuple, Set<Link>>();
+        directLinks = new HashMap<NodePortTuple, Set<Link>>();
+        interClusterLinks = new HashMap<NodePortTuple, Set<Link>>();
+        tunnelPorts = new HashSet<NodePortTuple>();
+        topologyAware = new ArrayList<ITopologyListener>();
+        ldUpdates = new LinkedBlockingQueue<LDUpdate>();
+        haListener = new HAListenerDelegate();
+        registerTopologyDebugCounters();
+
+        Map<String, String> configOptions = context.getConfigParams(this);
+        String metric = configOptions.get("pathMetric") != null
+                ? configOptions.get("pathMetric").trim().toLowerCase() : null;
+                if (metric != null) {
+                    metric = metric.toLowerCase().trim();
+                    switch (metric) {
+                    case "latency":
+                        pathMetric = PATH_METRIC.LATENCY;
+                        break;
+                    case "utilization":
+                        pathMetric = PATH_METRIC.UTILIZATION;
+                        break;
+                    case "hopcount":
+                        pathMetric = PATH_METRIC.HOPCOUNT;
+                        break;
+                    case "hopcount_avoid_tunnels":
+                        pathMetric = PATH_METRIC.HOPCOUNT_AVOID_TUNNELS;
+                        break;
+                    case "link_speed":
+                        pathMetric = PATH_METRIC.LINK_SPEED;
+                        break;
+                    default:
+                        log.error("Invalid routing metric {}. Using default {}", metric, pathMetric.getMetricName());
+                        break;
+                    }
+                }
+                log.info("Path metrics set to {}", pathMetric);
+
+                String maxroutes = configOptions.get("maxPathsToCompute") != null
+                        ? configOptions.get("maxPathsToCompute").trim() : null;
+                        if (maxroutes != null) {
+                            try {
+                                maxPathsToCompute = Integer.parseInt(maxroutes);
+                            } catch (NumberFormatException e) {
+                                log.error("Invalid 'maxPathsToCompute'. Using default {}", maxPathsToCompute);
+                            }
+                        }
+                        log.info("Will compute a max of {} paths upon topology updates", maxPathsToCompute);
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context) {
+        clearCurrentTopology();
+        // Initialize role to floodlight provider role.
+        this.role = floodlightProviderService.getRole();
+
+        ScheduledExecutorService ses = threadPoolService.getScheduledExecutor();
+        newInstanceTask = new SingletonTask(ses, new UpdateTopologyWorker());
+
+        if (role != HARole.STANDBY) {
+            newInstanceTask.reschedule(TOPOLOGY_COMPUTE_INTERVAL_MS, TimeUnit.MILLISECONDS);
+        }
+
+        linkDiscoveryService.addListener(this);
+        floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
+        floodlightProviderService.addHAListener(this.haListener);
+        addRestletRoutable();
+    }
+
+    private void registerTopologyDebugCounters() throws FloodlightModuleException {
+        if (debugCounterService == null) {
+            log.error("debugCounterService should not be null. Has IDebugEventService been loaded previously?");
+        }
+        debugCounterService.registerModule(PACKAGE);
+        ctrIncoming = debugCounterService.registerCounter(
+                PACKAGE, "incoming",
+                "All incoming packets seen by this module");
+    }
+
+    protected void addRestletRoutable() {
+        restApiService.addRestletRoutable(new TopologyWebRoutable());
+        restApiService.addRestletRoutable(new RoutingWebRoutable());
+    }
+
+    // ****************
+    // Internal methods
+    // ****************
+    /**
+     * If the packet-in switch port is disabled for all data traffic, then
+     * the packet will be dropped.  Otherwise, the packet will follow the
+     * normal processing chain.
+     * @param sw
+     * @param pi
+     * @param cntx
+     * @return
+     */
+    protected Command dropFilter(DatapathId sw, OFPacketIn pi,
+            FloodlightContext cntx) {
+        Command result = Command.CONTINUE;
+        OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
+
+        // If the input port is not allowed for data traffic, drop everything.
+        // BDDP packets will not reach this stage.
+        if (isNotBlocked(sw, inPort) == false) {
+            if (log.isTraceEnabled()) {
+                log.trace("Ignoring packet because of topology " +
+                        "restriction on switch={}, port={}", sw.getLong(), inPort.getPortNumber());
+                result = Command.STOP;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Send a packet-out to multiple ports
+     * @param packetData
+     * @param sw
+     * @param ports
+     * @param cntx
+     */
+    public void doMultiActionPacketOut(byte[] packetData, IOFSwitch sw,
+            Set<OFPort> ports,
+            FloodlightContext cntx) {
+
+        if (ports == null) return;
+        if (packetData == null || packetData.length <= 0) return;
+
+        //OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
+        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
+        List<OFAction> actions = new ArrayList<OFAction>();
+        for(OFPort p: ports) {
+            //actions.add(new OFActionOutput(p, (short) 0));
+            actions.add(sw.getOFFactory().actions().output(p, 0));
+        }
+
+        // set actions
+        pob.setActions(actions);
+        // set action length
+        //po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH * ports.size()));
+        // set buffer-id to BUFFER_ID_NONE
+        pob.setBufferId(OFBufferId.NO_BUFFER);
+        // set in-port to OFPP_NONE
+        pob.setInPort(OFPort.ZERO);
+
+        // set packet data
+        pob.setData(packetData);
+
+        // compute and set packet length.
+        //short poLength = (short)(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + packetData.length);
+
+        //po.setLength(poLength);
+
+        //ctrIncoming.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, pob.build()});
+        }
+        sw.write(pob.build(), LogicalOFMessageCategory.MAIN);
+    }
+
+    /**
+     * Get the set of ports to eliminate for sending out BDDP.  The method
+     * returns all the ports that are suppressed for link discovery on the
+     * switch.
+     * packets.
+     * @param sid
+     * @return
+     */
+    protected Set<OFPort> getPortsToEliminateForBDDP(DatapathId sid) {
+        Set<NodePortTuple> suppressedNptList = linkDiscoveryService.getSuppressLLDPsInfo();
+        if (suppressedNptList == null) return null;
+
+        Set<OFPort> resultPorts = new HashSet<OFPort>();
+        for(NodePortTuple npt: suppressedNptList) {
+            if (npt.getNodeId() == sid) {
+                resultPorts.add(npt.getPortId());
+            }
+        }
+
+        return resultPorts;
+    }
+
+    /**
+     * 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(DatapathId pinSwitch, OFPacketIn pi,
+            FloodlightContext cntx) {
+
+        TopologyInstance ti = getCurrentInstance();
+
+        Set<DatapathId> switches = ti.getSwitchesInCluster(pinSwitch);
+
+        if (switches == null)
+        {
+            // indicates no links are connected to the switches
+            switches = new HashSet<DatapathId>();
+            switches.add(pinSwitch);
+        }
+
+        for (DatapathId sid : switches) {
+            IOFSwitch sw = switchService.getSwitch(sid);
+            if (sw == null) continue;
+            Collection<OFPort> enabledPorts = sw.getEnabledPortNumbers();
+            if (enabledPorts == null)
+                continue;
+            Set<OFPort> ports = new HashSet<OFPort>();
+            ports.addAll(enabledPorts);
+
+            // 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<OFPort> portsKnownToTopo = ti.getPortsWithLinks(sid);
+
+            if (portsKnownToTopo != null) {
+                for (OFPort p : portsKnownToTopo) {
+                    NodePortTuple npt =
+                            new NodePortTuple(sid, p);
+                    if (ti.isBroadcastPort(npt) == false) {
+                        ports.remove(p);
+                    }
+                }
+            }
+
+            Set<OFPort> portsToEliminate = getPortsToEliminateForBDDP(sid);
+            if (portsToEliminate != null) {
+                ports.removeAll(portsToEliminate);
+            }
+
+            // remove the incoming switch port
+            if (pinSwitch == sid) {
+                ports.remove((pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+            }
+
+            // we have all the switch ports to which we need to broadcast.
+            doMultiActionPacketOut(pi.getData(), 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.getPayload() instanceof BSN) {
+            BSN bsn = (BSN) eth.getPayload();
+            if (bsn == null) return Command.STOP;
+            if (bsn.getPayload() == null) return Command.STOP;
+
+            // It could be a packet other than BSN LLDP, therefore
+            // continue with the regular processing.
+            if (bsn.getPayload() instanceof LLDP == false)
+                return Command.CONTINUE;
+
+            doFloodBDDP(sw.getId(), pi, cntx);
+            return Command.STOP;
+        } else {
+            return dropFilter(sw.getId(), pi, cntx);
+        }
+    }
+
+    /**
+     * Updates concerning switch disconnect and port down are not processed.
+     * LinkDiscoveryManager is expected to process those messages and send
+     * multiple link removed messages.  However, all the updates from
+     * LinkDiscoveryManager would be propagated to the listeners of topology.
+     */
+    public List<LDUpdate> applyUpdates() {
+        List<LDUpdate> appliedUpdates = new ArrayList<LDUpdate>();
+        LDUpdate update = null;
+        while (ldUpdates.peek() != null) {
+            try {
+                update = ldUpdates.take();
+            } catch (Exception e) {
+                log.error("Error reading link discovery update.", e);
+            }
+            if (log.isDebugEnabled()) {
+                log.debug("Applying update: {}", update);
+            }
+
+            switch (update.getOperation()) {
+            case LINK_UPDATED:
+                addOrUpdateLink(update.getSrc(), update.getSrcPort(),
+                        update.getDst(), update.getDstPort(),
+                        update.getLatency(), update.getType());
+                break;
+            case LINK_REMOVED:
+                removeLink(update.getSrc(), update.getSrcPort(),
+                        update.getDst(), update.getDstPort());
+                break;
+            case SWITCH_UPDATED:
+                addOrUpdateSwitch(update.getSrc());
+                break;
+            case SWITCH_REMOVED:
+                removeSwitch(update.getSrc());
+                break;
+            case TUNNEL_PORT_ADDED:
+                addTunnelPort(update.getSrc(), update.getSrcPort());
+                break;
+            case TUNNEL_PORT_REMOVED:
+                removeTunnelPort(update.getSrc(), update.getSrcPort());
+                break;
+            case PORT_UP: case PORT_DOWN:
+                break;
+            }
+            // Add to the list of applied updates.
+            appliedUpdates.add(update);
+        }
+        return (Collections.unmodifiableList(appliedUpdates));
+    }
+
+    protected void addOrUpdateSwitch(DatapathId sw) {
+        /*TODO react appropriately
 
 		addSwitch(sw);
 		for (OFPortDesc p : switchService.getSwitch(sw).getPorts()) {
 			addPortToSwitch(sw, p.getPortNo());
 		}
-		*/
-		return;
-	}
-
-	public void addTunnelPort(DatapathId sw, OFPort port) {
-		NodePortTuple npt = new NodePortTuple(sw, port);
-		tunnelPorts.add(npt);
-		tunnelPortsUpdated = true;
-	}
-
-	public void removeTunnelPort(DatapathId sw, OFPort port) {
-		NodePortTuple npt = new NodePortTuple(sw, port);
-		tunnelPorts.remove(npt);
-		tunnelPortsUpdated = true;
-	}
-
-	public boolean createNewInstance() {
-		return createNewInstance("internal");
-	}
-
-	/**
-	 * This function computes a new topology instance.
-	 * It ignores links connected to all broadcast domain ports
-	 * and tunnel ports. The method returns if a new instance of
-	 * topology was created or not.
-	 */
-	protected boolean createNewInstance(String reason) {
-		Set<NodePortTuple> blockedPorts = new HashSet<NodePortTuple>();
-
-		if (!linksUpdated) return false;
-
-		Map<NodePortTuple, Set<Link>> openflowLinks;
-		openflowLinks =
-				new HashMap<NodePortTuple, Set<Link>>();
-		Set<NodePortTuple> nptList = switchPortLinks.keySet();
-
-		if (nptList != null) {
-			for(NodePortTuple npt: nptList) {
-				Set<Link> linkSet = switchPortLinks.get(npt);
-				if (linkSet == null) continue;
-				openflowLinks.put(npt, new HashSet<Link>(linkSet));
-			}
-		}
+         */
+        return;
+    }
 
-		// Identify all broadcast domain ports.
-		// Mark any port that has inconsistent set of links
-		// as broadcast domain ports as well.
-		Set<NodePortTuple> broadcastDomainPorts =
-				identifyBroadcastDomainPorts();
-
-		// Remove all links incident on broadcast domain ports.
-		for (NodePortTuple npt : broadcastDomainPorts) {
-			if (switchPortLinks.get(npt) == null) continue;
-			for (Link link : switchPortLinks.get(npt)) {
-				removeLinkFromStructure(openflowLinks, link);
-			}
-		}
+    public void addTunnelPort(DatapathId sw, OFPort port) {
+        NodePortTuple npt = new NodePortTuple(sw, port);
+        tunnelPorts.add(npt);
+        tunnelPortsUpdated = true;
+    }
 
-		// Remove all tunnel links.
-		for (NodePortTuple npt: tunnelPorts) {
-			if (switchPortLinks.get(npt) == null) continue;
-			for (Link link : switchPortLinks.get(npt)) {
-				removeLinkFromStructure(openflowLinks, link);
-			}
-		}
-		//switchPorts contains only ports that are part of links. Calculation of broadcast ports needs set of all ports. 
-		Map<DatapathId, Set<OFPort>> allPorts = new HashMap<DatapathId, Set<OFPort>>();;
-		for (DatapathId sw : switchPorts.keySet()){
-			allPorts.put(sw, this.getPorts(sw));
-		}
+    public void removeTunnelPort(DatapathId sw, OFPort port) {
+        NodePortTuple npt = new NodePortTuple(sw, port);
+        tunnelPorts.remove(npt);
+        tunnelPortsUpdated = true;
+    }
 
-		TopologyInstance nt = new TopologyInstance(switchPorts,
-				blockedPorts,
-				openflowLinks,
-				broadcastDomainPorts,
-				tunnelPorts,
-				switchPortLinks,
-				allPorts,
-				portBroadcastDomainLinks);
-
-		nt.compute();
-
-		// We set the instances with and without tunnels to be identical.
-		// If needed, we may compute them differently.
-		currentInstance = nt;
-		currentInstanceWithoutTunnels = nt;
-
-		return true;
-	}
-
-	/**
-	 *  We expect every switch port to have at most two links.  Both these
-	 *  links must be unidirectional links connecting to the same switch port.
-	 *  If not, we will mark this as a broadcast domain port.
-	 */
-	protected Set<NodePortTuple> identifyBroadcastDomainPorts() {
-
-		Set<NodePortTuple> broadcastDomainPorts =
-				new HashSet<NodePortTuple>();
-		broadcastDomainPorts.addAll(this.portBroadcastDomainLinks.keySet());
-
-		Set<NodePortTuple> additionalNpt =
-				new HashSet<NodePortTuple>();
-
-		// Copy switchPortLinks
-		Map<NodePortTuple, Set<Link>> spLinks =
-				new HashMap<NodePortTuple, Set<Link>>();
-		for (NodePortTuple npt : switchPortLinks.keySet()) {
-			spLinks.put(npt, new HashSet<Link>(switchPortLinks.get(npt)));
-		}
+    public boolean createNewInstance() {
+        return createNewInstance("internal");
+    }
 
-		for (NodePortTuple npt : spLinks.keySet()) {
-			Set<Link> links = spLinks.get(npt);
-			boolean bdPort = false;
-			ArrayList<Link> linkArray = new ArrayList<Link>();
-			if (links.size() > 2) {
-				bdPort = true;
-			} else if (links.size() == 2) {
-				for (Link l : links) {
-					linkArray.add(l);
-				}
-				// now, there should be two links in [0] and [1].
-				Link l1 = linkArray.get(0);
-				Link l2 = linkArray.get(1);
-
-				// check if these two are symmetric.
-				if (!l1.getSrc().equals(l2.getDst()) ||
-						!l1.getSrcPort().equals(l2.getDstPort()) ||
-						!l1.getDst().equals(l2.getSrc()) ||
-						!l1.getDstPort().equals(l2.getSrcPort())) {
-					bdPort = true;
-				}
-			}
-
-			if (bdPort && (broadcastDomainPorts.contains(npt) == false)) {
-				additionalNpt.add(npt);
-			}
-		}
+    /**
+     * This function computes a new topology instance.
+     * It ignores links connected to all broadcast domain ports
+     * and tunnel ports. The method returns if a new instance of
+     * topology was created or not.
+     */
+    protected boolean createNewInstance(String reason) {
+        Set<NodePortTuple> blockedPorts = new HashSet<NodePortTuple>();
+
+        if (!linksUpdated) return false;
+
+        Map<NodePortTuple, Set<Link>> openflowLinks;
+        openflowLinks =
+                new HashMap<NodePortTuple, Set<Link>>();
+        Set<NodePortTuple> nptList = switchPortLinks.keySet();
+
+        if (nptList != null) {
+            for(NodePortTuple npt: nptList) {
+                Set<Link> linkSet = switchPortLinks.get(npt);
+                if (linkSet == null) continue;
+                openflowLinks.put(npt, new HashSet<Link>(linkSet));
+            }
+        }
 
-		if (additionalNpt.size() > 0) {
-			log.warn("The following switch ports have multiple " +
-					"links incident on them, so these ports will be treated " +
-					" as braodcast domain ports. {}", additionalNpt);
+        // Identify all broadcast domain ports.
+        // Mark any port that has inconsistent set of links
+        // as broadcast domain ports as well.
+        Set<NodePortTuple> broadcastDomainPorts =
+                identifyBroadcastDomainPorts();
+
+        // Remove all links incident on broadcast domain ports.
+        for (NodePortTuple npt : broadcastDomainPorts) {
+            if (switchPortLinks.get(npt) == null) continue;
+            for (Link link : switchPortLinks.get(npt)) {
+                removeLinkFromStructure(openflowLinks, link);
+            }
+        }
 
-			broadcastDomainPorts.addAll(additionalNpt);
-		}
-		return broadcastDomainPorts;
-	}
+        // Remove all tunnel links.
+        for (NodePortTuple npt: tunnelPorts) {
+            if (switchPortLinks.get(npt) == null) continue;
+            for (Link link : switchPortLinks.get(npt)) {
+                removeLinkFromStructure(openflowLinks, link);
+            }
+        }
+        //switchPorts contains only ports that are part of links. Calculation of broadcast ports needs set of all ports. 
+        Map<DatapathId, Set<OFPort>> allPorts = new HashMap<DatapathId, Set<OFPort>>();;
+        for (DatapathId sw : switchPorts.keySet()){
+            allPorts.put(sw, this.getPorts(sw));
+        }
 
+        TopologyInstance nt = new TopologyInstance(switchPorts,
+                blockedPorts,
+                openflowLinks,
+                broadcastDomainPorts,
+                tunnelPorts,
+                switchPortLinks,
+                allPorts,
+                interClusterLinks);
 
+        nt.compute();
 
-	public void informListeners(List<LDUpdate> linkUpdates) {
+        currentInstance = nt;
 
-		if (role != null && role != HARole.ACTIVE)
-			return;
+        return true;
+    }
 
-		for(int i=0; i < topologyAware.size(); ++i) {
-			ITopologyListener listener = topologyAware.get(i);
-			listener.topologyChanged(linkUpdates);
-		}
-	}
+    /**
+     *  We expect every switch port to have at most two links.  Both these
+     *  links must be unidirectional links connecting to the same switch port.
+     *  If not, we will mark this as a broadcast domain port.
+     */
+    protected Set<NodePortTuple> identifyBroadcastDomainPorts() {
 
-	public void addSwitch(DatapathId sid) {
-		if (switchPorts.containsKey(sid) == false) {
-			switchPorts.put(sid, new HashSet<OFPort>());
-		}
-	}
-
-	private void addPortToSwitch(DatapathId s, OFPort p) {
-		addSwitch(s);
-		switchPorts.get(s).add(p);
-	}
-
-	public void removeSwitch(DatapathId sid) {
-		// Delete all the links in the switch, switch and all
-		// associated data should be deleted.
-		if (switchPorts.containsKey(sid) == false) return;
-
-		// Check if any tunnel ports need to be removed.
-		for(NodePortTuple npt: tunnelPorts) {
-			if (npt.getNodeId() == sid) {
-				removeTunnelPort(npt.getNodeId(), npt.getPortId());
-			}
-		}
+        Set<NodePortTuple> broadcastDomainPorts =
+                new HashSet<NodePortTuple>();
+        broadcastDomainPorts.addAll(this.interClusterLinks.keySet());
 
-		Set<Link> linksToRemove = new HashSet<Link>();
-		for(OFPort p: switchPorts.get(sid)) {
-			NodePortTuple n1 = new NodePortTuple(sid, p);
-			linksToRemove.addAll(switchPortLinks.get(n1));
-		}
+        Set<NodePortTuple> additionalNpt =
+                new HashSet<NodePortTuple>();
 
-		if (linksToRemove.isEmpty()) return;
+        // Copy switchPortLinks
+        Map<NodePortTuple, Set<Link>> spLinks =
+                new HashMap<NodePortTuple, Set<Link>>();
+        for (NodePortTuple npt : switchPortLinks.keySet()) {
+            spLinks.put(npt, new HashSet<Link>(switchPortLinks.get(npt)));
+        }
 
-		for(Link link: linksToRemove) {
-			removeLink(link);
-		}
-	}
-
-	/**
-	 * Add the given link to the data structure.
-	 * @param s
-	 * @param l
-	 */
-	private void addLinkToStructure(Map<NodePortTuple, Set<Link>> s, Link l) {
-		NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
-		NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort());
-
-		if (s.get(n1) == null) {
-			s.put(n1, new HashSet<Link>());
-		} 
-		if (s.get(n2) == null) {
-			s.put(n2, new HashSet<Link>());
-		}
+        for (NodePortTuple npt : spLinks.keySet()) {
+            Set<Link> links = spLinks.get(npt);
+            boolean bdPort = false;
+            ArrayList<Link> linkArray = new ArrayList<Link>();
+            if (links.size() > 2) {
+                bdPort = true;
+            } else if (links.size() == 2) {
+                for (Link l : links) {
+                    linkArray.add(l);
+                }
+                // now, there should be two links in [0] and [1].
+                Link l1 = linkArray.get(0);
+                Link l2 = linkArray.get(1);
+
+                // check if these two are symmetric.
+                if (!l1.getSrc().equals(l2.getDst()) ||
+                        !l1.getSrcPort().equals(l2.getDstPort()) ||
+                        !l1.getDst().equals(l2.getSrc()) ||
+                        !l1.getDstPort().equals(l2.getSrcPort())) {
+                    bdPort = true;
+                }
+            }
+
+            if (bdPort && (broadcastDomainPorts.contains(npt) == false)) {
+                additionalNpt.add(npt);
+            }
+        }
+
+        if (additionalNpt.size() > 0) {
+            log.warn("The following switch ports have multiple " +
+                    "links incident on them, so these ports will be treated " +
+                    " as braodcast domain ports. {}", additionalNpt);
+
+            broadcastDomainPorts.addAll(additionalNpt);
+        }
+        return broadcastDomainPorts;
+    }
+
+
+
+    public void informListeners(List<LDUpdate> linkUpdates) {
+
+        if (role != null && role != HARole.ACTIVE)
+            return;
+
+        for(int i=0; i < topologyAware.size(); ++i) {
+            ITopologyListener listener = topologyAware.get(i);
+            listener.topologyChanged(linkUpdates);
+        }
+    }
+
+    public void addSwitch(DatapathId sid) {
+        if (switchPorts.containsKey(sid) == false) {
+            switchPorts.put(sid, new HashSet<OFPort>());
+        }
+    }
+
+    private void addPortToSwitch(DatapathId s, OFPort p) {
+        addSwitch(s);
+        switchPorts.get(s).add(p);
+    }
+
+    public void removeSwitch(DatapathId sid) {
+        // Delete all the links in the switch, switch and all
+        // associated data should be deleted.
+        if (switchPorts.containsKey(sid) == false) return;
+
+        // Check if any tunnel ports need to be removed.
+        for(NodePortTuple npt: tunnelPorts) {
+            if (npt.getNodeId() == sid) {
+                removeTunnelPort(npt.getNodeId(), npt.getPortId());
+            }
+        }
+
+        Set<Link> linksToRemove = new HashSet<Link>();
+        for(OFPort p: switchPorts.get(sid)) {
+            NodePortTuple n1 = new NodePortTuple(sid, p);
+            linksToRemove.addAll(switchPortLinks.get(n1));
+        }
+
+        if (linksToRemove.isEmpty()) return;
+
+        for(Link link: linksToRemove) {
+            removeLink(link);
+        }
+    }
 
-		/* 
-		 * Since we don't include latency in .equals(), we need
-		 * to explicitly remove the existing link (if present).
-		 * Otherwise, new latency values for existing links will
-		 * never be accepted.
-		 */
+    /**
+     * Add the given link to the data structure.
+     * @param s
+     * @param l
+     */
+    private void addLinkToStructure(Map<NodePortTuple, Set<Link>> s, Link l) {
+        NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
+        NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort());
+
+        if (s.get(n1) == null) {
+            s.put(n1, new HashSet<Link>());
+        } 
+        if (s.get(n2) == null) {
+            s.put(n2, new HashSet<Link>());
+        }
+
+        /* 
+         * Since we don't include latency in .equals(), we need
+         * to explicitly remove the existing link (if present).
+         * Otherwise, new latency values for existing links will
+         * never be accepted.
+         */
         s.get(n1).remove(l);
         s.get(n2).remove(l);
         s.get(n1).add(l);
@@ -1314,12 +1163,12 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
     }
 
     protected void addOrUpdateTunnelLink(DatapathId srcId, OFPort srcPort, DatapathId dstId,
-                                         OFPort dstPort, U64 latency) {
+            OFPort dstPort, U64 latency) {
         // If you need to handle tunnel links, this is a placeholder.
     }
 
     public void addOrUpdateLink(DatapathId srcId, OFPort srcPort, DatapathId dstId,
-                                OFPort dstPort, U64 latency, LinkType type) {
+            OFPort dstPort, U64 latency, LinkType type) {
         Link link = new Link(srcId, srcPort, dstId, dstPort, latency);
 
         if (type.equals(LinkType.MULTIHOP_LINK)) {
@@ -1327,7 +1176,7 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
             addPortToSwitch(dstId, dstPort);
             addLinkToStructure(switchPortLinks, link);
 
-            addLinkToStructure(portBroadcastDomainLinks, link);
+            addLinkToStructure(interClusterLinks, link);
             dtLinksUpdated = removeLinkFromStructure(directLinks, link);
             linksUpdated = true;
         } else if (type.equals(LinkType.DIRECT_LINK)) {
@@ -1336,7 +1185,7 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
             addLinkToStructure(switchPortLinks, link);
 
             addLinkToStructure(directLinks, link);
-            removeLinkFromStructure(portBroadcastDomainLinks, link);
+            removeLinkFromStructure(interClusterLinks, link);
             dtLinksUpdated = true;
             linksUpdated = true;
         } else if (type.equals(LinkType.TUNNEL)) {
@@ -1347,7 +1196,7 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
     public void removeLink(Link link) {
         linksUpdated = true;
         dtLinksUpdated = removeLinkFromStructure(directLinks, link);
-        removeLinkFromStructure(portBroadcastDomainLinks, link);
+        removeLinkFromStructure(interClusterLinks, link);
         removeLinkFromStructure(switchPortLinks, link);
 
         NodePortTuple srcNpt =
@@ -1377,7 +1226,7 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
     }
 
     public void removeLink(DatapathId srcId, OFPort srcPort,
-                           DatapathId dstId, OFPort dstPort) {
+            DatapathId dstId, OFPort dstPort) {
         Link link = new Link(srcId, srcPort, dstId, dstPort, U64.ZERO /* does not matter for remove (not included in .equals() of Link) */);
         removeLink(link);
     }
@@ -1386,7 +1235,7 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
         switchPorts.clear();
         tunnelPorts.clear();
         switchPortLinks.clear();
-        portBroadcastDomainLinks.clear();
+        interClusterLinks.clear();
         directLinks.clear();
     }
 
@@ -1406,26 +1255,16 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
     /**
      * Getters.  No Setters.
      */
-    public Map<DatapathId, Set<OFPort>> getSwitchPorts() {
+    public Map<DatapathId, Set<OFPort>> getPortsPerSwitch() {
         return switchPorts;
     }
 
-    public Map<NodePortTuple, Set<Link>> getSwitchPortLinks() {
+    public Map<NodePortTuple, Set<Link>> getPortsOnLinks() {
         return switchPortLinks;
     }
 
-    public Map<NodePortTuple, Set<Link>> getPortBroadcastDomainLinks() {
-        return portBroadcastDomainLinks;
-    }
-
-    public TopologyInstance getCurrentInstance(boolean tunnelEnabled) {
-        if (tunnelEnabled)
-            return currentInstance;
-        else return this.currentInstanceWithoutTunnels;
-    }
-
     public TopologyInstance getCurrentInstance() {
-        return this.getCurrentInstance(true);
+        return this.currentInstance;
     }
 
     /**
@@ -1446,4 +1285,39 @@ public class TopologyManager implements IFloodlightModule, ITopologyService, IRo
 
         return ports;
     }
-}
+
+    @Override
+    public Set<NodePortTuple> getBroadcastPortsInArchipelago(DatapathId sw) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getBroadcastPortsInArchipelago(sw);
+    }
+
+    @Override
+    public DatapathId getArchipelagoId(DatapathId switchId) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getArchipelagoId(switchId);
+    }
+
+    @Override
+    public Set<DatapathId> getClusterIdsInArchipelago(DatapathId sw) {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getClusterIdsInArchipelago(sw);
+    }
+
+    @Override
+    public Set<NodePortTuple> getAllBroadcastPorts() {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getAllBroadcastPorts();
+    }
+
+    @Override
+    public Set<DatapathId> getArchipelagoIds() {
+        TopologyInstance ti = getCurrentInstance();
+        return ti.getArchipelagoIds();
+    }
+
+    @Override
+    public TopologyInstance getCurrentTopologyInstance() {
+        return getCurrentInstance();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainPortsResource.java b/src/main/java/net/floodlightcontroller/topology/web/AllBroadcastPortsResource.java
similarity index 79%
rename from src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainPortsResource.java
rename to src/main/java/net/floodlightcontroller/topology/web/AllBroadcastPortsResource.java
index 36288ba871f7e629d3665493ef26858dc745eb2b..cef44c60a7e6dd27f0e367a1c0ff0440305f00db 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/BroadcastDomainPortsResource.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/AllBroadcastPortsResource.java
@@ -16,21 +16,20 @@
 
 package net.floodlightcontroller.topology.web;
 
-import java.util.Set;
 
-import net.floodlightcontroller.core.types.NodePortTuple;
+import net.floodlightcontroller.core.types.JsonObjectWrapper;
 import net.floodlightcontroller.topology.ITopologyService;
 
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 
-public class BroadcastDomainPortsResource extends ServerResource {
-    @Get("json")
-    public Set<NodePortTuple> retrieve() {
+public class AllBroadcastPortsResource extends ServerResource {
+    @Get
+    public JsonObjectWrapper retrieve() {
         ITopologyService topology = 
                 (ITopologyService)getContext().getAttributes().
                     get(ITopologyService.class.getCanonicalName());
         
-        return topology.getBroadcastDomainPorts();
+        return JsonObjectWrapper.of(topology.getAllBroadcastPorts());
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/topology/web/BlockedPortsResource.java b/src/main/java/net/floodlightcontroller/topology/web/BlockedPortsResource.java
index b95073aa6a9421bc5a63f27edcdd49e7950944fd..ee8e1c5b419971b93817eb1c7bcb1c5ee426e624 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/BlockedPortsResource.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/BlockedPortsResource.java
@@ -16,9 +16,7 @@
 
 package net.floodlightcontroller.topology.web;
 
-import java.util.Set;
-
-import net.floodlightcontroller.core.types.NodePortTuple;
+import net.floodlightcontroller.core.types.JsonObjectWrapper;
 import net.floodlightcontroller.topology.ITopologyService;
 
 import org.restlet.resource.Get;
@@ -26,11 +24,11 @@ import org.restlet.resource.ServerResource;
 
 public class BlockedPortsResource extends ServerResource {
     @Get("json")
-    public Set<NodePortTuple> retrieve() {
+    public JsonObjectWrapper retrieve() {
         ITopologyService topology = 
                 (ITopologyService)getContext().getAttributes().
                     get(ITopologyService.class.getCanonicalName());
         
-        return topology.getBlockedPorts();
+        return JsonObjectWrapper.of(topology.getBlockedPorts());
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java b/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java
index 8942a9d3d811e6e215fb8dbb08b20c43ef093c0d..6d4aafe85662a98d4a1bc5c7715a4d692e7276ad 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/EnabledPortsResource.java
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.Set;
 
 import net.floodlightcontroller.core.internal.IOFSwitchService;
+import net.floodlightcontroller.core.types.JsonObjectWrapper;
 import net.floodlightcontroller.core.types.NodePortTuple;
 import net.floodlightcontroller.topology.ITopologyService;
 
@@ -31,7 +32,7 @@ import org.restlet.resource.ServerResource;
 
 public class EnabledPortsResource extends ServerResource {
     @Get("json")
-    public List<NodePortTuple> retrieve() {
+    public JsonObjectWrapper retrieve() {
         List<NodePortTuple> result = new ArrayList<NodePortTuple>();
 
         IOFSwitchService switchService =
@@ -42,11 +43,14 @@ public class EnabledPortsResource extends ServerResource {
                 (ITopologyService) getContext().getAttributes().
                 get(ITopologyService.class.getCanonicalName());
 
-        if (switchService == null || topologyService == null)
-            return result;
+        if (switchService == null || topologyService == null) {
+            return JsonObjectWrapper.of(result);
+        }
 
         Set<DatapathId> switches = switchService.getAllSwitchDpids();
-        if (switches == null) return result;
+        if (switches == null) {
+            return JsonObjectWrapper.of(result);
+        }
 
         for(DatapathId sw: switches) {
             Set<OFPort> ports = topologyService.getPorts(sw);
@@ -55,6 +59,6 @@ public class EnabledPortsResource extends ServerResource {
                 result.add(new NodePortTuple(sw, p));
             }
         }
-        return result;
+        return JsonObjectWrapper.of(result);
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java b/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java
deleted file mode 100644
index 33eb0e58720480b5ed29d57e06987c67b4025181..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/topology/web/RouteResource.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- *    Copyright 2013, Big Switch Networks, Inc.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License"); you may
- *    not use this file except in compliance with the License. You may obtain
- *    a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- *    License for the specific language governing permissions and limitations
- *    under the License.
- **/
-
-package net.floodlightcontroller.topology.web;
-
-import java.util.List;
-
-import net.floodlightcontroller.core.types.NodePortTuple;
-import net.floodlightcontroller.routing.IRoutingService;
-import net.floodlightcontroller.routing.Route;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.U64;
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RouteResource extends ServerResource {
-
-    protected static Logger log = LoggerFactory.getLogger(RouteResource.class);
-
-    @Get("json")
-    public List<NodePortTuple> retrieve() {
-        IRoutingService routing = 
-                (IRoutingService)getContext().getAttributes().
-                    get(IRoutingService.class.getCanonicalName());
-        
-        String srcDpid = (String) getRequestAttributes().get("src-dpid");
-        String srcPort = (String) getRequestAttributes().get("src-port");
-        String dstDpid = (String) getRequestAttributes().get("dst-dpid");
-        String dstPort = (String) getRequestAttributes().get("dst-port");
-        
-        log.debug( srcDpid + "--" + srcPort + "--" + dstDpid + "--" + dstPort);
-
-        DatapathId longSrcDpid = DatapathId.of(srcDpid);
-        OFPort shortSrcPort = OFPort.of(Integer.parseInt(srcPort));
-        DatapathId longDstDpid = DatapathId.of(dstDpid);
-        OFPort shortDstPort = OFPort.of(Integer.parseInt(dstPort));
-        
-        Route result = routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort, U64.of(0));
-        
-        if (result != null) {
-            return routing.getRoute(longSrcDpid, shortSrcPort, longDstDpid, shortDstPort, U64.of(0)).getPath();
-        }
-        else {
-            log.debug("ERROR! no route found");
-            return null;
-        }
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/topology/web/SwitchArchipelagosResource.java b/src/main/java/net/floodlightcontroller/topology/web/SwitchArchipelagosResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..30c4ab5c4140e39bb03810babb22441516baad38
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/topology/web/SwitchArchipelagosResource.java
@@ -0,0 +1,54 @@
+/**
+ *    Copyright 2011, Big Switch Networks, Inc.
+ *    Originally created by David Erickson, Stanford University
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *    not use this file except in compliance with the License. You may obtain
+ *    a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ **/
+
+package net.floodlightcontroller.topology.web;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import net.floodlightcontroller.topology.ITopologyService;
+
+import org.projectfloodlight.openflow.types.DatapathId;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+/**
+ * Returns a JSON map of <Archipelago-ID, List<Cluster-IDs>>
+ */
+public class SwitchArchipelagosResource extends ServerResource {
+    @Get("json")
+    public Map<String, Map<String, Set<String>>> retrieve() {
+        ITopologyService topologyService =
+                (ITopologyService) getContext().getAttributes().
+                get(ITopologyService.class.getCanonicalName());
+
+        Map<String, Map<String, Set<String>>> switchArchMap = new HashMap<String, Map<String, Set<String>>>();
+        for (DatapathId a : topologyService.getArchipelagoIds()) {
+            switchArchMap.put(a.toString(), new HashMap<String, Set<String>>());
+            for (DatapathId c : topologyService.getClusterIdsInArchipelago(a)) {
+                switchArchMap.get(a.toString()).put(c.toString(), new HashSet<String>());
+                for (DatapathId s : topologyService.getSwitchesInCluster(c)) {
+                    switchArchMap.get(a.toString()).get(c.toString()).add(s.toString());
+                }
+            }
+        }
+
+        return switchArchMap; /* map serialized as object */
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java b/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java
deleted file mode 100644
index f62c8b1b73f2de99a376c376dedd2d8d114229cf..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
-*    Copyright 2011, Big Switch Networks, Inc.
-*    Originally created by David Erickson, Stanford University
-*
-*    Licensed under the Apache License, Version 2.0 (the "License"); you may
-*    not use this file except in compliance with the License. You may obtain
-*    a copy of the License at
-*
-*         http://www.apache.org/licenses/LICENSE-2.0
-*
-*    Unless required by applicable law or agreed to in writing, software
-*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-*    License for the specific language governing permissions and limitations
-*    under the License.
-**/
-
-package net.floodlightcontroller.topology.web;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import net.floodlightcontroller.core.internal.IOFSwitchService;
-import net.floodlightcontroller.topology.ITopologyService;
-
-import org.projectfloodlight.openflow.types.DatapathId;
-import org.restlet.data.Form;
-import org.restlet.resource.Get;
-import org.restlet.resource.ServerResource;
-
-/**
- * Returns a JSON map of <ClusterId, List<SwitchDpids>>
- */
-public class SwitchClustersResource extends ServerResource {
-    @Get("json")
-    public Map<String, List<String>> retrieve() {
-        IOFSwitchService switchService =
-                (IOFSwitchService) getContext().getAttributes().
-                    get(IOFSwitchService.class.getCanonicalName());
-        ITopologyService topologyService =
-                (ITopologyService) getContext().getAttributes().
-                    get(ITopologyService.class.getCanonicalName());
-
-        Form form = getQuery();
-        String queryType = form.getFirstValue("type", true);
-        boolean openflowDomain = true;
-        if (queryType != null && "l2".equals(queryType)) {
-            openflowDomain = false;
-        }
-
-        Map<String, List<String>> switchClusterMap = new HashMap<String, List<String>>();
-        for (DatapathId dpid: switchService.getAllSwitchDpids()) {
-            DatapathId clusterDpid =
-                    (openflowDomain
-                     ? topologyService.getOpenflowDomainId(dpid)
-                     :topologyService.getOpenflowDomainId(dpid));
-            List<String> switchesInCluster = switchClusterMap.get(clusterDpid.toString());
-            if (switchesInCluster != null) {
-                switchesInCluster.add(dpid.toString());
-            } else {
-                List<String> l = new ArrayList<String>();
-                l.add(dpid.toString());
-                switchClusterMap.put(clusterDpid.toString(), l);
-            }
-        }
-        return switchClusterMap;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java b/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java
index 0ae6a09f8fa4513b2d5fb448e8f82563634b7a29..ff5dc3a530aa29acb7e70934fcc194b3681c93bb 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java
@@ -35,11 +35,10 @@ public class TopologyWebRoutable implements RestletRoutable {
         router.attach("/directed-links/json", DirectedLinksResource.class);
         router.attach("/external-links/json", ExternalLinksResource.class);
         router.attach("/tunnellinks/json", TunnelLinksResource.class);
-        router.attach("/switchclusters/json", SwitchClustersResource.class);
-        router.attach("/broadcastdomainports/json", BroadcastDomainPortsResource.class);
+        router.attach("/archipelagos/json", SwitchArchipelagosResource.class);
+        router.attach("/broadcastports/json", AllBroadcastPortsResource.class);
         router.attach("/enabledports/json", EnabledPortsResource.class);
         router.attach("/blockedports/json", BlockedPortsResource.class);
-        router.attach("/route/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", RouteResource.class);
 
         return router;
     }
diff --git a/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java b/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java
index 10edc35264a43c2b9b32257b2a1881c60878d616..a56aba90af8efa2222654cb1dcb6e0f7ea66cf92 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/TunnelLinksResource.java
@@ -16,9 +16,7 @@
 
 package net.floodlightcontroller.topology.web;
 
-import java.util.Set;
-
-import net.floodlightcontroller.core.types.NodePortTuple;
+import net.floodlightcontroller.core.types.JsonObjectWrapper;
 import net.floodlightcontroller.topology.ITopologyService;
 
 import org.restlet.resource.Get;
@@ -26,11 +24,11 @@ import org.restlet.resource.ServerResource;
 
 public class TunnelLinksResource extends ServerResource {
     @Get("json")
-    public Set<NodePortTuple> retrieve() {
+    public JsonObjectWrapper retrieve() {
         ITopologyService topology = 
                 (ITopologyService)getContext().getAttributes().
                     get(ITopologyService.class.getCanonicalName());
         
-        return topology.getTunnelPorts();
+        return JsonObjectWrapper.of(topology.getTunnelPorts());
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/util/OFMessageUtils.java b/src/main/java/net/floodlightcontroller/util/OFMessageUtils.java
index ffca61530dbcab3eda7159bec0a7f86014682ac1..2259e6f0a53e26166a210e55925cbe11966a9101 100644
--- a/src/main/java/net/floodlightcontroller/util/OFMessageUtils.java
+++ b/src/main/java/net/floodlightcontroller/util/OFMessageUtils.java
@@ -35,6 +35,61 @@ public class OFMessageUtils {
 	 */
 	private OFMessageUtils() {};
 
+	/**
+	 * Simple class to streamline the use of OFMessage's
+	 * equalsIgnoreXid() and hashCodeIgnoreXid() functions.
+	 * Use this class to wrap OFMessages prior to inserting
+	 * them in containers where lookup or equality checks
+	 * should not include the XID.
+	 * 
+	 * See {@link net.floodlightcontroller.util.OFMessageDamper}
+	 * as an example where it's used to help cache OFMessages.
+	 * @author rizard
+	 */
+	public static class OFMessageIgnoreXid {
+	    private OFMessage m;
+	    
+	    private OFMessageIgnoreXid() {}
+	    private OFMessageIgnoreXid(OFMessage m) {
+	        this.m = m;
+	    }
+	    
+	    /**
+	     * Wrap an OFMessage to ignore the XID
+	     * when checking for equality or computing
+	     * the OFMessage's hash.
+	     * @param m
+	     * @return
+	     */
+	    public static OFMessageIgnoreXid of(OFMessage m) {
+	        return new OFMessageIgnoreXid(m);
+	    }
+	    
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((m == null) ? 0 : m.hashCodeIgnoreXid());
+            return result;
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            OFMessageIgnoreXid other = (OFMessageIgnoreXid) obj;
+            if (m == null) {
+                if (other.m != null)
+                    return false;
+            } else if (!m.equalsIgnoreXid(other.m))
+                return false;
+            return true;
+        }
+	}
+	
 	/**
 	 * Get the ingress port of a packet-in message. The manner in which
 	 * this is done depends on the OpenFlow version. OF1.0 and 1.1 have
@@ -81,24 +136,6 @@ public class OFMessageUtils {
 		return pi.getMatch().get(MatchField.VLAN_VID) == null ? OFVlanVidMatch.UNTAGGED : pi.getMatch().get(MatchField.VLAN_VID);
 	}
 
-	/**
-	 * Returns true if each object is deeply-equal in the same manner that
-	 * Object's equals() does with the exception of the XID field, which is
-	 * ignored; otherwise, returns false.
-	 * 
-	 * NOTE: This function is VERY INEFFICIENT and creates a new OFMessage
-	 * object in order to the the comparison minus the XID. It is advised
-	 * that you use it sparingly and ideally only within unit tests.
-	 * 
-	 * @param a; object A to compare
-	 * @param b; object B to compare
-	 * @return true if A and B are deeply-equal; false otherwise
-	 */
-	public static boolean equalsIgnoreXid(OFMessage a, OFMessage b) {
-		OFMessage.Builder mb = b.createBuilder().setXid(a.getXid());
-		return a.equals(mb.build());
-	}
-
 	/**
 	 * Writes an OFPacketOut message to a switch.
 	 * 
diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
index fe0e65f518d97bde01ca6da5f7db5921aa8c7919..3568e34bdbca7c5cbcb9655805595a976baed327 100644
--- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
+++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
@@ -26,4 +26,5 @@ net.floodlightcontroller.firewall.Firewall
 net.floodlightcontroller.accesscontrollist.ACL
 net.floodlightcontroller.dhcpserver.DHCPServer
 net.floodlightcontroller.learningswitch.LearningSwitch
-net.floodlightcontroller.statistics.StatisticsCollector
\ No newline at end of file
+net.floodlightcontroller.statistics.StatisticsCollector
+net.floodlightcontroller.routing.RoutingManager
\ No newline at end of file
diff --git a/src/main/resources/floodlightNodeBackup.properties b/src/main/resources/floodlightNodeBackup.properties
index 82d97aa68310d12700fa77db0759a958f8fd0d61..d7742e014d44910cbba51179e2247310a7066377 100644
--- a/src/main/resources/floodlightNodeBackup.properties
+++ b/src/main/resources/floodlightNodeBackup.properties
@@ -10,11 +10,11 @@ net.floodlightcontroller.forwarding.Forwarding,\
 net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager,\
 net.floodlightcontroller.ui.web.StaticWebRoutable,\
 net.floodlightcontroller.loadbalancer.LoadBalancer,\
-net.floodlightcontroller.loadbalancer.LoadBalancer,\
 net.floodlightcontroller.firewall.Firewall,\
 net.floodlightcontroller.simpleft.FT,\
 net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
 net.floodlightcontroller.accesscontrollist.ACL,\
+net.floodlightcontroller.routing.RoutingManager,\
 net.floodlightcontroller.statistics.StatisticsCollector
 org.sdnplatform.sync.internal.SyncManager.authScheme=CHALLENGE_RESPONSE
 org.sdnplatform.sync.internal.SyncManager.keyStorePath=/etc/floodlight/key2.jceks
diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties
index 31a9dead47b56ad42126176ed60a316c06233cfc..e757e85f4bc498a01f1d5cddb71d97973af6f943 100644
--- a/src/main/resources/floodlightdefault.properties
+++ b/src/main/resources/floodlightdefault.properties
@@ -8,6 +8,7 @@ net.floodlightcontroller.perfmon.PktInProcessingTime,\
 net.floodlightcontroller.staticentry.StaticEntryPusher,\
 net.floodlightcontroller.restserver.RestApiServer,\
 net.floodlightcontroller.topology.TopologyManager,\
+net.floodlightcontroller.routing.RoutingManager,\
 net.floodlightcontroller.forwarding.Forwarding,\
 net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager,\
 net.floodlightcontroller.ui.web.StaticWebRoutable,\
@@ -21,7 +22,7 @@ org.sdnplatform.sync.internal.SyncManager.authScheme=CHALLENGE_RESPONSE
 org.sdnplatform.sync.internal.SyncManager.keyStorePath=/etc/floodlight/key2.jceks
 org.sdnplatform.sync.internal.SyncManager.dbPath=/var/lib/floodlight/
 org.sdnplatform.sync.internal.SyncManager.keyStorePassword=PassWord
-org.sdnplatform.sync.internal.SyncManager.port=6642
+org.sdnplatform.sync.internal.SyncManager.port=6009
 org.sdnplatform.sync.internal.SyncManager.thisNodeId=1
 org.sdnplatform.sync.internal.SyncManager.persistenceEnabled=FALSE
 org.sdnplatform.sync.internal.SyncManager.nodes=[\
@@ -62,4 +63,6 @@ net.floodlightcontroller.restserver.RestApiServer.httpsPort=8081
 net.floodlightcontroller.restserver.RestApiServer.httpPort=8080
 net.floodlightcontroller.restserver.RestApiServer.accessControlAllowAllOrigins=TRUE
 net.floodlightcontroller.statistics.StatisticsCollector.enable=FALSE
-net.floodlightcontroller.statistics.StatisticsCollector.collectionIntervalPortStatsSeconds=10
\ No newline at end of file
+net.floodlightcontroller.statistics.StatisticsCollector.collectionIntervalPortStatsSeconds=10
+net.floodlightcontroller.topology.TopologyManager.pathMetric=latency
+net.floodlightcontroller.topology.TopologyManager.maxPathsToCompute=3
\ No newline at end of file
diff --git a/src/test/java/net/floodlightcontroller/accesscontrollist/ACLTest.java b/src/test/java/net/floodlightcontroller/accesscontrollist/ACLTest.java
index 7fa8150689f0054e21390bb4062f2df6ea4233a6..cf01c8cdad2c57ae7776e61b0ec587f2312007c0 100644
--- a/src/test/java/net/floodlightcontroller/accesscontrollist/ACLTest.java
+++ b/src/test/java/net/floodlightcontroller/accesscontrollist/ACLTest.java
@@ -408,7 +408,7 @@ public class ACLTest extends FloodlightTestCase {
 	public void testDeviceIPV4AddrChanged() {
 		
 		reset(topology);
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(1))).andReturn(true).anyTimes();
 		replay(topology);
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index 3c5d6fea36af340530b01260d1a0c1b2bcad66aa..9689f6eeca3adf3293b0be0d291c004c7c3e5daf 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -154,13 +154,13 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		ITopologyService mockTopology = createMock(ITopologyService.class);
 		mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()));
 		expectLastCall().andReturn(true).anyTimes();
-		mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()));
+		mockTopology.getClusterId(DatapathId.of(anyLong()));
 		expectLastCall().andReturn(DatapathId.of(1L)).anyTimes();
-		mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort()));
+		mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort()));
 		expectLastCall().andReturn(false).anyTimes();
 		mockTopology.isConsistent(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(anyShort()));
 		expectLastCall().andReturn(false).anyTimes();
-		mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(anyShort()));
+		mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong()));
 		expectLastCall().andReturn(false).anyTimes();
 		return mockTopology;
 	}
@@ -403,9 +403,9 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		deviceManager.startUp(null);
 
 		ITopologyService mockTopology = createMock(ITopologyService.class);
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()))).
+		expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
+		expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
 		andReturn(false).anyTimes();
 
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
@@ -574,9 +574,9 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		deviceManager.startUp(null);
 
 		ITopologyService mockTopology = createMock(ITopologyService.class);
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()))).
+		expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
+		expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
 		andReturn(false).anyTimes();
 
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
@@ -784,18 +784,18 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		reset(mockListener);
 
 		ITopologyService mockTopology = createMock(ITopologyService.class);
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(1L))).
+		expect(mockTopology.getClusterId(DatapathId.of(1L))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(5L))).
+		expect(mockTopology.getClusterId(DatapathId.of(5L))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(10L))).
+		expect(mockTopology.getClusterId(DatapathId.of(10L))).
 		andReturn(DatapathId.of(10L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(50L))).
+		expect(mockTopology.getClusterId(DatapathId.of(50L))).
 		andReturn(DatapathId.of(10L)).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
+		expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
 		andReturn(false).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()),
-				DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(false).anyTimes();
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()),
+				DatapathId.of(anyLong()))).andReturn(false).anyTimes();
 
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).andReturn(true).anyTimes();
@@ -901,18 +901,17 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		reset(mockListener);
 
 		ITopologyService mockTopology = createMock(ITopologyService.class);
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(1L))).
+		expect(mockTopology.getClusterId(DatapathId.of(1L))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(2L))).
+		expect(mockTopology.getClusterId(DatapathId.of(2L))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(3L))).
+		expect(mockTopology.getClusterId(DatapathId.of(3L))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(4L))).
+		expect(mockTopology.getClusterId(DatapathId.of(4L))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
+		expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
 		.andReturn(false).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()),
-				DatapathId.of(anyLong()), OFPort.of(anyShort())))
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong())))
 				.andReturn(false).anyTimes();
 
 		expect(mockTopology.isAttachmentPointPort(or(eq(DatapathId.of(1L)), eq(DatapathId.of(3L))), OFPort.of(anyShort())))
@@ -1025,18 +1024,17 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		reset(mockListener);
 
 		ITopologyService mockTopology = createMock(ITopologyService.class);
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(1L))). /* two different OpenFlow islands, 1 and 10 */
+		expect(mockTopology.getClusterId(DatapathId.of(1L))). /* two different OpenFlow islands, 1 and 10 */
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(5L))).
+		expect(mockTopology.getClusterId(DatapathId.of(5L))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(10L))).
+		expect(mockTopology.getClusterId(DatapathId.of(10L))).
 		andReturn(DatapathId.of(10L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(50L))).
+		expect(mockTopology.getClusterId(DatapathId.of(50L))).
 		andReturn(DatapathId.of(10L)).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
+		expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
 		.andReturn(false).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()),
-				DatapathId.of(anyLong()), OFPort.of(anyShort())))
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong())))
 				.andReturn(false).anyTimes();
 
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
@@ -1131,17 +1129,14 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 	@Test
 	public void testBDAttachmentPointLearning() throws Exception {
 		ITopologyService mockTopology = createMock(ITopologyService.class);
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
 		andReturn(true).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(1L), OFPort.of(1))).
+		expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(1))).
 		andReturn(false).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(1L), OFPort.of(2))).
+		expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(2))).
 		andReturn(true).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(1L), OFPort.of(1),
-				DatapathId.of(1L), OFPort.of(2))).andReturn(true).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(1L), OFPort.of(2),
-				DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(1L), DatapathId.of(1L))).andReturn(true).anyTimes();
 		expect(mockTopology.isConsistent(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(false).anyTimes();
 
 		Date topologyUpdateTime = new Date();
@@ -1192,22 +1187,17 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 	@Test
 	public void testLOCALAttachmentPointLearning() throws Exception {
 		ITopologyService mockTopology = createMock(ITopologyService.class);
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()))).
+		expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).
 		andReturn(DatapathId.of(1L)).anyTimes();
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort()))).
 		andReturn(true).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(1L), OFPort.of(1))).
+		expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(1))).
 		andReturn(false).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(1L), OFPort.LOCAL)).
+		expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.LOCAL)).
 		andReturn(false).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(1L), OFPort.of(2))).
+		expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(2))).
 		andReturn(true).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(1L), OFPort.of(1),
-				DatapathId.of(1L), OFPort.LOCAL)).andReturn(true).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(1L), OFPort.LOCAL,
-				DatapathId.of(1L), OFPort.of(2))).andReturn(true).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(1L), OFPort.of(2),
-				DatapathId.of(1L), OFPort.LOCAL)).andReturn(true).anyTimes();
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(1L), DatapathId.of(1L))).andReturn(true).anyTimes();
 		expect(mockTopology.isConsistent(DatapathId.of(anyLong()), OFPort.of(anyShort()), DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(false).anyTimes();
 
 		Date topologyUpdateTime = new Date();
@@ -1261,15 +1251,13 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 				DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort()))).andReturn(false).
 				anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(EasyMock.anyLong()),
+		expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort())))
 				.andReturn(false)
 				.anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()),
-				OFPort.of(anyShort()),
-				DatapathId.of(anyLong()),
-				OFPort.of(anyShort())))
+		expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()),
+				DatapathId.of(anyLong())))
 				.andReturn(false).anyTimes();
 
 	}
@@ -1726,10 +1714,10 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).andReturn(true).anyTimes();
 
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(1L), OFPort.of(1))).andReturn(false).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(5L), OFPort.of(1))).andReturn(false).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); /* different islands */
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(5L))).andReturn(DatapathId.of(5L)).anyTimes();
+		expect(mockTopology.isBroadcastPort(DatapathId.of(1L), OFPort.of(1))).andReturn(false).anyTimes();
+		expect(mockTopology.isBroadcastPort(DatapathId.of(5L), OFPort.of(1))).andReturn(false).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes(); /* different islands */
+		expect(mockTopology.getClusterId(DatapathId.of(5L))).andReturn(DatapathId.of(5L)).anyTimes();
 		expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(5L), OFPort.of(1))).
 		andReturn(false).anyTimes();
 
@@ -1817,14 +1805,14 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 				OFPort.of(EasyMock.anyShort()))).
 				andReturn(true).
 				anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(5L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(5L))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort()),
 				DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort()))).andReturn(false).
 				anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(EasyMock.anyLong()),
+		expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort()))).
 				andReturn(false).anyTimes();
 		replay(mockTopology);
@@ -1959,12 +1947,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		ITopologyService mockTopology = createMock(ITopologyService.class);
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).andReturn(true).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()),
+		expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).
 				andReturn(false).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()),
-				DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(false).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()))).
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong())))
+		.andReturn(false).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).
 		andReturn(DatapathId.of(1L)).anyTimes();
 		expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(1))).
 		andReturn(true).anyTimes();
@@ -2049,14 +2037,14 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		ITopologyService mockTopology = createMock(ITopologyService.class);
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).andReturn(true).anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(anyLong()),
+		expect(mockTopology.isBroadcastPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).
 				andReturn(false).anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(anyLong()), OFPort.of(anyShort()),
-				DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(false).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(1L))).
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(anyLong()), DatapathId.of(anyLong())))
+		.andReturn(false).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(1L))).
 		andReturn(DatapathId.of(1L)).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(5L))).
+		expect(mockTopology.getClusterId(DatapathId.of(5L))).
 		andReturn(DatapathId.of(5L)).anyTimes();
 		expect(mockTopology.isConsistent(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(2))).
 		andReturn(false).anyTimes();
@@ -2233,7 +2221,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).
 				andReturn(true).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
 		replay(mockTopology);
 		doTestDeviceQuery();
 	}
@@ -2245,7 +2233,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).
 				andReturn(true).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
 		replay(mockTopology);
 
 		doTestDeviceQuery();
@@ -2330,7 +2318,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).
 				andReturn(true).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
 		replay(mockTopology);
 
 		doTestDeviceClassQuery();
@@ -2342,7 +2330,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		deviceManager.topology = mockTopology;
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).andReturn(true).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
 		replay(mockTopology);
 
 		doTestDeviceClassQuery();
@@ -2359,7 +2347,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).
 				andReturn(true).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(EasyMock.anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
 		replay(mockTopology);
 
 		Entity entity1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.of(1), IPv6Address.NONE, DatapathId.of(1L), OFPort.of(1), new Date());
@@ -2493,21 +2481,19 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).
 				andReturn(true).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort()),
 				DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort())))
 				.andReturn(false)
 				.anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(EasyMock.anyLong()),
+		expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort())))
 				.andReturn(false)
 				.anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(EasyMock.anyLong()),
-				OFPort.of(EasyMock.anyShort()),
-				DatapathId.of(EasyMock.anyLong()),
-				OFPort.of(EasyMock.anyShort()))).
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(EasyMock.anyLong()),
+				DatapathId.of(EasyMock.anyLong()))).
 				andReturn(false).anyTimes();
 		replay(mockTopology);
 
@@ -2604,21 +2590,19 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).
 				andReturn(true).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort()),
 				DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort())))
 				.andReturn(false)
 				.anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(EasyMock.anyLong()),
+		expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort())))
 				.andReturn(false)
 				.anyTimes();
-		expect(mockTopology.isInSameBroadcastDomain(DatapathId.of(EasyMock.anyLong()),
-				OFPort.of(EasyMock.anyShort()),
-				DatapathId.of(EasyMock.anyLong()),
-				OFPort.of(EasyMock.anyShort()))).
+		expect(mockTopology.isInSameArchipelago(DatapathId.of(EasyMock.anyLong()),
+				DatapathId.of(EasyMock.anyLong()))).
 				andReturn(false).anyTimes();
 		replay(mockTopology);
 
@@ -2742,14 +2726,14 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		expect(mockTopology.isAttachmentPointPort(DatapathId.of(anyLong()),
 				OFPort.of(anyShort()))).
 				andReturn(true).anyTimes();
-		expect(mockTopology.getOpenflowDomainId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(mockTopology.getClusterId(DatapathId.of(anyLong()))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(mockTopology.isConsistent(DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort()),
 				DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort())))
 				.andReturn(false)
 				.anyTimes();
-		expect(mockTopology.isBroadcastDomainPort(DatapathId.of(EasyMock.anyLong()),
+		expect(mockTopology.isBroadcastPort(DatapathId.of(EasyMock.anyLong()),
 				OFPort.of(EasyMock.anyShort())))
 				.andReturn(false)
 				.anyTimes();
diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
index beaf22ad490c5adaffb2ed63fcc97e5781153cba..d8dbedcd8b22eee6993509ee154772b021db89e9 100644
--- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
+++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
@@ -55,7 +55,7 @@ import net.floodlightcontroller.packet.IPv6;
 import net.floodlightcontroller.packet.UDP;
 import net.floodlightcontroller.routing.IRoutingDecision.RoutingAction;
 import net.floodlightcontroller.routing.IRoutingService;
-import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.Path;
 import net.floodlightcontroller.routing.RoutingDecision;
 import net.floodlightcontroller.test.FloodlightTestCase;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
@@ -159,7 +159,7 @@ public class ForwardingTest extends FloodlightTestCase {
 
 		topology.addListener(anyObject(ITopologyListener.class));
 		expectLastCall().anyTimes();
-		expect(topology.isIncomingBroadcastAllowed(anyObject(DatapathId.class), anyObject(OFPort.class))).andReturn(true).anyTimes();
+		expect(topology.isBroadcastAllowed(anyObject(DatapathId.class), anyObject(OFPort.class))).andReturn(true).anyTimes();
 		replay(topology);
 
 		threadPool.init(fmc);
@@ -476,15 +476,15 @@ public class ForwardingTest extends FloodlightTestCase {
 		Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
 		Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
 
-		Route route = new Route(DatapathId.of(1L), DatapathId.of(2L));
+		Path path = new Path(DatapathId.of(1L), DatapathId.of(2L));
 		List<NodePortTuple> nptList = new ArrayList<NodePortTuple>();
 		nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
 		nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
 		nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(1)));
 		nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3)));
-		route.setPath(nptList);
+		path.setPath(nptList);
 		reset(routingEngine);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3))).andReturn(path).atLeastOnce();
 		
 		// Expected Flow-mods
 		Match match = packetIn.getMatch();
@@ -507,11 +507,11 @@ public class ForwardingTest extends FloodlightTestCase {
 		expect(sw2.write(capture(wc2))).andReturn(true).anyTimes();
 
 		reset(topology);
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
-		expect(topology.getOpenflowDomainId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L),  OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(2L),  OFPort.of(3))).andReturn(true).anyTimes();
-		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
 		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isEdge(DatapathId.of(2L), OFPort.of(3))).andReturn(true).anyTimes();
 
@@ -527,15 +527,15 @@ public class ForwardingTest extends FloodlightTestCase {
 
 		for (OFMessage m: msglist) {
 			if (m instanceof OFFlowMod)
-				assertTrue(OFMessageUtils.equalsIgnoreXid(fm1, m));
+				assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(fm1), OFMessageUtils.OFMessageIgnoreXid.of(m));
 			else if (m instanceof OFPacketOut) {
-				assertTrue(OFMessageUtils.equalsIgnoreXid(packetOut, m));
+                assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(packetOut), OFMessageUtils.OFMessageIgnoreXid.of(m));
 			}
 		}
 
 		OFMessage m = wc2.getValue();
 		assert (m instanceof OFFlowMod);
-		assertTrue(OFMessageUtils.equalsIgnoreXid(m, fm2));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(m), OFMessageUtils.OFMessageIgnoreXid.of(fm2));
 		
 		removeDeviceFromContext();
 	}
@@ -547,7 +547,7 @@ public class ForwardingTest extends FloodlightTestCase {
 		Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
 		Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
 
-		Route route = new Route(DatapathId.of(1L), DatapathId.of(2L));
+		Path route = new Path(DatapathId.of(1L), DatapathId.of(2L));
 		List<NodePortTuple> nptList = new ArrayList<NodePortTuple>();
 		nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
 		nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
@@ -555,8 +555,8 @@ public class ForwardingTest extends FloodlightTestCase {
 		nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3)));
 		route.setPath(nptList);
 		reset(routingEngine);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
-		
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3))).andReturn(route).atLeastOnce();
+
 		// Expected Flow-mods
 		Match match = packetInIPv6.getMatch();
 		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
@@ -578,11 +578,11 @@ public class ForwardingTest extends FloodlightTestCase {
 		expect(sw2.write(capture(wc2))).andReturn(true).anyTimes();
 
 		reset(topology);
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
-		expect(topology.getOpenflowDomainId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L),  OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(2L),  OFPort.of(3))).andReturn(true).anyTimes();
-		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
 		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isEdge(DatapathId.of(2L), OFPort.of(3))).andReturn(true).anyTimes();
 		
@@ -598,15 +598,15 @@ public class ForwardingTest extends FloodlightTestCase {
 
 		for (OFMessage m: msglist) {
 			if (m instanceof OFFlowMod)
-				assertTrue(OFMessageUtils.equalsIgnoreXid(fm1, m));
+                assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(fm1), OFMessageUtils.OFMessageIgnoreXid.of(m));
 			else if (m instanceof OFPacketOut) {
-				assertTrue(OFMessageUtils.equalsIgnoreXid(packetOutIPv6, m));
+                assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(packetOutIPv6), OFMessageUtils.OFMessageIgnoreXid.of(m));
 			}
 		}
 
 		OFMessage m = wc2.getValue();
 		assert (m instanceof OFFlowMod);
-		assertTrue(OFMessageUtils.equalsIgnoreXid(m, fm2));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(m), OFMessageUtils.OFMessageIgnoreXid.of(fm2));
 		
 		removeDeviceFromContext();
 	}
@@ -618,10 +618,11 @@ public class ForwardingTest extends FloodlightTestCase {
 		Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
 		Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
 
-		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
+		Path route = new  Path(DatapathId.of(1L), DatapathId.of(1L));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
-		
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(route).atLeastOnce();
+
 		// Expected Flow-mods
 		Match match = packetIn.getMatch();
 		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
@@ -645,8 +646,8 @@ public class ForwardingTest extends FloodlightTestCase {
 		expect(sw1.write(capture(wc2))).andReturn(true).once();
 
 		reset(topology);
-		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
 		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
@@ -654,7 +655,7 @@ public class ForwardingTest extends FloodlightTestCase {
 
 		// Reset mocks, trigger the packet in, and validate results
 		reset(routingEngine);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(route).atLeastOnce();
 		replay(sw1, sw2, routingEngine, topology);
 		forwarding.receive(sw1, this.packetIn, cntx);
 		verify(sw1, sw2, routingEngine);
@@ -662,8 +663,8 @@ public class ForwardingTest extends FloodlightTestCase {
 		assertTrue(wc1.hasCaptured());
 		assertTrue(wc2.hasCaptured());
 
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1));
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOut));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(fm1));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc2.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(packetOut));
 		
 		removeDeviceFromContext();
 	}
@@ -675,11 +676,11 @@ public class ForwardingTest extends FloodlightTestCase {
 		Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
 		Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
 
-		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
+		Path route = new  Path(DatapathId.of(1L), DatapathId.of(1L));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
 		reset(routingEngine);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(route).atLeastOnce();
 		
 		// Expected Flow-mods
 		Match match = packetInIPv6.getMatch();
@@ -702,8 +703,8 @@ public class ForwardingTest extends FloodlightTestCase {
 		expect(sw1.write(capture(wc2))).andReturn(true).once();
 
 		reset(topology);
-		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L),  OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L),  OFPort.of(3))).andReturn(true).anyTimes();
 		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
@@ -717,8 +718,8 @@ public class ForwardingTest extends FloodlightTestCase {
 		assertTrue(wc1.hasCaptured());
 		assertTrue(wc2.hasCaptured());
 
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1));
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOutIPv6));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(fm1));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc2.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(packetOutIPv6));
 		
 		removeDeviceFromContext();
 	}
@@ -731,14 +732,14 @@ public class ForwardingTest extends FloodlightTestCase {
 		reset(topology);
 		expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
 		.andReturn(true).anyTimes();
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
 		replay(topology);
 
 
-		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
+		Path route = new  Path(DatapathId.of(1L), DatapathId.of(1L));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
 		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce();
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(route).atLeastOnce();
 
 		// Expected Flow-mods
 		Match match = packetIn.getMatch();
@@ -766,8 +767,8 @@ public class ForwardingTest extends FloodlightTestCase {
 		expectLastCall().times(3);
 
 		reset(topology);
-		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L),  OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L),  OFPort.of(3))).andReturn(true).anyTimes();
 
@@ -808,7 +809,7 @@ public class ForwardingTest extends FloodlightTestCase {
 		verify(sw1, sw2, routingEngine);
 
 		assertTrue(wc1.hasCaptured());
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), packetOutFlooded));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(packetOutFlooded));
 		
 		removeDeviceFromContext();
 	}
@@ -843,7 +844,7 @@ public class ForwardingTest extends FloodlightTestCase {
 		verify(sw1, sw2, routingEngine);
 
 		assertTrue(wc1.hasCaptured());
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), packetOutFloodedIPv6));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(packetOutFloodedIPv6));
 		
 		removeDeviceFromContext();
 	}
@@ -858,11 +859,11 @@ public class ForwardingTest extends FloodlightTestCase {
 		Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
 		Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
 
-		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
-		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
-		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
+		Path path = new Path(DatapathId.of(1L), DatapathId.of(1L));
+		path.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
+		path.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
 		reset(routingEngine);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), Forwarding.DEFAULT_FORWARDING_COOKIE)).andReturn(route).atLeastOnce();
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(path).atLeastOnce();
 		
 		// Expected Flow-mods
 		Match match = packetIn.getMatch();
@@ -889,8 +890,8 @@ public class ForwardingTest extends FloodlightTestCase {
 		expect(sw1.write(capture(wc2))).andReturn(true).once();
 
 		reset(topology);
-		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
 		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
@@ -904,68 +905,68 @@ public class ForwardingTest extends FloodlightTestCase {
 		assertTrue(wc1.hasCaptured());
 		assertTrue(wc2.hasCaptured());
 
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1));
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOut));
+		assertTrue(wc1.getValue().equalsIgnoreXid(fm1));
+		assertTrue(wc2.getValue().equalsIgnoreXid(packetOut));
 	}
 	
 	@Test
-	public void testForwardDecisionForwardingCookieNotZero() throws Exception {
-		learnDevices(DestDeviceToLearn.DEVICE2);
-		
-		Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
-		Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
-
-		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
-		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
-		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
-		reset(routingEngine);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.of(0x200000FFffFFffL))).andReturn(route).atLeastOnce();
-		
-		// Expected Flow-mods
-		Match match = packetIn.getMatch();
-		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
-		List<OFAction> actions = new ArrayList<OFAction>();
-		actions.add(action);
-		
-		RoutingDecision decision = new RoutingDecision(DatapathId.of(1L), OFPort.of(1), dstDevice1, RoutingAction.FORWARD);
-		decision.setDescriptor(U64.of(0x00000000ffffffffL));
-		decision.addToContext(cntx);
-		//RoutingDecision de2 = (RoutingDecision) RoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); // Same as decision
-		//(DatapathId swDipd, OFPort inPort, IDevice srcDevice, RoutingAction action);
-		
-		OFFlowMod fm1 = factory.buildFlowAdd()
-				.setIdleTimeout((short)5)
-				.setMatch(match)
-				.setActions(actions)
-				.setOutPort(OFPort.of(3))
-				.setBufferId(OFBufferId.NO_BUFFER)
-				.setCookie(U64.of(2L<< 52 | 0xFFffFFffL))
-				.setPriority(1)
-				.build();
-
-		// Record expected packet-outs/flow-mods
-		expect(sw1.write(capture(wc1))).andReturn(true).once();
-		expect(sw1.write(capture(wc2))).andReturn(true).once();
-
-		reset(topology);
-		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
-		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
-		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
-		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
-		expect(topology.isEdge(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
-
-		// Reset mocks, trigger the packet in, and validate results
-		replay(sw1, sw2, routingEngine, topology);
-		forwarding.receive(sw1, this.packetIn, cntx);
-		verify(sw1, sw2, routingEngine);
-
-		assertTrue(wc1.hasCaptured());
-		assertTrue(wc2.hasCaptured());
-		
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1));
-		assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOut));
-	}
+    public void testForwardDecisionForwardingCookieNotZero() throws Exception {
+        learnDevices(DestDeviceToLearn.DEVICE2);
+        
+        Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
+        Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
+
+        Path path = new Path(DatapathId.of(1L), DatapathId.of(1L));
+        path.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
+        path.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
+        reset(routingEngine);
+        expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(path).atLeastOnce();
+        
+        // Expected Flow-mods
+        Match match = packetIn.getMatch();
+        OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
+        List<OFAction> actions = new ArrayList<OFAction>();
+        actions.add(action);
+        
+        RoutingDecision decision = new RoutingDecision(DatapathId.of(1L), OFPort.of(1), dstDevice1, RoutingAction.FORWARD);
+        decision.setDescriptor(U64.of(0x00000000ffffffffL));
+        decision.addToContext(cntx);
+        //RoutingDecision de2 = (RoutingDecision) RoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); // Same as decision
+        //(DatapathId swDipd, OFPort inPort, IDevice srcDevice, RoutingAction action);
+        
+        OFFlowMod fm1 = factory.buildFlowAdd()
+                .setIdleTimeout((short)5)
+                .setMatch(match)
+                .setActions(actions)
+                .setOutPort(OFPort.of(3))
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setCookie(U64.of(2L<< 52 | 0xFFffFFffL))
+                .setPriority(1)
+                .build();
+
+        // Record expected packet-outs/flow-mods
+        expect(sw1.write(capture(wc1))).andReturn(true).once();
+        expect(sw1.write(capture(wc2))).andReturn(true).once();
+
+        reset(topology);
+        expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+        expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+        expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
+        expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
+        expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
+        expect(topology.isEdge(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
+
+        // Reset mocks, trigger the packet in, and validate results
+        replay(sw1, sw2, routingEngine, topology);
+        forwarding.receive(sw1, this.packetIn, cntx);
+        verify(sw1, sw2, routingEngine);
+
+        assertTrue(wc1.hasCaptured());
+        assertTrue(wc2.hasCaptured());
+        
+        assertTrue(wc1.getValue().equalsIgnoreXid(fm1));
+        assertTrue(wc2.getValue().equalsIgnoreXid(packetOut));
+    }
 
 	@Test
 	public void testForwardDeleteFlowsByDescriptorSingle() throws Exception {
diff --git a/src/test/java/net/floodlightcontroller/hub/HubTest.java b/src/test/java/net/floodlightcontroller/hub/HubTest.java
index 6fcd37e81669945e853450426cb09a2fb97b8c23..61ddd24bad2daa35e5e9f44e11cb2b2bc1547b95 100644
--- a/src/test/java/net/floodlightcontroller/hub/HubTest.java
+++ b/src/test/java/net/floodlightcontroller/hub/HubTest.java
@@ -138,7 +138,7 @@ public class HubTest extends FloodlightTestCase {
         
         assertTrue(wc1.hasCaptured());
         OFMessage m = wc1.getValue();
-        assertTrue(OFMessageUtils.equalsIgnoreXid(m, po));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(m), OFMessageUtils.OFMessageIgnoreXid.of(po));
     }
 
     @Test
diff --git a/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java b/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java
index eb884f4406694a574b31dd31a1a3fb33d1dd176b..8796e3f62f5f8b0153cc18565b55d10de5985e62 100644
--- a/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java
+++ b/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java
@@ -204,7 +204,7 @@ public class LearningSwitchTest extends FloodlightTestCase {
         verify(mockSwitch);
         
         assertTrue(wc1.hasCaptured());
-        assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), po));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(po));
 
         // Verify the MAC table inside the switch
         assertEquals(OFPort.of(1), result);
@@ -291,9 +291,9 @@ public class LearningSwitchTest extends FloodlightTestCase {
         assertTrue(wc1.hasCaptured());
         assertTrue(wc2.hasCaptured());
         assertTrue(wc3.hasCaptured());
-        assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), packetOut));
-        assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), fm1));
-        assertTrue(OFMessageUtils.equalsIgnoreXid(wc3.getValue(), fm2));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(packetOut));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc2.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(fm1));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc3.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(fm2));
 
         // Verify the MAC table inside the switch
         assertEquals(OFPort.of(1), result);
diff --git a/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManagerTest.java b/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManagerTest.java
index 7ba7ee0d417ddf802f31bbbf1d5385f583e52711..8d5ea89b7dfd72800d59d8874f38b6b648b53f6e 100644
--- a/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManagerTest.java
+++ b/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManagerTest.java
@@ -48,6 +48,7 @@ import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.debugcounter.MockDebugCounterService;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
+import net.floodlightcontroller.linkdiscovery.Link;
 import net.floodlightcontroller.packet.Data;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
@@ -56,7 +57,6 @@ import net.floodlightcontroller.packet.UDP;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.restserver.RestApiServer;
 import net.floodlightcontroller.routing.IRoutingService;
-import net.floodlightcontroller.routing.Link;
 import net.floodlightcontroller.storage.IStorageSourceService;
 import net.floodlightcontroller.storage.memory.MemoryStorageSource;
 import net.floodlightcontroller.test.FloodlightTestCase;
diff --git a/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java b/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java
index 09bfec33a7769a78c7896a7204cf0de561b30868..df26f7c614bdb46e4dac1a10a885bdbf38006920 100644
--- a/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java
+++ b/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java
@@ -51,7 +51,6 @@ import org.projectfloodlight.openflow.types.IpProtocol;
 import org.projectfloodlight.openflow.types.MacAddress;
 import org.projectfloodlight.openflow.types.OFBufferId;
 import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.U64;
 import org.projectfloodlight.openflow.types.VlanVid;
 import org.projectfloodlight.openflow.protocol.OFPacketInReason;
 import org.projectfloodlight.openflow.protocol.action.OFAction;
@@ -81,7 +80,7 @@ import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.restserver.RestApiServer;
 import net.floodlightcontroller.routing.IRoutingService;
-import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.Path;
 import net.floodlightcontroller.staticentry.IStaticEntryPusherService;
 import net.floodlightcontroller.staticentry.StaticEntryPusher;
 import net.floodlightcontroller.storage.IStorageSourceService;
@@ -460,8 +459,8 @@ public class LoadBalancerTest extends FloodlightTestCase {
 
 		// Build topology
 		reset(topology);
-		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
-		expect(topology.getOpenflowDomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(2))).andReturn(true).anyTimes();
 		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
@@ -541,7 +540,7 @@ public class LoadBalancerTest extends FloodlightTestCase {
 
 		for (OFMessage m: msglist1) {
 			if (m instanceof OFPacketOut)
-				assertTrue(OFMessageUtils.equalsIgnoreXid(arpReplyPacketOut1, m));
+                assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(arpReplyPacketOut1), OFMessageUtils.OFMessageIgnoreXid.of(m));
 			else
 				assertTrue(false); // unexpected message
 		}
@@ -627,36 +626,36 @@ public class LoadBalancerTest extends FloodlightTestCase {
 				DatapathId.of(1), OFPort.of(4));
 
 		// in bound #1
-		Route route1 = new Route(DatapathId.of(1L), DatapathId.of(1L));
+		Path route1 = new Path(DatapathId.of(1L), DatapathId.of(1L));
 		List<NodePortTuple> nptList1 = new ArrayList<NodePortTuple>();
 		nptList1.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
 		nptList1.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
 		route1.setPath(nptList1);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.of(0))).andReturn(route1).atLeastOnce();
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(route1).atLeastOnce();
 
 		// outbound #1
-		Route route2 = new Route(DatapathId.of(1L), DatapathId.of(1L));
+		Path route2 = new Path(DatapathId.of(1L), DatapathId.of(1L));
 		List<NodePortTuple> nptList2 = new ArrayList<NodePortTuple>();
 		nptList2.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
 		nptList2.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
 		route2.setPath(nptList2);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(3), DatapathId.of(1L), OFPort.of(1), U64.of(0))).andReturn(route2).atLeastOnce();
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(3), DatapathId.of(1L), OFPort.of(1))).andReturn(route2).atLeastOnce();
 
 		// inbound #2
-		Route route3 = new Route(DatapathId.of(1L), DatapathId.of(1L));
+		Path route3 = new Path(DatapathId.of(1L), DatapathId.of(1L));
 		List<NodePortTuple> nptList3 = new ArrayList<NodePortTuple>();
 		nptList3.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(2)));
 		nptList3.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(4)));
 		route3.setPath(nptList3);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(2), DatapathId.of(1L), OFPort.of(4), U64.of(0))).andReturn(route3).atLeastOnce();
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(2), DatapathId.of(1L), OFPort.of(4))).andReturn(route3).atLeastOnce();
 
 		// outbound #2
-		Route route4 = new Route(DatapathId.of(1L), DatapathId.of(1L));
+		Path route4 = new Path(DatapathId.of(1L), DatapathId.of(1L));
 		List<NodePortTuple> nptList4 = new ArrayList<NodePortTuple>();
 		nptList4.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(4)));
 		nptList4.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(2)));
 		route4.setPath(nptList3);
-		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(4), DatapathId.of(1L), OFPort.of(2), U64.of(0))).andReturn(route4).atLeastOnce();
+		expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(4), DatapathId.of(1L), OFPort.of(2))).andReturn(route4).atLeastOnce();
 
 		replay(routingEngine);
 
diff --git a/src/test/java/net/floodlightcontroller/routing/RouteTest.java b/src/test/java/net/floodlightcontroller/routing/RouteTest.java
index 92ec44e5a1c8a88d9f72a96795762f8f743c2c9b..2b3b97747b87818be787c9308bed26800fca106a 100644
--- a/src/test/java/net/floodlightcontroller/routing/RouteTest.java
+++ b/src/test/java/net/floodlightcontroller/routing/RouteTest.java
@@ -24,7 +24,7 @@ import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
 
 import net.floodlightcontroller.core.types.NodePortTuple;
-import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.routing.Path;
 import net.floodlightcontroller.test.FloodlightTestCase;
 
 /**
@@ -34,13 +34,13 @@ import net.floodlightcontroller.test.FloodlightTestCase;
 public class RouteTest extends FloodlightTestCase {
     @Test
     public void testCloneable() throws Exception {
-        Route r1 = new Route(DatapathId.of(1L), DatapathId.of(2L));
-        Route r2 = new Route(DatapathId.of(1L), DatapathId.of(3L));
+        Path r1 = new Path(DatapathId.of(1L), DatapathId.of(2L));
+        Path r2 = new Path(DatapathId.of(1L), DatapathId.of(3L));
 
         assertNotSame(r1, r2);
         assertNotSame(r1.getId(), r2.getId());
 
-        r1 = new Route(DatapathId.of(1L), DatapathId.of(3L));
+        r1 = new Path(DatapathId.of(1L), DatapathId.of(3L));
         r1.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of((short)1)));
         r1.getPath().add(new NodePortTuple(DatapathId.of(2L), OFPort.of((short)1)));
         r1.getPath().add(new NodePortTuple(DatapathId.of(2L), OFPort.of((short)2)));
diff --git a/src/test/java/net/floodlightcontroller/staticentry/StaticFlowTests.java b/src/test/java/net/floodlightcontroller/staticentry/StaticFlowTests.java
index a2a6eb964d58d84c71b0d1d777927bb6859b6c3e..e2b52156f53676e2986fefc099687274aa590361 100644
--- a/src/test/java/net/floodlightcontroller/staticentry/StaticFlowTests.java
+++ b/src/test/java/net/floodlightcontroller/staticentry/StaticFlowTests.java
@@ -175,7 +175,7 @@ public class StaticFlowTests extends FloodlightTestCase {
 		// dont' bother testing the cookie; just copy it over
 		goodFlowMod = goodFlowMod.createBuilder().setCookie(testFlowMod.getCookie()).build();
 		// .. so we can continue to use .equals()
-		assertTrue(OFMessageUtils.equalsIgnoreXid(goodFlowMod, testFlowMod));
+        assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(goodFlowMod), OFMessageUtils.OFMessageIgnoreXid.of(testFlowMod));
 	}
 
 
diff --git a/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java b/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java
index 47790482095cfd3e4ff691c13f3f4679e62d307e..8d7ee1f83bc35a7010ac7e286f791a7b4baabfdd 100644
--- a/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java
+++ b/src/test/java/net/floodlightcontroller/topology/TopologyInstanceTest.java
@@ -18,10 +18,11 @@ package net.floodlightcontroller.topology;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import static net.floodlightcontroller.routing.IRoutingService.PATH_METRIC.HOPCOUNT;
+import static net.floodlightcontroller.routing.IRoutingService.PATH_METRIC.LATENCY;
 import static org.junit.Assert.*;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.internal.IOFSwitchService;
@@ -29,12 +30,15 @@ import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.test.MockFloodlightProvider;
 import net.floodlightcontroller.core.test.MockSwitchManager;
 import net.floodlightcontroller.core.test.MockThreadPoolService;
-import net.floodlightcontroller.core.types.NodePortTuple;
 import net.floodlightcontroller.debugcounter.IDebugCounterService;
 import net.floodlightcontroller.debugcounter.MockDebugCounterService;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
+import net.floodlightcontroller.routing.IRoutingService;
+import net.floodlightcontroller.routing.Path;
+import net.floodlightcontroller.routing.RoutingManager;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.core.types.NodePortTuple;
 import net.floodlightcontroller.topology.TopologyInstance;
 import net.floodlightcontroller.topology.TopologyManager;
 
@@ -50,6 +54,7 @@ import org.slf4j.LoggerFactory;
 public class TopologyInstanceTest {
     protected static Logger log = LoggerFactory.getLogger(TopologyInstanceTest.class);
     protected TopologyManager topologyManager;
+    protected RoutingManager routingManager;
     protected FloodlightModuleContext fmc;
     protected ILinkDiscoveryService linkDiscovery;
     protected MockFloodlightProvider mockFloodlightProvider;
@@ -69,17 +74,18 @@ public class TopologyInstanceTest {
         fmc.addService(IDebugCounterService.class, new MockDebugCounterService());
         MockThreadPoolService tp = new MockThreadPoolService();
         topologyManager = new TopologyManager();
+        routingManager = new RoutingManager();
+        fmc.addService(IRoutingService.class, routingManager);
         fmc.addService(IThreadPoolService.class, tp);
+        fmc.addService(ITopologyService.class, topologyManager);
         topologyManager.init(fmc);
+        routingManager.init(fmc);
+        routingManager.startUp(fmc);
         tp.init(fmc);
         tp.startUp(fmc);
     }
 
     protected void verifyClusters(int[][] clusters) {
-        verifyClusters(clusters, true);
-    }
-
-    protected void verifyClusters(int[][] clusters, boolean tunnelsEnabled) {
         List<DatapathId> verifiedSwitches = new ArrayList<DatapathId>();
 
         // Make sure the expected cluster arrays are sorted so we can
@@ -88,7 +94,7 @@ public class TopologyInstanceTest {
             Arrays.sort(clusters[i]);
 
         TopologyInstance ti = 
-                topologyManager.getCurrentInstance(tunnelsEnabled);
+                topologyManager.getCurrentInstance();
         Set<DatapathId> switches = ti.getSwitches();
 
         for (DatapathId sw: switches) {
@@ -103,7 +109,7 @@ public class TopologyInstanceTest {
                     }
                 }
                 if (expectedCluster != null) {
-                    Set<DatapathId> cluster = ti.getSwitchesInOpenflowDomain(sw);
+                    Set<DatapathId> cluster = ti.getSwitchesInCluster(sw);
                     assertEquals(expectedCluster.length, cluster.size());
                     for (DatapathId sw2: cluster) {
                         assertTrue(Arrays.binarySearch(expectedCluster, (int)sw2.getLong()) >= 0);
@@ -113,15 +119,9 @@ public class TopologyInstanceTest {
             }
         }
     }
-
-    protected void 
+    
+    /*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) {
@@ -131,15 +131,16 @@ public class TopologyInstanceTest {
                 npt = new NodePortTuple(DatapathId.of(nptList[j][0]), OFPort.of(nptList[j][1]));
                 expected.add(npt);
             }
-            TopologyInstance ti = topologyManager.getCurrentInstance(tunnelsEnabled);
+            TopologyInstance ti = topologyManager.getCurrentInstance();
             Set<NodePortTuple> computed = ti.getBroadcastNodePortsInCluster(npt.getNodeId());
             log.info("computed: {}", computed);
+            log.info("expected: {}", expected);
             if (computed != null)
                 assertTrue(computed.equals(expected));
             else if (computed == null)
                 assertTrue(expected.isEmpty());
         }
-    }
+    }*/
 
     public void createTopologyFromLinks(int [][] linkArray) throws Exception {
         ILinkDiscovery.LinkType type = ILinkDiscovery.LinkType.DIRECT_LINK;
@@ -159,6 +160,30 @@ public class TopologyInstanceTest {
         topologyManager.createNewInstance();
     }
 
+    private void configureTopology(int [][] linkArray, int [] latency) throws Exception {
+        ILinkDiscovery.LinkType type = ILinkDiscovery.LinkType.DIRECT_LINK;
+
+        // Use topologymanager to write this test, it will make it a lot easier.
+        for (int i = 0; i < linkArray.length; i++) {
+            int [] r = linkArray[i];
+            if (r[4] == DIRECT_LINK)
+                type= ILinkDiscovery.LinkType.DIRECT_LINK;
+            else if (r[4] == MULTIHOP_LINK)
+                type= ILinkDiscovery.LinkType.MULTIHOP_LINK;
+            else if (r[4] == TUNNEL_LINK)
+                type = ILinkDiscovery.LinkType.TUNNEL;
+
+            //Check for valid latency
+            int lat = latency[i];
+            if(lat < 0 || lat > 10000)
+                lat = 10000;
+
+
+            topologyManager.addOrUpdateLink(DatapathId.of(r[0]), OFPort.of(r[1]), DatapathId.of(r[2]), OFPort.of(r[3]), U64.of(lat), type);
+        }
+        topologyManager.createNewInstance();
+    }
+
     public TopologyManager getTopologyManager() {
         return topologyManager;
     }
@@ -317,7 +342,7 @@ public class TopologyInstanceTest {
         createTopologyFromLinks(linkArray);
         topologyManager.createNewInstance();
         verifyClusters(expectedClusters);
-        verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
+        //FIXME verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
     }
 
     @Test
@@ -379,7 +404,7 @@ public class TopologyInstanceTest {
             createTopologyFromLinks(linkArray);
             topologyManager.createNewInstance();
             verifyClusters(expectedClusters);
-            verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
+            //FIXME verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
         }
 
         //      +-------+             +-------+
@@ -427,8 +452,8 @@ public class TopologyInstanceTest {
 
             createTopologyFromLinks(linkArray);
             topologyManager.createNewInstance();
-            verifyClusters(expectedClusters, false);
-            verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
+            verifyClusters(expectedClusters);
+            //FIXMEverifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
         }
     }
 
@@ -475,4 +500,437 @@ public class TopologyInstanceTest {
                 verifyClusters(expectedClusters);
         }
     }
-}
+
+    private void verifyRoute(List<Path> r, Integer size)
+    {
+        ArrayList<Path> paths = new ArrayList<Path>();
+
+        DatapathId one = DatapathId.of(1);
+        DatapathId two = DatapathId.of(2);
+        DatapathId three = DatapathId.of(3);
+        DatapathId four = DatapathId.of(4);
+        DatapathId five = DatapathId.of(5);
+        DatapathId six = DatapathId.of(6);
+
+        NodePortTuple one1 = new NodePortTuple(one, OFPort.of(1));
+        NodePortTuple one2 = new NodePortTuple(one, OFPort.of(2));
+
+        NodePortTuple two1 = new NodePortTuple(two, OFPort.of(1));
+        NodePortTuple two2 = new NodePortTuple(two, OFPort.of(2));
+        NodePortTuple two3 = new NodePortTuple(two, OFPort.of(3));
+
+        NodePortTuple three1 = new NodePortTuple(three, OFPort.of(1));
+        NodePortTuple three2 = new NodePortTuple(three, OFPort.of(2));
+        NodePortTuple three3 = new NodePortTuple(three, OFPort.of(3));
+        NodePortTuple three4 = new NodePortTuple(three, OFPort.of(4));
+
+        NodePortTuple four1 = new NodePortTuple(four, OFPort.of(1));
+        NodePortTuple four2 = new NodePortTuple(four, OFPort.of(2));
+        NodePortTuple four3 = new NodePortTuple(four, OFPort.of(3));
+        NodePortTuple four4 = new NodePortTuple(four, OFPort.of(4));
+
+        NodePortTuple five1 = new NodePortTuple(five, OFPort.of(1));
+        NodePortTuple five2 = new NodePortTuple(five, OFPort.of(2));
+        NodePortTuple five3 = new NodePortTuple(five, OFPort.of(3));
+
+        NodePortTuple six1 = new NodePortTuple(six, OFPort.of(1));
+        NodePortTuple six2 = new NodePortTuple(six, OFPort.of(2));
+
+        List<NodePortTuple> route0 = new ArrayList<NodePortTuple>();
+        route0.add(one1);
+        route0.add(two1);
+        route0.add(two2);
+        route0.add(three1);
+        route0.add(three4);
+        route0.add(six2);
+        Path root0 = new Path(one, six);
+        root0.setPath(route0);
+        paths.add(root0);
+        //log.info("root0: {}", root0);
+        //log.info("r.get(0) {}:", r.get(0));
+
+
+        ArrayList<NodePortTuple> route1 = new ArrayList<NodePortTuple>();
+        route1.add(one2);
+        route1.add(four1);
+        route1.add(four3);
+        route1.add(three2);
+        route1.add(three4);
+        route1.add(six2);
+        Path root1 = new Path(one, six);
+        root1.setPath(route1);
+        //log.info("root1: {}", root1);
+        //log.info("r.get(1) {}:", r.get(1));
+        paths.add(root1);
+
+        ArrayList<NodePortTuple> route2 = new ArrayList<NodePortTuple>();
+        route2.add(one2);
+        route2.add(four1);
+        route2.add(four4);
+        route2.add(five1);
+        route2.add(five3);
+        route2.add(six1);
+        Path root2 = new Path(one, six);
+        root2.setPath(route2);
+        //log.info("root2: {}", root2);
+        //log.info("r.get(2) {}:", r.get(2));
+        paths.add(root2);
+
+        ArrayList<NodePortTuple> route3 = new ArrayList<NodePortTuple>();
+        route3.add(one1);
+        route3.add(two1);
+        route3.add(two2);
+        route3.add(three1);
+        route3.add(three3);
+        route3.add(five2);
+        route3.add(five3);
+        route3.add(six1);
+        Path root3 = new Path(one, six);
+        root3.setPath(route3);
+        //log.info("root3: {}", root3);
+        //log.info("r.get(3) {}:", r.get(3));
+        paths.add(root3);
+
+        ArrayList<NodePortTuple> route4 = new ArrayList<NodePortTuple>();
+        route4.add(one2);
+        route4.add(four1);
+        route4.add(four3);
+        route4.add(three2);
+        route4.add(three3);
+        route4.add(five2);
+        route4.add(five3);
+        route4.add(six1);
+        Path root4 = new Path(one, six);
+        root4.setPath(route4);
+        //log.info("root4: {}", root4);
+        //log.info("r.get(4) {}:", r.get(4));
+        paths.add(root4);
+
+        ArrayList<NodePortTuple> route5 = new ArrayList<NodePortTuple>();
+        route5.add(one2);
+        route5.add(four1);
+        route5.add(four2);
+        route5.add(two3);
+        route5.add(two2);
+        route5.add(three1);
+        route5.add(three4);
+        route5.add(six2);
+        Path root5 = new Path(one, six);
+        root5.setPath(route5);
+        //log.info("root5: {}", root5);
+        //log.info("r.get(5) {}:", r.get(5));
+        paths.add(root5);
+
+        ArrayList<NodePortTuple> route6 = new ArrayList<NodePortTuple>();
+        route6.add(one2);
+        route6.add(four1);
+        route6.add(four2);
+        route6.add(two3);
+        route6.add(two2);
+        route6.add(three1);
+        route6.add(three3);
+        route6.add(five2);
+        route6.add(five3);
+        route6.add(six1);
+        Path root6 = new Path(one, six);
+        root6.setPath(route6);
+        //log.info("root6: {}", root6);
+        //log.info("r.get(6) {}:", r.get(6));
+        paths.add(root6);
+
+        //The heart of the validate function.
+        //Iterates through list and ensures each entry is present.
+        int count = 0;
+        int path_length = 7;
+        for(int i=0; i<size; i++) {
+            for(int j=0; j<path_length; j++) {
+                //This may be redundant, but bear with me...
+                if(paths.get(j).equals(r.get(i))){
+                    assertTrue((paths.get(j)).equals(r.get(i)));
+                    count++;
+                    break;
+                }
+            }
+        }
+        assertTrue(count == size);
+    }
+
+    @Test
+    public void testgetPathsFast() throws Exception{
+        Integer k = 2;
+        DatapathId one = DatapathId.of(1);
+        DatapathId three = DatapathId.of(3);
+        DatapathId six = DatapathId.of(6);
+
+        /*
+         * FIRST TOPOLOGY
+         * Both link arrays and corresponding latency
+         * array used in this unit test. Shown below is
+         * a graphical representation of the topology.
+         * This topology is entirely weakly-connected
+         * and will form single-switch clusters despite
+         * each link being an inter-cluster/direct link.
+         * It will be detected as a single archipelago
+         * though, since some nodes can reach others
+         * over the weak links.
+
+                                    -------
+                                   |       |
+                          -------->|1 '2' 2|--------
+                          |        |       |        |
+                          |         -------         |
+                          |                         V
+                       -------                   -------
+                      |   1   |                 |   2   |
+                      |  '1' 2|---------------->|1 '3'  |
+                      |       |                 |       |
+                       -------                   -------
+         */
+        int [][] linkArray = {
+                {1, 1, 2, 1, DIRECT_LINK},
+                {1, 2, 3, 1, DIRECT_LINK},
+                {2, 2, 3, 2, DIRECT_LINK},
+        };
+        int [] lat = {1,50,1};
+
+        /* 
+         * NOTE: Output from the next four log.info should be mirrored!
+         * Get paths based on latency.
+         */
+        topologyManager.setPathMetric(LATENCY);
+        configureTopology(linkArray, lat);
+        List<Path> lat_paths = routingManager.getPathsFast(one, three, k);
+        log.info("Path 1: {}", lat_paths.get(0));
+        log.info("Path 2: {}", lat_paths.get(1));
+
+        //Get paths based on hop count
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(HOPCOUNT);
+        configureTopology(linkArray, lat);
+        topologyManager.createNewInstance();
+        List<Path> hop_paths = routingManager.getPathsFast(one, three, k);
+        log.info("Path 1: {}", hop_paths.get(0));
+        log.info("Path 2: {}", hop_paths.get(1));
+
+        /*
+         * Check if routes equal what the expected output should be.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(LATENCY);
+        int [] lat1 = {1,50,1};
+        configureTopology(linkArray, lat1);
+        topologyManager.createNewInstance();
+        List<Path> r1 = routingManager.getPathsFast(one, three, k);
+        assertTrue((r1.get(0)).equals(lat_paths.get(0)));
+        assertTrue((r1.get(1)).equals(lat_paths.get(1)));
+
+        /*
+         * Check output with bottom latency = -100.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(LATENCY);
+        int [] lat2 = {1,-100,1};
+        configureTopology(linkArray, lat2);
+        topologyManager.createNewInstance();
+        log.info("Latency = (-100) => Links: {}", topologyManager.getAllLinks());
+
+        /*
+         * Check output with bottom latency = 25000.
+         */
+        topologyManager.clearCurrentTopology();
+        int [] lat3 = {1,25000,1};
+        configureTopology(linkArray, lat3);
+        topologyManager.createNewInstance();
+        log.info("Latency = (25000) => Links: {}", topologyManager.getAllLinks());
+
+        /*
+         * SECOND TOPOLOGY - Multiple latency arrays used.
+         * Shown below is the topology
+         
+            -------        -------        -------
+           |       |      |       |----->|1      |
+           |  '1' 1|----->|1 '2' 2|      |  '3' 4|----------|
+           |   2   |      |   3   |   |->|2  3   |          |
+            -------        -------    |   -------           |
+               |              |       |      |              |
+               |              |       |      |              |
+               |              V       |      V              V
+               |           -------    |   -------        -------
+               |          |   2  3|---|  |   2   |      |   2   |
+               |--------->|1 '4'  |      |  '5' 3|----->|1 '6'  |
+                          |      4|----->|1      |      |       |
+                           -------        -------        -------
+         */
+        int [][] linkArray2 = {
+                {1, 1, 2, 1, DIRECT_LINK},
+                {1, 2, 4, 1, DIRECT_LINK},
+                {2, 2, 3, 1, DIRECT_LINK},
+                {3, 3, 5, 2, DIRECT_LINK},
+                {3, 4, 6, 2, DIRECT_LINK},
+                {4, 2, 2, 3, DIRECT_LINK},
+                {4, 3, 3, 2, DIRECT_LINK},
+                {4, 4, 5, 1, DIRECT_LINK},
+                {5, 3, 6, 1, DIRECT_LINK},
+        };
+
+
+        /*
+         * What happens when k > total paths in topology?
+         * All paths should be found. 7 in this case.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(HOPCOUNT);
+        k = 1000;
+        int [] lat4 = {3,2,4,2,1,1,2,3,2};
+        configureTopology(linkArray2, lat4);
+        topologyManager.createNewInstance();
+        List<Path> r = routingManager.getPathsFast(one, six, k);
+        for(int i = 0; i< r.size(); i++) {
+            log.info("k = (1000) => Route: {}", r.get(i));
+        }
+        verifyRoute(r, r.size());
+
+        /*
+         * Checking algorithm to see if all paths are found.
+         * Result should be 7 distinct paths.
+         * Total number of paths in topology is SEVEN.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(HOPCOUNT);
+        k = 7;
+        configureTopology(linkArray2, lat4);
+        topologyManager.createNewInstance();
+        List<Path> r2 = routingManager.getPathsFast(one, six, k);
+        for(int i = 0; i< r2.size(); i++) {
+            log.info("k = (7) => Route: {}", r2.get(i));
+        }
+        verifyRoute(r2, r2.size());
+
+        /*
+         * Test output with negative input value.
+         * No paths should be output as a result.
+         * Based on HOPCOUNT.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(HOPCOUNT);
+        k = -1;
+        configureTopology(linkArray2, lat4);
+        topologyManager.createNewInstance();
+        List<Path> r3 = routingManager.getPathsFast(one, six, k);
+        for(int i = 0; i< r3.size(); i++) {
+            log.info("HOPCOUNT.k = (-1) => Route: {}", r3.get(i));
+        }
+        verifyRoute(r3, r3.size());
+
+        /*
+         * Test output with negative input value.
+         * No paths should be output as a result.
+         * Based on LATENCY.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(LATENCY);
+        k = -1;
+        configureTopology(linkArray2, lat4);
+        topologyManager.createNewInstance();
+        List<Path> r4 = routingManager.getPathsFast(one, six, k);
+        for(int i = 0; i< r4.size(); i++) {
+            log.info("LATENCY.k = (-1) => Route: {}", r4.get(i));
+        }
+        verifyRoute(r4, r4.size());
+
+        /*
+         * Simple route checking with less than max routes requested.
+         * In this case, only 3 were requested.
+         * Based on HOPCOUNT.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(HOPCOUNT);
+        k = 3;
+        configureTopology(linkArray2, lat4);
+        topologyManager.createNewInstance();
+        List<Path> r5 = routingManager.getPathsFast(one, six, k);
+        for(int i = 0; i< r5.size(); i++) {
+            log.info("HOPCOUNT.k = (3) => Route: {}", r5.get(i));
+        }
+        verifyRoute(r5, r5.size());
+
+        /*
+         * Simple route checking with less than max routes requested.
+         * In this case, just 4 out of 7 possibilities requested.
+         * Based on LATENCY.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(LATENCY);
+        k = 4;
+        configureTopology(linkArray2, lat4);
+        topologyManager.createNewInstance();
+        List<Path> r6 = routingManager.getPathsFast(one, six, k);
+        for(int i = 0; i< r6.size(); i++) {
+            log.info("LATENCY.k = (4) => Route: {}", r6.get(i));
+        }
+        verifyRoute(r6, r6.size());
+
+        /*
+         * Test output with all latency links set to zero.
+         * Should return four of the first paths that yen's algorithm calculated.
+         * Order of output here is of no concern.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(LATENCY);
+        k = 4;
+        int [] lat5 = {0,0,0,0,0,0,0,0,0};
+        configureTopology(linkArray2, lat5);
+        topologyManager.createNewInstance();
+        List<Path> r7 = routingManager.getPathsFast(one, six, k);
+        for(int i = 0; i< r7.size(); i++) {
+            log.info("Route latency all ZERO: {}", r7.get(i));
+        }
+        verifyRoute(r7, r7.size());
+
+        /*
+         * Check topology with same switch input: 1 -> 1.
+         * Should have no output.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(HOPCOUNT);
+        k = 4;
+        configureTopology(linkArray2, lat4);
+        topologyManager.createNewInstance();
+        List<Path> r8 = routingManager.getPathsFast(one, one, k);
+        for(int i = 0; i< r8.size(); i++) {
+            log.info("(src == dst) => Route: {}", r8.get(i));
+        }
+        verifyRoute(r8, r8.size());
+
+        /*
+         * Check topology with reverse input: 6 -> 1 instead of 1 -> 6
+         * Should have no output since it is impossible to get from 6 to 1.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(HOPCOUNT);
+        k = 4;
+        configureTopology(linkArray2, lat4);
+        topologyManager.createNewInstance();
+        List<Path> r9 = routingManager.getPathsFast(six, one, k);
+        for(int i = 0; i< r9.size(); i++) {
+            log.info("Reversed Route (6 -> 1): {}", r9.get(i));
+        }
+        verifyRoute(r9, r9.size());
+
+        /*
+         * Check topology with invalid node numbers.
+         * Try to use src == 7
+         * Output should indicate no valid route.
+         */
+        topologyManager.clearCurrentTopology();
+        topologyManager.setPathMetric(HOPCOUNT);
+        k = 4;
+        configureTopology(linkArray2, lat4);
+        topologyManager.createNewInstance();
+        List<Path> r10 = routingManager.getPathsFast(one, DatapathId.of(7), k);
+        for(int i = 0; i< r10.size(); i++) {
+            log.info("(src == 7) => Route: {}", r10.get(i));
+        }
+        verifyRoute(r10, r10.size());
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java b/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java
index 5310f0af93fac8a3bc0ee29500228251c3aeefc7..9ea244acd4269958cfb4fb35f5e24b911b36a9ba 100644
--- a/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java
+++ b/src/test/java/net/floodlightcontroller/topology/TopologyManagerTest.java
@@ -58,74 +58,74 @@ public class TopologyManagerTest extends FloodlightTestCase {
     @Test
     public void testBasic1() throws Exception {
         tm.addOrUpdateLink(DatapathId.of(1), OFPort.of(1), DatapathId.of(2), OFPort.of(1), U64.ZERO, ILinkDiscovery.LinkType.DIRECT_LINK);
-        assertTrue(tm.getSwitchPorts().size() == 2);  // for two nodes.
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(1)).size()==1);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(2)).size()==1);
-        assertTrue(tm.getSwitchPortLinks().size()==2);
-        assertTrue(tm.getPortBroadcastDomainLinks().size()==0);
+        assertTrue(tm.getPortsPerSwitch().size() == 2);  // for two nodes.
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(1)).size()==1);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(2)).size()==1);
+        assertTrue(tm.getPortsOnLinks().size()==2);
+        assertEquals(0, tm.getExternalInterClusterLinks().size());
         assertTrue(tm.getTunnelPorts().size()==0);
 
         tm.addOrUpdateLink(DatapathId.of(1), OFPort.of(2), DatapathId.of(2), OFPort.of(2), U64.ZERO, ILinkDiscovery.LinkType.MULTIHOP_LINK);
-        assertTrue(tm.getSwitchPorts().size() == 2);  // for two nodes.
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(1)).size()==2);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(2)).size()==2);
-        assertTrue(tm.getSwitchPortLinks().size()==4);
-        assertTrue(tm.getPortBroadcastDomainLinks().size()==2);
+        assertTrue(tm.getPortsPerSwitch().size() == 2);  // for two nodes.
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(1)).size()==2);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(2)).size()==2);
+        assertTrue(tm.getPortsOnLinks().size()==4);
+        assertEquals(1, tm.getExternalInterClusterLinks().size());
         assertTrue(tm.getTunnelPorts().size()==0);
 
         tm.removeLink(DatapathId.of(1), OFPort.of(2), DatapathId.of(2), OFPort.of(2));
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(1)).size()==1);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(2)).size()==1);
-        assertTrue(tm.getSwitchPorts().size() == 2);
-        assertTrue(tm.getSwitchPortLinks().size()==2);
-        assertTrue(tm.getPortBroadcastDomainLinks().size()==0);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(1)).size()==1);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(2)).size()==1);
+        assertTrue(tm.getPortsPerSwitch().size() == 2);
+        assertTrue(tm.getPortsOnLinks().size()==2);
+        assertEquals(0, tm.getExternalInterClusterLinks().size());
 
         tm.removeLink(DatapathId.of(1), OFPort.of(1), DatapathId.of(2), OFPort.of(1));
-        assertTrue(tm.getSwitchPorts().size() == 0);
-        assertTrue(tm.getSwitchPortLinks().size()==0);
-        assertTrue(tm.getPortBroadcastDomainLinks().size()==0);
+        assertTrue(tm.getPortsPerSwitch().size() == 0);
+        assertTrue(tm.getPortsOnLinks().size()==0);
+        assertEquals(0, tm.getExternalInterClusterLinks().size());
     }
 
     @Test
     public void testBasic2() throws Exception {
         tm.addOrUpdateLink(DatapathId.of(1), OFPort.of(1), DatapathId.of(2), OFPort.of(1), U64.ZERO, ILinkDiscovery.LinkType.DIRECT_LINK);
         tm.addOrUpdateLink(DatapathId.of(2), OFPort.of(2), DatapathId.of(3), OFPort.of(1), U64.ZERO, ILinkDiscovery.LinkType.MULTIHOP_LINK);
-        assertTrue(tm.getSwitchPorts().size() == 3);  // for two nodes.
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(1)).size()==1);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(2)).size()==2);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(3)).size()==1);
-        assertTrue(tm.getSwitchPortLinks().size()==4);
-        assertTrue(tm.getPortBroadcastDomainLinks().size()==2);
+        assertTrue(tm.getPortsPerSwitch().size() == 3);  // for two nodes.
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(1)).size()==1);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(2)).size()==2);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(3)).size()==1);
+        assertTrue(tm.getPortsOnLinks().size()==4);
+        assertEquals(1, tm.getExternalInterClusterLinks().size());
 
         tm.removeLink(DatapathId.of(1), OFPort.of(1), DatapathId.of(2), OFPort.of(1));
-        assertTrue(tm.getSwitchPorts().size() == 2);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(1)) == null);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(2)).size()==1);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(3)).size()==1);
-        assertTrue(tm.getSwitchPortLinks().size()==2);
-        assertTrue(tm.getPortBroadcastDomainLinks().size()==2);
+        assertTrue(tm.getPortsPerSwitch().size() == 2);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(1)) == null);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(2)).size()==1);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(3)).size()==1);
+        assertTrue(tm.getPortsOnLinks().size()==2);
+        assertEquals(1, tm.getExternalInterClusterLinks().size());
 
         // nonexistent link // no null pointer exceptions.
         tm.removeLink(DatapathId.of(3), OFPort.of(1), DatapathId.of(2), OFPort.of(2));
-        assertTrue(tm.getSwitchPorts().size() == 2);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(1)) == null);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(2)).size()==1);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(3)).size()==1);
-        assertTrue(tm.getSwitchPortLinks().size()==2);
-        assertTrue(tm.getPortBroadcastDomainLinks().size()==2);
+        assertTrue(tm.getPortsPerSwitch().size() == 2);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(1)) == null);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(2)).size()==1);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(3)).size()==1);
+        assertTrue(tm.getPortsOnLinks().size()==2);
+        assertEquals(1, tm.getExternalInterClusterLinks().size());
 
         tm.removeLink(DatapathId.of(3), OFPort.of(2), DatapathId.of(1), OFPort.of(2));
-        assertTrue(tm.getSwitchPorts().size() == 2);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(1))==null);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(2)).size()==1);
-        assertTrue(tm.getSwitchPorts().get(DatapathId.of(3)).size()==1);
-        assertTrue(tm.getSwitchPortLinks().size()==2);
-        assertTrue(tm.getPortBroadcastDomainLinks().size()==2);
+        assertTrue(tm.getPortsPerSwitch().size() == 2);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(1))==null);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(2)).size()==1);
+        assertTrue(tm.getPortsPerSwitch().get(DatapathId.of(3)).size()==1);
+        assertTrue(tm.getPortsOnLinks().size()==2);
+        assertEquals(1, tm.getExternalInterClusterLinks().size());
 
         tm.removeLink(DatapathId.of(2), OFPort.of(2), DatapathId.of(3), OFPort.of(1));
-        assertTrue(tm.getSwitchPorts().size() == 0);  // for two nodes.
-        assertTrue(tm.getSwitchPortLinks().size()==0);
-        assertTrue(tm.getPortBroadcastDomainLinks().size()==0);
+        assertTrue(tm.getPortsPerSwitch().size() == 0);  // for two nodes.
+        assertTrue(tm.getPortsOnLinks().size()==0);
+        assertEquals(0, tm.getExternalInterClusterLinks().size());
         assertTrue(tm.getTunnelPorts().size()==0);
     }