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