diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index a33f1410419c5c9b9fe7cc6a9c977a8f0768c4a9..e5d7ad28cd0fbb71980064d0a950f3793e788af5 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -275,6 +275,15 @@ public class Controller implements IFloodlightProviderService,
             this.newRole = newRole;
         }
         public void dispatch() {
+            // Make sure that old and new roles are different.
+            if (oldRole == newRole) {
+                if (log.isTraceEnabled()) {
+                    log.trace("HA role update ignored as the old and " +
+                              "new roles are the same. newRole = {}" +
+                              "oldRole = {}", newRole, oldRole);
+                }
+                return;
+            }
             if (log.isTraceEnabled()) {
                 log.trace("Dispatching HA Role update newRole = {}, oldRole = {}",
                           newRole, oldRole);
@@ -354,6 +363,10 @@ public class Controller implements IFloodlightProviderService,
     @Override
     public void setRole(Role role) {
         if (role == null) throw new NullPointerException("Role can not be null.");
+        if (role == Role.MASTER && this.role == Role.SLAVE) {
+            // Reset db state to Inactive for all switches. 
+            updateAllInactiveSwitchInfo();
+        }
         
         // Need to synchronize to ensure a reliable ordering on role request
         // messages send and to ensure the list of connected switches is stable
@@ -1483,6 +1496,9 @@ public class Controller implements IFloodlightProviderService,
     // **************
 
     protected void updateAllInactiveSwitchInfo() {
+        if (role == Role.SLAVE) {
+            return;
+        }
         String controllerId = getControllerId();
         String[] switchColumns = { SWITCH_DATAPATH_ID,
                                    SWITCH_CONTROLLER_ID,
@@ -1540,6 +1556,9 @@ public class Controller implements IFloodlightProviderService,
     }
     
     protected void updateActiveSwitchInfo(IOFSwitch sw) {
+        if (role == Role.SLAVE) {
+            return;
+        }
         // Obtain the row info for the switch
         Map<String, Object> switchInfo = new HashMap<String, Object>();
         String datapathIdString = sw.getStringId();
@@ -1584,6 +1603,9 @@ public class Controller implements IFloodlightProviderService,
     }
     
     protected void updateInactiveSwitchInfo(IOFSwitch sw) {
+        if (role == Role.SLAVE) {
+            return;
+        }
         log.debug("Update DB with inactiveSW {}", sw);
         // Update the controller info in the storage source to be inactive
         Map<String, Object> switchInfo = new HashMap<String, Object>();
@@ -1595,6 +1617,9 @@ public class Controller implements IFloodlightProviderService,
     }
 
     protected void updatePortInfo(IOFSwitch sw, OFPhysicalPort port) {
+        if (role == Role.SLAVE) {
+            return;
+        }
         String datapathIdString = sw.getStringId();
         Map<String, Object> portInfo = new HashMap<String, Object>();
         int portNumber = U16.f(port.getPortNumber());
@@ -1668,6 +1693,9 @@ public class Controller implements IFloodlightProviderService,
     }
     
     protected void removePortInfo(IOFSwitch sw, short portNumber) {
+        if (role == Role.SLAVE) {
+            return;
+        }
         String datapathIdString = sw.getStringId();
         String id = datapathIdString + "|" + portNumber;
         storageSource.deleteRowAsync(PORT_TABLE_NAME, id);
diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/OFMatchJSONSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/OFMatchJSONSerializer.java
deleted file mode 100644
index 98048b1a59eb21ff5ad8627a82c73ecf8beb8564..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/core/web/serializers/OFMatchJSONSerializer.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
-*    Copyright 2011, Big Switch Networks, Inc. 
-*    Originally created by David Erickson, Stanford University
-* 
-*    Licensed under the Apache License, Version 2.0 (the "License"); you may
-*    not use this file except in compliance with the License. You may obtain
-*    a copy of the License at
-*
-*         http://www.apache.org/licenses/LICENSE-2.0
-*
-*    Unless required by applicable law or agreed to in writing, software
-*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-*    License for the specific language governing permissions and limitations
-*    under the License.
-**/
-
-package net.floodlightcontroller.core.web.serializers;
-
-import java.io.IOException;
-
-import org.codehaus.jackson.JsonGenerator;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.map.JsonSerializer;
-import org.codehaus.jackson.map.SerializerProvider;
-import org.openflow.protocol.OFMatch;
-import org.openflow.util.HexString;
-
-public class OFMatchJSONSerializer extends JsonSerializer<OFMatch> {
-
-    /**
-     * Converts an IP in a 32 bit integer to a dotted-decimal string
-     * @param i The IP address in a 32 bit integer
-     * @return An IP address string in dotted-decimal
-     */
-    private String intToIp(int i) {
-        return ((i >> 24 ) & 0xFF) + "." +
-               ((i >> 16 ) & 0xFF) + "." +
-               ((i >>  8 ) & 0xFF) + "." +
-               ( i        & 0xFF);
-    }
-
-    /**
-     * Performs the serialization of a OFMatch object
-     */
-    @Override
-    public void serialize(OFMatch match, JsonGenerator jGen, 
-                                SerializerProvider serializer) 
-                                throws IOException, JsonProcessingException {
-        jGen.writeStartObject();
-        jGen.writeStringField("dataLayerDestination", 
-                    HexString.toHexString(match.getDataLayerDestination()));
-        jGen.writeStringField("dataLayerSource", 
-                    HexString.toHexString(match.getDataLayerSource()));
-        String dataType = Integer.toHexString(match.getDataLayerType());
-        while (dataType.length() < 4) {
-            dataType = "0".concat(dataType);
-        }
-        jGen.writeStringField("dataLayerType", "0x" + dataType);
-        jGen.writeNumberField("dataLayerVirtualLan", 
-                    match.getDataLayerVirtualLan());
-        jGen.writeNumberField("dataLayerVirtualLanPriorityCodePoint", 
-                    match.getDataLayerVirtualLanPriorityCodePoint());
-        jGen.writeNumberField("inputPort", match.getInputPort());
-        jGen.writeStringField("networkDestination", 
-                    intToIp(match.getNetworkDestination()));
-        jGen.writeNumberField("networkDestinationMaskLen", 
-                    match.getNetworkDestinationMaskLen());
-        jGen.writeNumberField("networkProtocol", match.getNetworkProtocol());
-        jGen.writeStringField("networkSource", 
-                    intToIp(match.getNetworkSource()));
-        jGen.writeNumberField("networkSourceMaskLen", 
-                    match.getNetworkSourceMaskLen());
-        jGen.writeNumberField("networkTypeOfService", 
-                    match.getNetworkTypeOfService());
-        jGen.writeNumberField("transportDestination", 
-                    match.getTransportDestination());
-        jGen.writeNumberField("transportSource", 
-                    match.getTransportSource());
-        jGen.writeNumberField("wildcards", match.getWildcards());
-        jGen.writeEndObject();
-    }
-
-    /**
-     * Tells SimpleModule that we are the serializer for OFMatch
-     */
-    @Override
-    public Class<OFMatch> handledType() {
-        return OFMatch.class;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java b/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java
index dd54638212c9fdc8dcb746375a7cb936ecf1f25c..95969f8c859299fabd53d5a0d917db3ff90230fe 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/IDevice.java
@@ -73,6 +73,14 @@ public interface IDevice {
      * @return an array containing all unique attachment points for the device
      */
     public SwitchPort[] getAttachmentPoints(boolean includeError);
+
+    /**
+     * Returns all unique VLAN IDs for the device that were observed on 
+     * the given switch port
+     * @param swp the switch port to query
+     * @return an array containing the unique VLAN IDs
+     */
+    public Short[] getSwitchPortVlanIds(SwitchPort swp);
     
     /**
      * Get the most recent timestamp for this device
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
index dc7c0da7bf897cccbfc6e09a21762a3fddc25358..333777e731ac505dae9f31b3d886dce9de017cca 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
@@ -33,6 +33,7 @@ import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.IEntityClass;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import static net.floodlightcontroller.devicemanager.SwitchPort.ErrorStatus.*;
+import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.topology.ITopologyService;
 
 /**
@@ -342,6 +343,21 @@ public class Device implements IDevice {
 
         return vals.toArray(new SwitchPort[vals.size()]);
     }
+    
+    @Override
+    public Short[] getSwitchPortVlanIds(SwitchPort swp) {
+        TreeSet<Short> vals = new TreeSet<Short>();
+        for (Entity e : entities) {
+            if (e.switchDPID == swp.getSwitchDPID() 
+                    && e.switchPort == swp.getPort()) {
+                if (e.getVlan() == null)
+                    vals.add(Ethernet.VLAN_UNTAGGED);
+                else
+                    vals.add(e.getVlan());
+            }
+        }
+        return vals.toArray(new Short[vals.size()]);
+    }
 
     @Override
     public Date getLastSeen() {
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
index 4ac12eba8cfeb1c3a4c1d1cf16ccb70b85f01ca0..8496f0a8e4f9a5e4b670969599e98f04adacb218 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
@@ -213,7 +213,7 @@ public class Entity implements Comparable<Entity> {
 
     @Override
     public String toString() {
-        return "Entity [macAddress=" + HexString.toHexString(macAddress)
+        return "Entity [macAddress=" + HexString.toHexString(macAddress, 6)
                + ", ipv4Address="
                + IPv4.fromIPv4Address(ipv4Address==null ? 0 : ipv4Address.intValue()) + ", vlan=" + vlan + ", switchDPID="
                + switchDPID + ", switchPort=" + switchPort + "]";
diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
index a251bd3e7df26aaf45fe5bc6b40b41d16adff714..fa3fd4c88c58de6823a1997a30cf3b02429507b1 100644
--- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java
@@ -291,11 +291,11 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
 
     @Override
     public void init(FloodlightModuleContext context) throws FloodlightModuleException {
-        this.setFloodlightProvider(context.getServiceImpl(IFloodlightProviderService.class));
-        this.setDeviceManager(context.getServiceImpl(IDeviceService.class));
-        this.setRoutingEngine(context.getServiceImpl(IRoutingService.class));
-        this.setTopology(context.getServiceImpl(ITopologyService.class));
-        this.setCounterStore(context.getServiceImpl(ICounterStoreService.class));
+        this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+        this.deviceManager = context.getServiceImpl(IDeviceService.class);
+        this.routingEngine = context.getServiceImpl(IRoutingService.class);
+        this.topology = context.getServiceImpl(ITopologyService.class);
+        this.counterStore = context.getServiceImpl(ICounterStoreService.class);
     }
 
     @Override
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java
index 08f7c50cd221eb577ac1177871f53871cb17a356..af731cea76b10533264a7eaa2a9661616f897e95 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscovery.java
@@ -103,6 +103,29 @@ public interface ILinkDiscovery {
     };
 
     public enum LinkType {
-        INVALID_LINK, DIRECT_LINK, MULTIHOP_LINK, TUNNEL
+        INVALID_LINK {
+        	@Override
+        	public String toString() {
+        		return "invalid";
+        	}
+        }, 
+        DIRECT_LINK{
+        	@Override
+        	public String toString() {
+        		return "internal";
+        	}
+        }, 
+        MULTIHOP_LINK {
+        	@Override
+        	public String toString() {
+        		return "external";
+        	}
+        }, 
+        TUNNEL {
+        	@Override
+        	public String toString() {
+        		return "tunnel";
+        	}
+        }
     };
 }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java b/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java
index b12be9379d67a4bd06ec523fd43a42db62ff90ca..9c0dd1a0a405f0b010ee0b9b80d3301d28c7ca4f 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/LinkInfo.java
@@ -116,7 +116,7 @@ public class LinkInfo {
         result = prime * result + ((firstSeenTime == null) ? 0 : firstSeenTime.hashCode());
         result = prime * result + ((lastLldpReceivedTime == null) ? 0 : lastLldpReceivedTime.hashCode());
         result = prime * result + ((lastBddpReceivedTime == null) ? 0 : lastBddpReceivedTime.hashCode());
-        result = prime * result + ((srcPortState == null) ? 0 : lastLldpReceivedTime.hashCode());
+        result = prime * result + ((srcPortState == null) ? 0 : srcPortState.hashCode());
         result = prime * result + ((dstPortState == null) ? 0 : dstPortState.hashCode());
         return result;
     }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index 9a3441c0e36e8217c1360528e2ade81e08ca5ba3..8c3cde18679295eb048fe513cc4c291d52ffc4ba 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -271,6 +271,30 @@ IFloodlightModule, IInfoProvider, IHAListener {
         return ILinkDiscovery.LinkType.INVALID_LINK;
     }
 
+    private void doUpdatesThread() throws InterruptedException {
+        do {
+            LDUpdate update = updates.take();
+
+            if (linkDiscoveryAware != null) {
+                if (log.isTraceEnabled()) {
+                    log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
+                              new Object[]{update.getOperation(),
+                                           HexString.toHexString(update.getSrc()), update.getSrcPort(),
+                                           HexString.toHexString(update.getDst()), update.getDstPort(),
+                                           linkDiscoveryAware});
+                }
+                try {
+                for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained
+                    lda.linkDiscoveryUpdate(update);
+                    }
+                }
+                catch (Exception e) {
+                    log.error("Error in link discovery updates loop", e);
+                }
+            }
+        } while (updates.peek() != null);
+    }
+
     private boolean isLLDPSuppressed(long sw, short portNumber) {
         return this.suppressLLDPs.contains(new NodePortTuple(sw, portNumber));
     }
@@ -602,17 +626,23 @@ IFloodlightModule, IInfoProvider, IHAListener {
         }
 
         if (!remoteSwitch.portEnabled(remotePort)) {
-            log.debug("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort);
+            if (log.isTraceEnabled()) {
+                log.trace("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort);
+            }
             return Command.STOP;
         }
         if (suppressLLDPs.contains(new NodePortTuple(remoteSwitch.getId(), 
                                                      remotePort))) {
-            log.debug("Ignoring link with suppressed src port: switch {} port {}",
+            if (log.isTraceEnabled()) {
+                log.trace("Ignoring link with suppressed src port: switch {} port {}",
                       remoteSwitch, remotePort);
+            }
             return Command.STOP;
         }
         if (!iofSwitch.portEnabled(pi.getInPort())) {
-            log.debug("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort());
+            if (log.isTraceEnabled()) {
+                log.trace("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort());
+            }
             return Command.STOP;
         }
 
@@ -805,8 +835,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
 
                 if (linkChanged) {
                     updateOperation = UpdateOperation.ADD_OR_UPDATE;
-                    if (log.isDebugEnabled()) {
-                        log.debug("Updated link {}", lt);
+                    if (log.isTraceEnabled()) {
+                        log.trace("Updated link {}", lt);
                     }
                     // Add to event history
                     evHistTopoLink(lt.getSrc(),
@@ -890,8 +920,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
                 removeLinkFromStorage(lt);
 
 
-                if (log.isDebugEnabled()) {
-                    log.debug("Deleted link {}", lt);
+                if (log.isTraceEnabled()) {
+                    log.trace("Deleted link {}", lt);
                 }
             }
         } finally {
@@ -911,8 +941,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
         IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
         if (iofSwitch == null) return Command.CONTINUE;
 
-        if (log.isDebugEnabled()) {
-            log.debug("handlePortStatus: Switch {} port #{} reason {}; " +
+        if (log.isTraceEnabled()) {
+            log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
                     "config is {} state is {}",
                     new Object[] {iofSwitch.getStringId(),
                                   ps.getDesc().getPortNumber(),
@@ -979,8 +1009,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
             }
 
             if (!linkDeleted && !linkInfoChanged){
-                if (log.isDebugEnabled()) {
-                    log.debug("handlePortStatus: Switch {} port #{} reason {};"+
+                if (log.isTraceEnabled()) {
+                    log.trace("handlePortStatus: Switch {} port #{} reason {};"+
                             " no links to update/remove",
                             new Object[] {HexString.toHexString(sw),
                                           ps.getDesc().getPortNumber(),
@@ -1037,8 +1067,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
         lock.writeLock().lock();
         try {
             if (switchLinks.containsKey(sw)) {
-                if (log.isDebugEnabled()) {
-                    log.debug("Handle switchRemoved. Switch {}; removing links {}",
+                if (log.isTraceEnabled()) {
+                    log.trace("Handle switchRemoved. Switch {}; removing links {}",
                               HexString.toHexString(sw), switchLinks.get(sw));
                 }
                 // add all tuples with an endpoint on this switch to erase list
@@ -1058,8 +1088,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
     protected void deleteLinksOnPort(NodePortTuple npt, String reason) {
         List<Link> eraseList = new ArrayList<Link>();
         if (this.portLinks.containsKey(npt)) {
-            if (log.isDebugEnabled()) {
-                log.debug("handlePortStatus: Switch {} port #{} " +
+            if (log.isTraceEnabled()) {
+                log.trace("handlePortStatus: Switch {} port #{} " +
                         "removing links {}",
                         new Object[] {HexString.toHexString(npt.getNodeId()),
                                       npt.getPortId(),
@@ -1438,8 +1468,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
                     updated_switches.add(sw);
                 }
             } else {
-                if (log.isDebugEnabled()) {
-                    log.debug("Update for switch which has no entry in switch " +
+                if (log.isTraceEnabled()) {
+                    log.trace("Update for switch which has no entry in switch " +
                             "list (dpid={}), a delete action.", (String)key);
                 }
             }
@@ -1449,15 +1479,15 @@ IFloodlightModule, IInfoProvider, IHAListener {
             // Set SWITCH_IS_CORE_SWITCH to it's inverse value
             if (sw.hasAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH)) {
                 sw.removeAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH);
-                if (log.isDebugEnabled()) {
-                    log.debug("SWITCH_IS_CORE_SWITCH set to False for {}", sw);
+                if (log.isTraceEnabled()) {
+                    log.trace("SWITCH_IS_CORE_SWITCH set to False for {}", sw);
                 }
                 updates.add(new LDUpdate(sw.getId(), SwitchType.BASIC_SWITCH));
             }
             else {
                 sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, new Boolean(true));
-                if (log.isDebugEnabled()) {
-                    log.debug("SWITCH_IS_CORE_SWITCH set to True for {}", sw);
+                if (log.isTraceEnabled()) {
+                    log.trace("SWITCH_IS_CORE_SWITCH set to True for {}", sw);
                 }
                 updates.add(new LDUpdate(sw.getId(), SwitchType.CORE_SWITCH));
             }
@@ -1568,6 +1598,19 @@ IFloodlightModule, IInfoProvider, IHAListener {
             }
         });
 
+        updatesThread = new Thread(new Runnable () {
+            @Override
+            public void run() {
+                while (true) {
+                    try {
+                        doUpdatesThread();
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                }
+            }}, "Topology Updates");
+        updatesThread.start();
+
         // Register for the OpenFlow messages we want to receive
         floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
         floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
@@ -1680,15 +1723,19 @@ IFloodlightModule, IInfoProvider, IHAListener {
             case MASTER:
                 if (oldRole == Role.SLAVE) {
                     clearAllLinks();
-                    log.debug("Sending LLDPs " +
-                            "to HA change from SLAVE->MASTER");
+                    if (log.isTraceEnabled()) {
+                        log.trace("Sending LLDPs " +
+                                "to HA change from SLAVE->MASTER");
+                    }
                     clearAllLinks();
                     discoverLinks();
                 }
                 break;
             case SLAVE:
-                log.debug("Clearing links due to " +
-                        "HA change to SLAVE");
+                if (log.isTraceEnabled()) {
+                    log.trace("Clearing links due to " +
+                            "HA change to SLAVE");
+                }
                 switchLinks.clear();
                 links.clear();
                 portLinks.clear();
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
new file mode 100644
index 0000000000000000000000000000000000000000..514cfe4f62acd329e772879c38296f9c5f7b1ff4
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
@@ -0,0 +1,56 @@
+package net.floodlightcontroller.linkdiscovery.web;
+
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.openflow.util.HexString;
+
+import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
+import net.floodlightcontroller.routing.Link;
+
+/**
+ * This class is both the datastructure and the serializer
+ * for a link with the corresponding type of link.
+ * @author alexreimers
+ */
+@JsonSerialize(using=LinkWithType.class)
+public class LinkWithType extends JsonSerializer<LinkWithType> {
+    public long srcSwDpid;
+    public short srcPort;
+    public long dstSwDpid;
+    public short dstPort;
+    public LinkType type;
+
+    // Do NOT delete this, it's required for the serializer
+    public LinkWithType() {}
+    
+    public LinkWithType(Link link, LinkType type) {
+        this.srcSwDpid = link.getSrc();
+        this.srcPort = link.getSrcPort();
+        this.dstSwDpid = link.getDst();
+        this.dstPort = link.getDstPort();
+        this.type = type;
+    }
+
+	@Override
+	public void serialize(LinkWithType lwt, JsonGenerator jgen, SerializerProvider arg2) 
+			throws IOException, JsonProcessingException {
+		// You ****MUST*** use lwt for the fields as it's actually a different object.
+		jgen.writeStartObject();
+		jgen.writeStringField("src-switch", HexString.toHexString(lwt.srcSwDpid));
+		jgen.writeNumberField("src-port", lwt.srcPort);
+		jgen.writeStringField("dst-switch", HexString.toHexString(lwt.dstSwDpid));
+		jgen.writeNumberField("dst-port", lwt.dstPort);
+		jgen.writeStringField("type", lwt.type.toString());
+		jgen.writeEndObject();
+	}
+	
+	@Override
+	public Class<LinkWithType> handledType() {
+		return LinkWithType.class;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
index eda84c591bc3645c42e0643861b044d0097df7a9..8fe1ff046f192cd0bcded0792a0bbf3a7030a737 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
@@ -5,7 +5,6 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
-import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.floodlightcontroller.linkdiscovery.LinkInfo;
 import net.floodlightcontroller.routing.Link;
@@ -15,26 +14,8 @@ import org.restlet.resource.ServerResource;
 
 public class LinksResource extends ServerResource {
 
-    public class LinkWithType {
-        long src;
-        short srcPort;
-        long dst;
-        short dstPort;
-        String type;
-
-        public LinkWithType(Link link, String type) {
-            this.src = link.getSrc();
-            this.srcPort = link.getSrcPort();
-            this.dst = link.getDst();
-            this.dstPort = link.getDstPort();
-            this.type = type;
-        }
-    };
-
     @Get("json")
     public Set<LinkWithType> retrieve() {
-        String str;
-
         ILinkDiscoveryService ld = (ILinkDiscoveryService)getContext().getAttributes().
                 get(ILinkDiscoveryService.class.getCanonicalName());
         Map<Link, LinkInfo> links = new HashMap<Link, LinkInfo>();
@@ -44,17 +25,7 @@ public class LinksResource extends ServerResource {
             links.putAll(ld.getLinks());
             for (Link link: links.keySet()) {
                 LinkInfo info = links.get(link);
-                LinkType type = ld.getLinkType(info);
-
-                if (type == LinkType.DIRECT_LINK) 
-                    str = "internal";
-                else if (type == LinkType.MULTIHOP_LINK)
-                    str = "external";
-                else if (type == LinkType.TUNNEL)
-                    str = "tunnel";
-                else str = "invalid";
-
-                LinkWithType lwt = new LinkWithType(link, str);
+                LinkWithType lwt = new LinkWithType(link, ld.getLinkType(info));
                 returnLinkSet.add(lwt);
             }
         }
diff --git a/src/main/java/net/floodlightcontroller/packet/BasePacket.java b/src/main/java/net/floodlightcontroller/packet/BasePacket.java
index d8729ef0dba6856ea358e5b141c42ce0ecc47bdf..6df676d6bf5eb3e74eb0b14e9d3ea6189636fd6b 100644
--- a/src/main/java/net/floodlightcontroller/packet/BasePacket.java
+++ b/src/main/java/net/floodlightcontroller/packet/BasePacket.java
@@ -17,6 +17,7 @@
 
 package net.floodlightcontroller.packet;
 
+
 /**
 *
 * @author David Erickson (daviderickson@cs.stanford.edu)
@@ -85,4 +86,21 @@ public abstract class BasePacket implements IPacket {
             return false;
         return true;
     }
-}
+    
+    @Override
+    public Object clone() {
+        IPacket pkt;
+        try {
+            pkt = this.getClass().newInstance();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not clone packet");
+        }
+        // TODO: we are using serialize()/deserialize() to perform the 
+        // cloning. Not the most efficient way but simple. We can revisit
+        // if we hit performance problems.
+        byte[] data = this.serialize();
+        pkt.deserialize(this.serialize(), 0, data.length);
+        pkt.setParent(this.parent);
+        return pkt;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/packet/IPacket.java b/src/main/java/net/floodlightcontroller/packet/IPacket.java
index 8f783e31baa720229e0efeaf3b6f8bf5c8247114..094cfc700a10a4aab4d1ca7531333aed3309ace9 100644
--- a/src/main/java/net/floodlightcontroller/packet/IPacket.java
+++ b/src/main/java/net/floodlightcontroller/packet/IPacket.java
@@ -63,4 +63,10 @@ public interface IPacket {
      * @return the deserialized data
      */
     public IPacket deserialize(byte[] data, int offset, int length);
+    
+    /** Clone this packet and its payload packet but not its parent. 
+     * 
+     * @return
+     */
+    public Object clone();
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
index 445956a4d01cc8dd0bd40b1276f5275859f0c01d..d56bbb67f06f5bb7152e9d610a275efd207d1295 100644
--- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
+++ b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
@@ -20,9 +20,9 @@ package net.floodlightcontroller.routing;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Comparator;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -35,6 +35,7 @@ import net.floodlightcontroller.devicemanager.IDeviceListener;
 import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.packet.IPacket;
 import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.IRoutingDecision;
 import net.floodlightcontroller.routing.Route;
@@ -178,6 +179,7 @@ public abstract class ForwardingBase implements
                 (OFFlowMod) floodlightProvider.getOFMessageFactory()
                                               .getMessage(OFType.FLOW_MOD);
         OFActionOutput action = new OFActionOutput();
+        action.setMaxLength((short)0xffff);
         List<OFAction> actions = new ArrayList<OFAction>();
         actions.add(action);
 
@@ -208,9 +210,6 @@ public abstract class ForwardingBase implements
 
             // set buffer id if it is the source switch
             if (1 == indx) {
-                //fm.setMatch(match);
-                fm.setBufferId(bufferId);
-                //fm.setMatch(wildcard(match, sw, wildcard_hints));
                 // Set the flag to request flow-mod removal notifications only for the
                 // source switch. The removal message is used to maintain the flow
                 // cache. Don't set the flag for ARP messages - TODO generalize check
@@ -244,6 +243,8 @@ public abstract class ForwardingBase implements
 
                 // Push the packet out the source switch
                 if (sw.getId() == pinSwitch) {
+                    // TODO: Instead of doing a packetOut here we could also 
+                    // send a flowMod with bufferId set.... 
                     pushPacket(sw, match, pi, outPort, cntx);
                     srcSwitchIncluded = true;
                 }
@@ -268,6 +269,72 @@ public abstract class ForwardingBase implements
         }
         return match.clone();
     }
+    
+    /**
+     * Pushes a packet-out to a switch. If bufferId != BUFFER_ID_NONE we 
+     * assume that the packetOut switch is the same as the packetIn switch
+     * and we will use the bufferId 
+     * Caller needs to make sure that inPort and outPort differs
+     * @param packet    packet data to send
+     * @param sw        switch from which packet-out is sent
+     * @param bufferId  bufferId
+     * @param inPort    input port
+     * @param outPort   output port
+     * @param cntx      context of the packet
+     */
+    public void pushPacket(IPacket packet, 
+                           IOFSwitch sw,
+                           int bufferId,
+                           short inPort,
+                           short outPort, 
+                           FloodlightContext cntx) {
+        
+        
+        if (log.isTraceEnabled()) {
+            log.trace("PacketOut srcSwitch={} inPort={} outPort={}", 
+                      new Object[] {sw, inPort, outPort});
+        }
+
+        OFPacketOut po =
+                (OFPacketOut) floodlightProvider.getOFMessageFactory()
+                                                .getMessage(OFType.PACKET_OUT);
+
+        // set actions
+        List<OFAction> actions = new ArrayList<OFAction>();
+        actions.add(new OFActionOutput(outPort, (short) 0xffff));
+
+        po.setActions(actions)
+          .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
+        short poLength =
+                (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
+
+        // set buffer_id, in_port
+        po.setBufferId(bufferId);
+        po.setInPort(inPort);
+
+        // set data - only if buffer_id == -1
+        if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
+            if (packet == null) {
+                log.error("BufferId is set but no packet data is null. " +
+                		"Cannot send packetOut. " +
+                        "srcSwitch={} inPort={} outPort={}",
+                        new Object[] {sw, inPort, outPort});
+                return;
+            }
+            byte[] packetData = packet.serialize();
+            poLength += packetData.length;
+            po.setPacketData(packetData);
+        }
+
+        po.setLength(poLength);
+
+        try {
+            counterStore.updatePktOutFMCounterStore(sw, po);
+            sw.write(po, cntx);
+        } catch (IOException e) {
+            log.error("Failure writing packet out", e);
+        }
+    }
 
     /**
      * Pushes a packet-out to a switch.  The assumption here is that
@@ -311,7 +378,7 @@ public abstract class ForwardingBase implements
 
         // set actions
         List<OFAction> actions = new ArrayList<OFAction>();
-        actions.add(new OFActionOutput(outport, (short) 0));
+        actions.add(new OFActionOutput(outport, (short) 0xffff));
 
         po.setActions(actions)
           .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
@@ -339,20 +406,20 @@ public abstract class ForwardingBase implements
         }
     }
 
+    
     /**
      * Write packetout message to sw with output actions to one or more
      * output ports with inPort/outPorts passed in.
-     * Note that the packet in could be from a different switch.
-     * @param pi
+     * @param packetData
      * @param sw
      * @param inPort
      * @param ports
      * @param cntx
      */
-    public void PacketOutMultiPort(OFPacketIn pi,
+    public void packetOutMultiPort(byte[] packetData,
                                    IOFSwitch sw,
                                    short inPort,
-                                   HashSet<Integer> outPorts,
+                                   Set<Integer> outPorts,
                                    FloodlightContext cntx) {
         //setting actions
         List<OFAction> actions = new ArrayList<OFAction>();
@@ -379,7 +446,6 @@ public abstract class ForwardingBase implements
         // data (note buffer_id is always BUFFER_ID_NONE) and length
         short poLength = (short)(po.getActionsLength() + 
                 OFPacketOut.MINIMUM_LENGTH);
-        byte[] packetData = pi.getPacketData();
         poLength += packetData.length;
         po.setPacketData(packetData);
         po.setLength(poLength);
@@ -388,8 +454,8 @@ public abstract class ForwardingBase implements
             counterStore.updatePktOutFMCounterStore(sw, po);
             if (log.isTraceEnabled()) {
                 log.trace("write broadcast packet on switch-id={} " + 
-                        "interaces={} packet-in={} packet-out={}",
-                        new Object[] {sw.getId(), outPorts, pi, po});
+                        "interfaces={} packet-out={}",
+                        new Object[] {sw.getId(), outPorts, po});
             }
             sw.write(po, cntx);
 
@@ -397,6 +463,32 @@ public abstract class ForwardingBase implements
             log.error("Failure writing packet out", e);
         }
     }
+    
+    /** 
+     * @see packetOutMultiPort
+     * Accepts a PacketIn instead of raw packet data. Note that the inPort
+     * and switch can be different than the packet in switch/port
+     */
+    public void packetOutMultiPort(OFPacketIn pi,
+                                   IOFSwitch sw,
+                                   short inPort,
+                                   Set<Integer> outPorts,
+                                   FloodlightContext cntx) {
+        packetOutMultiPort(pi.getPacketData(), sw, inPort, outPorts, cntx);
+    }
+    
+    /** 
+     * @see packetOutMultiPort
+     * Accepts an IPacket instead of raw packet data. Note that the inPort
+     * and switch can be different than the packet in switch/port
+     */
+    public void packetOutMultiPort(IPacket packet,
+                                   IOFSwitch sw,
+                                   short inPort,
+                                   Set<Integer> outPorts,
+                                   FloodlightContext cntx) {
+        packetOutMultiPort(packet.serialize(), sw, inPort, outPorts, cntx);
+    }
 
     protected boolean isInBroadcastCache(IOFSwitch sw, OFPacketIn pi,
     		FloodlightContext cntx) {
@@ -486,40 +578,6 @@ public abstract class ForwardingBase implements
 
     }
 
-    /**
-     * @param floodlightProvider the floodlightProvider to set
-     */
-    public void setFloodlightProvider(IFloodlightProviderService floodlightProvider) {
-        this.floodlightProvider = floodlightProvider;
-    }
-
-    /**
-     * @param routingEngine the routingEngine to set
-     */
-    public void setRoutingEngine(IRoutingService routingEngine) {
-        this.routingEngine = routingEngine;
-    }
-
-    /**
-     * @param deviceManager
-     *            the deviceManager to set
-     */
-    public void setDeviceManager(IDeviceService deviceManager) {
-        this.deviceManager = deviceManager;
-    }
-
-    /**
-     * @param topology
-     *            the topology to set
-     */
-    public void setTopology(ITopologyService topology) {
-        this.topology = topology;
-    }
-
-    public void setCounterStore(ICounterStoreService counterStore) {
-        this.counterStore = counterStore;
-    }
-
     @Override
     public void deviceAdded(IDevice device) {
         // NOOP
diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
index 462612dfb820f9f966a64f0a1deb7f00cf0e3b10..fae8fd2a071ca8b1881bd942f6ca6a36de051ef1 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
@@ -616,7 +616,7 @@ public class TopologyManager implements
         floodlightProvider.addHAListener(this);
         addRestletRoutable();
     }
-    
+
     protected void addRestletRoutable() {
         restApi.addRestletRoutable(new TopologyWebRoutable());
     }
@@ -624,31 +624,35 @@ public class TopologyManager implements
     // ****************
     // Internal methods
     // ****************
-    protected Command dropFilter(IOFSwitch sw, OFPacketIn pi, 
+    /**
+     * If the packet-in switch port is disabled for all data traffic, then
+     * the packet will be dropped.  Otherwise, the packet will follow the
+     * normal processing chain.
+     * @param sw
+     * @param pi
+     * @param cntx
+     * @return
+     */
+    protected Command dropFilter(long sw, OFPacketIn pi,
                                              FloodlightContext cntx) {
         Command result = Command.CONTINUE;
-        Ethernet eth = 
-                IFloodlightProviderService.bcStore.
-                get(cntx,IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+        short port = pi.getInPort();
 
-        if (isAllowed(sw.getId(), pi.getInPort()) == false) {
-            if (eth.getEtherType() == Ethernet.TYPE_BDDP ||
-                (eth.isBroadcast() == false && eth.isMulticast() == false)) {
-                result = Command.CONTINUE;
-            } else {
-                if (log.isTraceEnabled()) {
-                    log.trace("Ignoring packet because of topology " + 
-                              "restriction on switch={}, port={}", 
-                              new Object[] {sw.getStringId(), 
-                                            pi.getInPort()});
-                }
+        // If the input port is not allowed for data traffic, drop everything.
+        // BDDP packets will not reach this stage.
+        if (isAllowed(sw, port) == false) {
+            if (log.isTraceEnabled()) {
+                log.trace("Ignoring packet because of topology " +
+                        "restriction on switch={}, port={}", sw, port);
                 result = Command.STOP;
             }
         }
+
+        // if sufficient information is available, then drop broadcast
+        // packets here as well.
         return result;
     }
 
-    
     /** 
      * TODO This method must be moved to a layer below forwarding
      * so that anyone can use it.
@@ -723,9 +727,10 @@ public class TopologyManager implements
         TopologyInstance ti = getCurrentInstance(false);
 
         Set<Long> switches = ti.getSwitchesInOpenflowDomain(pinSwitch);
-        
-        if (switches == null) // this implies that there are no links connected to the switches
+
+        if (switches == null)
         {
+            // indicates no links are connected to the switches
             switches = new HashSet<Long>();
             switches.add(pinSwitch);
         }
@@ -774,9 +779,7 @@ public class TopologyManager implements
         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.
-            return dropFilter(sw, pi, cntx);
+            return dropFilter(sw.getId(), pi, cntx);
         }
         return Command.STOP;
     }
@@ -823,7 +826,7 @@ public class TopologyManager implements
                            update.getDst(), update.getDstPort());
                 updateApplied = true;
             }
-            
+
             if (updateApplied) {
             	appliedUpdates.add(newUpdate);
             }
diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
index af007737c2308aaf1d7616c0cd22651623229a5d..20b677aef010bab17c2de08801c22d68e9063c25 100644
--- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
+++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
@@ -18,4 +18,4 @@ net.floodlightcontroller.counter.NullCounterStore
 net.floodlightcontroller.threadpool.ThreadPool
 net.floodlightcontroller.ui.web.StaticWebRoutable
 net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter
-net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier
\ No newline at end of file
+net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index f0bc0cdbde2db152c04be08504a4019ebeea6001..2d86734d465e6d436e55b8a1f049faa02522fd6b 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -1380,4 +1380,30 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         Arrays.sort(ips);
         assertArrayEquals(new Integer[] { 2, 42, 4242 }, ips);
     }
+    
+    // TODO: this test should really go into a separate class that collects
+    // unit tests for Device
+    @Test
+    public void testGetSwitchPortVlanId() {
+            Entity entity1 = new Entity(1L, (short)1, null, 10L, 1, new Date());
+            Entity entity2 = new Entity(1L, null, null, 10L, 1, new Date());
+            Entity entity3 = new Entity(1L, (short)3, null,  1L, 1, new Date());
+            Entity entity4 = new Entity(1L, (short)42, null,  1L, 1, new Date());
+            Entity[] entities = new Entity[] { entity1, entity2, 
+                                               entity3, entity4
+                                             };
+            Device d = new Device(null,1L, Arrays.asList(entities), null);
+            SwitchPort swp1x1 = new SwitchPort(1L, 1);
+            SwitchPort swp1x2 = new SwitchPort(1L, 2);
+            SwitchPort swp2x1 = new SwitchPort(2L, 1);
+            SwitchPort swp10x1 = new SwitchPort(10L, 1);
+            assertArrayEquals(new Short[] { -1, 1}, 
+                              d.getSwitchPortVlanIds(swp10x1));
+            assertArrayEquals(new Short[] { 3, 42}, 
+                              d.getSwitchPortVlanIds(swp1x1));
+            assertArrayEquals(new Short[0],
+                              d.getSwitchPortVlanIds(swp1x2));
+            assertArrayEquals(new Short[0],
+                              d.getSwitchPortVlanIds(swp2x1));
+    }
 }
diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
index 0d850a789fccbb818ffbe65c9a587e163c321198..feafc185b8471cd09e6f771b1cb883ecd3ced478 100644
--- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
+++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
@@ -215,7 +215,7 @@ public class ForwardingTest extends FloodlightTestCase {
         packetOut.setBufferId(this.packetIn.getBufferId())
             .setInPort(this.packetIn.getInPort());
         List<OFAction> poactions = new ArrayList<OFAction>();
-        poactions.add(new OFActionOutput((short) 3, (short) 0));
+        poactions.add(new OFActionOutput((short) 3, (short) 0xffff));
         packetOut.setActions(poactions)
             .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
             .setPacketData(testPacketSerialized)
@@ -274,7 +274,7 @@ public class ForwardingTest extends FloodlightTestCase {
         // Expected Flow-mods
         OFMatch match = new OFMatch();
         match.loadFromPacket(testPacketSerialized, (short) 1);
-        OFActionOutput action = new OFActionOutput((short)3, (short)0);
+        OFActionOutput action = new OFActionOutput((short)3, (short)0xffff);
         List<OFAction> actions = new ArrayList<OFAction>();
         actions.add(action);
 
@@ -310,9 +310,9 @@ public class ForwardingTest extends FloodlightTestCase {
         
         for (OFMessage m: msglist) {
             if (m instanceof OFFlowMod) 
-                assertTrue(m.equals(fm1));
+                assertEquals(fm1, m);
             else if (m instanceof OFPacketOut)
-                assertTrue(m.equals(packetOut)); 
+                assertEquals(packetOut, m);
         }
         
         OFMessage m = wc2.getValue();
@@ -356,7 +356,7 @@ public class ForwardingTest extends FloodlightTestCase {
         // Expected Flow-mods
         OFMatch match = new OFMatch();
         match.loadFromPacket(testPacketSerialized, (short) 1);
-        OFActionOutput action = new OFActionOutput((short)3, (short)0);
+        OFActionOutput action = new OFActionOutput((short)3, (short)0xffff);
         List<OFAction> actions = new ArrayList<OFAction>();
         actions.add(action);
 
diff --git a/src/test/java/net/floodlightcontroller/packet/PacketTest.java b/src/test/java/net/floodlightcontroller/packet/PacketTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..67bed71632c5b8163b57219c5488c9b8b007ad0b
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/packet/PacketTest.java
@@ -0,0 +1,126 @@
+package net.floodlightcontroller.packet;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PacketTest {
+    protected IPacket pkt1, pkt2, pkt3, pkt4;
+    protected IPacket dummyPkt;
+    protected IPacket[] packets;
+    
+    @Before
+    public void setUp() {
+        this.pkt1 = new Ethernet()
+        .setDestinationMACAddress("00:11:22:33:44:55")
+        .setSourceMACAddress("00:44:33:22:11:00")
+        .setEtherType(Ethernet.TYPE_IPv4)
+        .setPayload(
+                    new IPv4()
+                    .setTtl((byte) 128)
+                    .setSourceAddress("192.168.1.1")
+                    .setDestinationAddress("192.168.1.2")
+                    .setPayload(new UDP()
+                    .setSourcePort((short) 5000)
+                    .setDestinationPort((short) 5001)
+                    .setPayload(new Data(new byte[] {0x01}))));
+        
+        this.pkt2 = new Ethernet()
+        .setSourceMACAddress("00:44:33:22:11:01")
+        .setDestinationMACAddress("00:11:22:33:44:55")
+        .setEtherType(Ethernet.TYPE_ARP)
+        .setVlanID((short)5)
+        .setPayload(
+                    new ARP()
+                    .setHardwareType(ARP.HW_TYPE_ETHERNET)
+                    .setProtocolType(ARP.PROTO_TYPE_IP)
+                    .setHardwareAddressLength((byte) 6)
+                    .setProtocolAddressLength((byte) 4)
+                    .setOpCode(ARP.OP_REPLY)
+                    .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01"))
+                    .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
+                    .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
+                    .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
+        
+        
+        this.pkt3 = new Ethernet()
+        .setSourceMACAddress("00:44:33:22:11:01")
+        .setDestinationMACAddress("00:11:22:33:44:55")
+        .setEtherType(Ethernet.TYPE_ARP)
+        .setPayload(
+                    new ARP()
+                    .setHardwareType(ARP.HW_TYPE_ETHERNET)
+                    .setProtocolType(ARP.PROTO_TYPE_IP)
+                    .setHardwareAddressLength((byte) 6)
+                    .setProtocolAddressLength((byte) 4)
+                    .setOpCode(ARP.OP_REPLY)
+                    .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:01"))
+                    .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
+                    .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
+                    .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
+        
+        this.pkt4 = new Ethernet()
+        .setDestinationMACAddress("FF:FF:FF:FF:FF:FF")
+        .setSourceMACAddress("00:11:33:55:77:01")
+        .setEtherType(Ethernet.TYPE_IPv4)
+        .setPayload(
+                    new IPv4()
+                    .setTtl((byte) 128)
+                    .setSourceAddress("192.168.10.1")
+                    .setDestinationAddress("192.168.255.255")
+                    .setPayload(new UDP()
+                    .setSourcePort((short) 5000)
+                    .setDestinationPort((short) 5001)
+                    .setPayload(new Data(new byte[] {0x01}))));
+        
+        this.dummyPkt =  new IPv4()
+        .setTtl((byte) 32)
+        .setSourceAddress("1.2.3.4")
+        .setDestinationAddress("5.6.7.8");
+        
+        this.packets = new IPacket[] { pkt1, pkt2, pkt3, pkt4 };
+    }
+    
+    protected void doTestClone(IPacket pkt) {
+        if (pkt.getPayload() != null)
+            doTestClone(pkt.getPayload());
+        IPacket newPkt = (IPacket)pkt.clone();
+        assertSame(pkt.getClass(), newPkt.getClass());
+        assertNotSame(pkt, newPkt);
+        assertSame(pkt.getParent(), newPkt.getParent());
+        assertEquals(pkt, newPkt);
+        assertEquals(pkt.getPayload(), newPkt.getPayload());
+        if (pkt.getPayload() != null)
+            assertNotSame(pkt.getPayload(), newPkt.getPayload());
+        
+        if (pkt instanceof Ethernet) {
+            Ethernet eth = (Ethernet)pkt;
+            Ethernet newEth = (Ethernet)newPkt;
+            newEth.setDestinationMACAddress(new byte[] { 1,2,3,4,5,6});
+            assertEquals(false, newEth.getDestinationMAC()
+                                .equals(eth.getDestinationMAC()));
+            assertEquals(false, newPkt.equals(pkt));
+        }
+        if (pkt instanceof ARP) {
+            ARP arp = (ARP)pkt;
+            ARP newArp = (ARP)newPkt;
+            newArp.setSenderProtocolAddress(new byte[] {1,2,3,4});
+            assertEquals(false, newArp.getSenderProtocolAddress()
+                                .equals(arp.getSenderProtocolAddress()));
+            assertEquals(false, newPkt.equals(pkt));
+        }
+        
+        byte[] dummyData = dummyPkt.serialize().clone();
+        newPkt = (IPacket)pkt.clone();
+        newPkt.deserialize(dummyData, 0, dummyData.length);
+        assertEquals(false, newPkt.equals(pkt));
+    }
+    
+    @Test
+    public void testClone() {
+        for (IPacket pkt: packets) {
+            doTestClone(pkt);
+        }
+    }
+    
+}