diff --git a/.gitignore b/.gitignore
index aeb0dd73cfa475e0201e0be90a255c6240b0ba04..ad6e64ae7652599743f9625971681d5529b7b232 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@
 target
 thrift
 logback.xml
+*.swp
+*.pyc
diff --git a/build.xml b/build.xml
index e985d6fbd58f05c5c38e79c3cf09f19c9fd7c1c3..61017da6f4543e6b90f1b95622e0fd304c41c636 100644
--- a/build.xml
+++ b/build.xml
@@ -173,6 +173,7 @@
                 <pathelement location="${build-coverage}"/>
                 <pathelement location="${build}"/>
                 <pathelement location="${build-test}"/>
+                <pathelement location="${floodlight-jar}"/>
                 <path refid="classpath-test"/>
             </classpath>
             <formatter type="brief" usefile="true" />
@@ -181,6 +182,7 @@
                     <exclude name="**/storage/tests/StorageTest.java"/>
                     <exclude name="**/test/Mock*"/>
                     <exclude name="**/core/test/**"/>
+                    <exclude name="**/core/module/**"/>
                 </fileset>
             </batchtest>
         </junit>
diff --git a/floodlight.sh b/floodlight.sh
index 04e9afb9218de6f38cd62f6d5eee14bade1f8037..e67c6a7c13895b2c609a0040b4fa755dd5dee618 100755
--- a/floodlight.sh
+++ b/floodlight.sh
@@ -12,6 +12,7 @@ JVM_OPTS="$JVM_OPTS -Xmx2g -Xms2g -Xmn800m"
 JVM_OPTS="$JVM_OPTS -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods"
 JVM_OPTS="$JVM_OPTS -XX:InlineSmallCode=8192 -XX:MaxInlineSize=8192 -XX:FreqInlineSize=8192"
 JVM_OPTS="$JVM_OPTS -XX:CompileThreshold=1500 -XX:PreBlockSpin=8"
+JVM_OPTS="$JVM_OPTS -Dpython.security.respectJavaAccessibility=false"
 
 # Create a logback file if required
 [ -f ${FL_LOGBACK} ] || cat <<EOF_LOGBACK >${FL_LOGBACK}
diff --git a/src/main/images/Floodlight Icons.sketch/Data b/src/main/images/Floodlight Icons.sketch/Data
index bb5c893b9e5d4172708bd150a5c1137548333db9..0fbceabe0c97c926b15762291f968aca11db5a96 100644
Binary files a/src/main/images/Floodlight Icons.sketch/Data and b/src/main/images/Floodlight Icons.sketch/Data differ
diff --git a/src/main/images/Floodlight Icons.sketch/QuickLook/Preview.png b/src/main/images/Floodlight Icons.sketch/QuickLook/Preview.png
index 77fc493ec2b292f44d48e5a360f0459b45dab267..4a36e7cbb504eacc1a3a70237183873e35cbb61c 100644
Binary files a/src/main/images/Floodlight Icons.sketch/QuickLook/Preview.png and b/src/main/images/Floodlight Icons.sketch/QuickLook/Preview.png differ
diff --git a/src/main/images/Floodlight Icons.sketch/QuickLook/Thumbnail.png b/src/main/images/Floodlight Icons.sketch/QuickLook/Thumbnail.png
index 942c917bac3f2f0d351c47e4ad18001e31c4132d..50ebe22932430361c768192df9e1f4a2e3c2423a 100644
Binary files a/src/main/images/Floodlight Icons.sketch/QuickLook/Thumbnail.png and b/src/main/images/Floodlight Icons.sketch/QuickLook/Thumbnail.png differ
diff --git a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
index ec443e2076057ee754182dfa8bdff12bfe47d993..46a9b0e981d9e4ed2fd3a70834a4418e2b7722ac 100644
--- a/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
+++ b/src/main/java/net/floodlightcontroller/core/module/FloodlightModuleLoader.java
@@ -11,11 +11,13 @@ import java.util.Collection;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Queue;
+import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
 import java.util.Set;
 
@@ -75,9 +77,20 @@ public class FloodlightModuleLoader {
 	        ServiceLoader<IFloodlightModule> moduleLoader
 	            = ServiceLoader.load(IFloodlightModule.class, cl);
 	        // Iterate for each module, iterate through and add it's services
-	        for (IFloodlightModule m : moduleLoader) {
-	            if (logger.isTraceEnabled()) {
-	                logger.trace("Found module " + m.getClass().getName());
+	        Iterator<IFloodlightModule> moduleIter = moduleLoader.iterator();
+	        while (moduleIter.hasNext()) {
+	        	IFloodlightModule m = null;
+	        	try {
+	        		m = moduleIter.next();
+	        	} catch (ServiceConfigurationError sce) {
+	        		logger.debug("Could not find module");
+	        		//moduleIter.remove();
+	        		continue;
+	        	}
+	        //}
+	        //for (IFloodlightModule m : moduleLoader) {
+	            if (logger.isDebugEnabled()) {
+	                logger.debug("Found module " + m.getClass().getName());
 	            }
 
 	            // Set up moduleNameMap
@@ -100,7 +113,7 @@ public class FloodlightModuleLoader {
 	                    int dupInConf = 0;
 	                    for (IFloodlightModule cMod : mods) {
 	                        if (mList.contains(cMod.getClass().getCanonicalName()))
-	                            dupInConf++;
+	                            dupInConf += 1;
 	                    }
 	                    
 	                    if (dupInConf > 1) {
@@ -108,7 +121,7 @@ public class FloodlightModuleLoader {
                             for (IFloodlightModule mod : mods) {
                                 duplicateMods += mod.getClass().getCanonicalName() + ", ";
                             }
-	                        throw new FloodlightModuleException("ERROR! The configuraiton " +
+	                        throw new FloodlightModuleException("ERROR! The configuraiton" +
 	                                " file specifies more than one module that provides the service " +
 	                                s.getCanonicalName() +". Please specify only ONE of the " +
 	                                "following modules in the config file: " + duplicateMods);
@@ -164,12 +177,17 @@ public class FloodlightModuleLoader {
 	/**
 	 * Loads modules (and their dependencies) specified in the list
 	 * @param mList The array of fully qualified module names
+	 * @param ignoreList The list of Floodlight services NOT to 
+	 * load modules for. Used for unit testing.
 	 * @return The ModuleContext containing all the loaded modules
 	 * @throws FloodlightModuleException
 	 */
-	public IFloodlightModuleContext loadModulesFromList(Collection<String> configMods, Properties prop) 
-            throws FloodlightModuleException {
-        logger.trace("Starting module loader");
+	protected IFloodlightModuleContext loadModulesFromList(Collection<String> configMods, Properties prop, 
+			Collection<IFloodlightService> ignoreList) throws FloodlightModuleException {
+		logger.debug("Starting module loader");
+		if (logger.isDebugEnabled() && ignoreList != null)
+			logger.debug("Not loading module services " + ignoreList.toString());
+
         findAllModules(configMods);
         
         Collection<IFloodlightModule> moduleSet = new ArrayList<IFloodlightModule>();
@@ -192,6 +210,30 @@ public class FloodlightModuleLoader {
                 throw new FloodlightModuleException("Module " + 
                         moduleName + " not found");
             }
+            // If the module provies a service that is in the
+            // services ignorelist don't load it.
+            if ((ignoreList != null) && (module.getModuleServices() != null)) {
+            	for (IFloodlightService ifs : ignoreList) {
+            		for (Class<?> intsIgnore : ifs.getClass().getInterfaces()) {
+            			//System.out.println(intsIgnore.getName());
+        				// Check that the interface extends IFloodlightService
+        				//if (intsIgnore.isAssignableFrom(IFloodlightService.class)) {
+            			//System.out.println(module.getClass().getName());
+    					if (intsIgnore.isAssignableFrom(module.getClass())) {
+    						// We now ignore loading this module.
+    						logger.debug("Not loading module " + 
+    									 module.getClass().getCanonicalName() +
+    									 " because interface " +
+    									 intsIgnore.getCanonicalName() +
+    									 " is in the ignore list.");
+    						
+    						continue;
+    					}
+        				//}
+            		}
+            	}
+            }
+            
             // Add the module to be loaded
             addModule(moduleMap, moduleSet, module);
             // Add it's dep's to the queue
@@ -243,6 +285,18 @@ public class FloodlightModuleLoader {
         startupModules(moduleSet);
         
         return floodlightModuleContext;
+	}
+	
+	/**
+	 * Loads modules (and their dependencies) specified in the list.
+	 * @param configMods The collection of fully qualified module names to load.
+	 * @param prop The list of properties that are configuration options.
+	 * @return The ModuleContext containing all the loaded modules.
+	 * @throws FloodlightModuleException
+	 */
+	public IFloodlightModuleContext loadModulesFromList(Collection<String> configMods, Properties prop) 
+            throws FloodlightModuleException {
+		return loadModulesFromList(configMods, prop, null);
     }
 	
 	/**
@@ -320,8 +374,7 @@ public class FloodlightModuleLoader {
     protected void startupModules(Collection<IFloodlightModule> moduleSet) {
         for (IFloodlightModule m : moduleSet) {
             if (logger.isDebugEnabled()) {
-                logger.debug("Starting " + 
-                             m.getClass().getCanonicalName());
+                logger.debug("Starting " + m.getClass().getCanonicalName());
             }
             m.startUp(floodlightModuleContext);
         }
@@ -332,6 +385,8 @@ public class FloodlightModuleLoader {
      * @param prop The properties file to use
      */
     protected void parseConfigParameters(Properties prop) {
+    	if (prop == null) return;
+    	
         Enumeration<?> e = prop.propertyNames();
         while (e.hasMoreElements()) {
             String key = (String) e.nextElement();
diff --git a/src/main/java/net/floodlightcontroller/counter/CountSeries.java b/src/main/java/net/floodlightcontroller/counter/CountSeries.java
index c94e5bc613b66767903165ce74d8dec26ce8e4d0..e8a547a516bab83395aa9b73affd425e85b897bd 100644
--- a/src/main/java/net/floodlightcontroller/counter/CountSeries.java
+++ b/src/main/java/net/floodlightcontroller/counter/CountSeries.java
@@ -69,16 +69,18 @@ public class CountSeries {
   public static final long dateSpanToMilliseconds(DateSpan ds) {
     long delta = 1;
     switch(ds) {
-    case WEEKS:
-      delta *= 7;
-    case DAYS:
-      delta *= 24;
-    case HOURS:
-      delta *= 60;
-    case MINUTES:
-      delta *= 60;
-    case SECONDS:
-      delta *= 1000;
+	    case WEEKS:
+	    	delta *= 7;
+	    case DAYS:
+	    	delta *= 24;
+	    case HOURS:
+	    	delta *= 60;
+	    case MINUTES:
+	    	delta *= 60;
+	    case SECONDS:
+	    	delta *= 1000;
+	    default:
+	    	break;
     }
     return delta;
   }
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java
index 55efa582dccf873a716ded053ed7c6789ac0c4eb..e66aff98b458fd1cf0f223e9f8941dd81b577b53 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/AttachmentPoint.java
@@ -28,10 +28,9 @@ public class AttachmentPoint {
 
     // Timeout for moving attachment points from OF/broadcast
     // domain to another.
-    protected static long NBD_TO_BD_TIMEDIFF_MS = 300000; // 5 minutes
-    public static final long OPENFLOW_TO_EXTERNAL_TIMEOUT = 5000;  // 5 seconds
     public static final long EXTERNAL_TO_EXTERNAL_TIMEOUT = 5000;  // 5 seconds
-    public static final long CONSISTENT_TIMEOUT = 5000;            // 5 seconds
+    public static final long OPENFLOW_TO_EXTERNAL_TIMEOUT = 30000; // 30 seconds
+    public static final long CONSISTENT_TIMEOUT = 30000;           // 30 seconds
 
     public AttachmentPoint(long sw, short port, long lastSeen) {
         super();
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
index e654a6e798804a7469e0433acf62475d87563995..9caaa9779737ce7bc856ae41929a5746cc27edb1 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java
@@ -37,6 +37,7 @@ import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.IEntityClass;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.topology.ITopologyService;
 
 /**
@@ -94,6 +95,61 @@ public class Device implements IDevice {
         }
     }
 
+    /**
+     * Create a device from a set of entities
+     * @param deviceManager the device manager for this device
+     * @param deviceKey the unique identifier for this device object
+     * @param entities the initial entities for the device
+     * @param entityClass the entity class associated with the entities
+     */
+    public Device(DeviceManagerImpl deviceManager,
+                  Long deviceKey,
+                  Collection<AttachmentPoint> attachmentPoints,
+                  Collection<Entity> entities,
+                  IEntityClass entityClass) {
+        this.deviceManager = deviceManager;
+        this.deviceKey = deviceKey;
+        this.entities = entities.toArray(new Entity[entities.size()]);
+        if (attachmentPoints == null) {
+            this.attachmentPoints = null;
+        } else {
+            this.attachmentPoints =
+                    new ArrayList<AttachmentPoint>(attachmentPoints);
+        }
+        this.macAddressString =
+                HexString.toHexString(this.entities[0].getMacAddress(), 6);
+        this.entityClass = entityClass;
+        Arrays.sort(this.entities);
+    }
+
+    /**
+     * Construct a new device consisting of the entities from the old device
+     * plus an additional entity
+     * @param device the old device object
+     * @param newEntity the entity to add. newEntity must be have the same
+     *        entity class as device
+     */
+    public Device(Device device,
+                  Entity newEntity) {
+        this.deviceManager = device.deviceManager;
+        this.deviceKey = device.deviceKey;
+        this.entities = Arrays.<Entity>copyOf(device.entities,
+                                              device.entities.length + 1);
+        this.entities[this.entities.length - 1] = newEntity;
+        Arrays.sort(this.entities);
+    
+        if (device.attachmentPoints != null) {
+            this.attachmentPoints =
+                    new ArrayList<AttachmentPoint>(device.attachmentPoints);
+        } else 
+            this.attachmentPoints = null;
+    
+        this.macAddressString =
+                HexString.toHexString(this.entities[0].getMacAddress(), 6);
+    
+        this.entityClass = device.entityClass;
+    }
+
     private Map<Long, AttachmentPoint> getAPMap() {
 
         if (attachmentPoints == null) return null;
@@ -103,6 +159,16 @@ public class Device implements IDevice {
         List<AttachmentPoint>oldAP =
                 new ArrayList<AttachmentPoint>(attachmentPoints);
 
+        // Remove invalid attachment points before sorting.
+        List<AttachmentPoint>tempAP =
+                new ArrayList<AttachmentPoint>();
+        for(AttachmentPoint ap: oldAP) {
+            if (deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort())){
+                tempAP.add(ap);
+            }
+        }
+        oldAP = tempAP;
+
         Collections.sort(oldAP, deviceManager.apComparator);
 
         // Map of attachment point by L2 domain Id.
@@ -263,60 +329,7 @@ public class Device implements IDevice {
         return sp.toArray(new SwitchPort[sp.size()]);
     }
 
-    /**
-     * Create a device from a set of entities
-     * @param deviceManager the device manager for this device
-     * @param deviceKey the unique identifier for this device object
-     * @param entities the initial entities for the device
-     * @param entityClass the entity class associated with the entities
-     */
-    public Device(DeviceManagerImpl deviceManager,
-                  Long deviceKey,
-                  Collection<AttachmentPoint> attachmentPoints,
-                  Collection<Entity> entities,
-                  IEntityClass entityClass) {
-        this.deviceManager = deviceManager;
-        this.deviceKey = deviceKey;
-        this.entities = entities.toArray(new Entity[entities.size()]);
-        if (attachmentPoints == null) {
-            this.attachmentPoints = null;
-        } else {
-            this.attachmentPoints =
-                    new ArrayList<AttachmentPoint>(attachmentPoints);
-        }
-        this.macAddressString =
-                HexString.toHexString(this.entities[0].getMacAddress(), 6);
-        this.entityClass = entityClass;
-        Arrays.sort(this.entities);
-    }
-
-    /**
-     * Construct a new device consisting of the entities from the old device
-     * plus an additional entity
-     * @param device the old device object
-     * @param newEntity the entity to add. newEntity must be have the same
-     *        entity class as device
-     */
-    public Device(Device device,
-                  Entity newEntity) {
-        this.deviceManager = device.deviceManager;
-        this.deviceKey = device.deviceKey;
-        this.entities = Arrays.<Entity>copyOf(device.entities,
-                                              device.entities.length + 1);
-        this.entities[this.entities.length - 1] = newEntity;
-        Arrays.sort(this.entities);
-
-        if (device.attachmentPoints != null) {
-            this.attachmentPoints =
-                    new ArrayList<AttachmentPoint>(device.attachmentPoints);
-        } else 
-            this.attachmentPoints = null;
-
-        this.macAddressString =
-                HexString.toHexString(this.entities[0].getMacAddress(), 6);
-
-        this.entityClass = device.entityClass;
-    }
+    
 
     // *******
     // IDevice
@@ -476,7 +489,22 @@ public class Device implements IDevice {
 
     @Override
     public String toString() {
-        return "Device [entityClass=" + entityClass.getName() +
-                " entities=" + Arrays.toString(entities) + "]";
+        StringBuilder builder = new StringBuilder();
+        builder.append("Device [entityClass=");
+        builder.append(entityClass.getName());
+        builder.append(", MAC=");
+        builder.append(macAddressString);
+        builder.append(", IPs=[");
+        boolean isFirst = true;
+        for (Integer ip: getIPv4Addresses()) {
+            if (!isFirst)
+                builder.append(", ");
+            isFirst = false;
+            builder.append(IPv4.fromIPv4Address(ip));
+        }
+        builder.append("], APs=");
+        builder.append(Arrays.toString(getAttachmentPoints(true)));
+        builder.append("]");
+        return builder.toString();
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
index 62e4701e89a8ef96e0ee889bb5aef3cfa616a9f7..32d2ebc8ad73f148ae2c8f755cd07060de7cba3f 100755
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImpl.java
@@ -66,7 +66,6 @@ import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.packet.UDP;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.storage.IStorageSourceService;
-import net.floodlightcontroller.storage.IStorageSourceListener;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.floodlightcontroller.topology.ITopologyListener;
 import net.floodlightcontroller.topology.ITopologyService;
@@ -89,7 +88,7 @@ import org.slf4j.LoggerFactory;
  */
 public class DeviceManagerImpl implements
 IDeviceService, IOFMessageListener, ITopologyListener,
-IStorageSourceListener, IFloodlightModule, IEntityClassListener,
+IFloodlightModule, IEntityClassListener,
 IFlowReconcileListener, IInfoProvider, IHAListener {
     protected static Logger logger =
             LoggerFactory.getLogger(DeviceManagerImpl.class);
@@ -201,7 +200,7 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
      * A device update event to be dispatched
      */
     protected static class DeviceUpdate {
-        protected enum Change {
+        public enum Change {
             ADD, DELETE, CHANGE;
         }
 
@@ -227,6 +226,15 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
             this.change = change;
             this.fieldsChanged = fieldsChanged;
         }
+
+        @Override
+        public String toString() {
+            String devIdStr = device.getEntityClass().getName() + "::" +
+                    device.getMACAddressString();
+            return "DeviceUpdate [device=" + devIdStr + ", change=" + change
+                   + ", fieldsChanged=" + fieldsChanged + "]";
+        }
+        
     }
 
     /**
@@ -473,6 +481,46 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
         
         return new MultiIterator<Device>(iterators.iterator());
     }
+    
+    protected Iterator<Device> getDeviceIteratorForQuery(Long macAddress,
+    		Short vlan,
+    		Integer ipv4Address,
+    		Long switchDPID,
+    		Integer switchPort) {
+    	DeviceIndex index = null;
+    	if (secondaryIndexMap.size() > 0) {
+    		EnumSet<DeviceField> keys =
+    				getEntityKeys(macAddress, vlan, ipv4Address,
+    						switchDPID, switchPort);
+    		index = secondaryIndexMap.get(keys);
+    	}
+
+    	Iterator<Device> deviceIterator = null;
+    	if (index == null) {
+    		// Do a full table scan
+    		deviceIterator = deviceMap.values().iterator();
+    	} else {
+    		// index lookup
+    		Entity entity = new Entity((macAddress == null ? 0 : macAddress),
+    				vlan,
+    				ipv4Address,
+    				switchDPID,
+    				switchPort,
+    				null);
+    		deviceIterator =
+    				new DeviceIndexInterator(this, index.queryByEntity(entity));
+    	}
+
+    	DeviceIterator di =
+    			new DeviceIterator(deviceIterator,
+    					null,
+    					macAddress,
+    					vlan,
+    					ipv4Address,
+    					switchDPID,
+    					switchPort);
+    	return di;
+    }
 
     @Override
     public void addListener(IDeviceListener listener) {
@@ -520,6 +568,8 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
             case PACKET_IN:
                 return this.processPacketInMessage(sw,
                                                    (OFPacketIn) msg, cntx);
+            default:
+            	break;
         }
 
         logger.error("received an unexpected message {} from switch {}",
@@ -550,33 +600,22 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
             // Find the device matching the destination from the entity
             // classes of the source.
             Entity dstEntity = getEntityFromFlowMod(ofm.ofmWithSwDpid, false);
-            logger.trace("DeviceManager dstEntity {}", dstEntity);
+            Device dstDevice = null;
             if (dstEntity != null) {
-                Device dstDevice =
-                        findDestByEntity(srcDevice, dstEntity);
-                logger.trace("DeviceManager dstDevice {}", dstDevice);
+                dstDevice = findDestByEntity(srcDevice, dstEntity);
                 if (dstDevice != null)
                     fcStore.put(ofm.cntx, CONTEXT_DST_DEVICE, dstDevice);
             }
+            if (logger.isTraceEnabled()) {
+                logger.trace("Reconciling flow: match={}, srcDev={}, " 
+                		     + "dstEntity={}, dstDev={}",
+                		     new Object[] { ofm.ofmWithSwDpid, srcDevice, 
+                		                    dstEntity, dstDevice } );
+            }
         }
         return Command.CONTINUE;
     }
 
-    // **********************
-    // IStorageSourceListener
-    // **********************
-
-    @Override
-    public void rowsModified(String tableName, Set<Object> rowKeys) {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void rowsDeleted(String tableName, Set<Object> rowKeys) {
-        // TODO Auto-generated method stub
-
-    }
 
     // *****************
     // IFloodlightModule
@@ -686,6 +725,8 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                 logger.debug("Resetting device state because of role change");
                 startUp(null);
                 break;
+            default:
+            	break;
         }
     }
 
@@ -1176,6 +1217,9 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
         if (updates == null) return;
         DeviceUpdate update = null;
         while (null != (update = updates.poll())) {
+            if (logger.isTraceEnabled()) {
+                logger.trace("Dispatching device update: {}", update);
+            }
             for (IDeviceListener listener : deviceListeners) {
                 switch (update.change) {
                     case ADD:
@@ -1197,6 +1241,10 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                                 case VLAN:
                                     listener.deviceVlanChanged(update.device);
                                     break;
+                                default:
+                                	logger.error("Unknown device field changed {}",
+                                				update.fieldsChanged.toString());
+                                	break;
                             }
                         }
                         break;
@@ -1414,13 +1462,25 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                                            d,
                                            newDevice)) {
                         // concurrent modification; try again
-                        continue;
+                        // need to use device that is the map now for the next
+                        // iteration
+                        d = deviceMap.get(d.getDeviceKey());
+                        if (null != d)
+                            continue;
+                        else
+                            break;
                     }
                 } else {
                     deviceUpdates.add(new DeviceUpdate(d, DELETE, null));
                     if (!deviceMap.remove(d.getDeviceKey(), d))
                         // concurrent modification; try again
-                        continue;
+                        // need to use device that is the map now for the next
+                        // iteration
+                        d = deviceMap.get(d.getDeviceKey());
+                        if (null != d)
+                            continue;
+                        else
+                            break;
                 }
                 processUpdates(deviceUpdates);
                 break;
@@ -1448,6 +1508,23 @@ IFlowReconcileListener, IInfoProvider, IHAListener {
                                                        others);
         }
     }
+    
+    /**
+     * method to delete a given device, remove all entities first and then
+     * finally delete the device itself.
+     * @param device
+     */
+    protected void deleteDevice(Device device) {
+    	ArrayList<Entity> emptyToKeep = new ArrayList<Entity>();
+    	for (Entity entity : device.getEntities()) {
+    		this.removeEntity(entity, device.getEntityClass(), 
+    				device.getDeviceKey(), emptyToKeep);
+    	}
+    	if (!deviceMap.remove(device.getDeviceKey(), device)) {
+    		logger.info("device map does not have this device -" + 
+    	                 device.toString());
+    	}
+    }
 
     private EnumSet<DeviceField> getEntityKeys(Long macAddress,
                                                Short vlan,
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
index 8496f0a8e4f9a5e4b670969599e98f04adacb218..5904a6108fde23831647e0ea10d7cc0065fe51c1 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Entity.java
@@ -211,12 +211,28 @@ public class Entity implements Comparable<Entity> {
         return true;
     }
 
+    
+    
     @Override
     public String toString() {
-        return "Entity [macAddress=" + HexString.toHexString(macAddress, 6)
-               + ", ipv4Address="
-               + IPv4.fromIPv4Address(ipv4Address==null ? 0 : ipv4Address.intValue()) + ", vlan=" + vlan + ", switchDPID="
-               + switchDPID + ", switchPort=" + switchPort + "]";
+        StringBuilder builder = new StringBuilder();
+        builder.append("Entity [macAddress=");
+        builder.append(HexString.toHexString(macAddress, 6));
+        builder.append(", ipv4Address=");
+        builder.append(IPv4.fromIPv4Address(ipv4Address==null ?
+                       0 : ipv4Address.intValue()));
+        builder.append(", vlan=");
+        builder.append(vlan);
+        builder.append(", switchDPID=");
+        builder.append(switchDPID);
+        builder.append(", switchPort=");
+        builder.append(switchPort);
+        builder.append(", lastSeenTimestamp=");
+        builder.append(lastSeenTimestamp.getTime());
+        builder.append(", activeSince=");
+        builder.append(activeSince.getTime());
+        builder.append("]");
+        return builder.toString();
     }
 
     @Override
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
index 9d738ead7df24f8f919b47b1a1c34f883ab89732..618169f99985de0e2ce75a014e53965ebca801f4 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
@@ -33,6 +33,10 @@ public class FlowReconcileManager
      * need to be reconciled with the current configuration of the controller.
      */
     protected ListenerDispatcher<OFType, IFlowReconcileListener> flowReconcileListeners;
+    
+    /** Config to enable or disable flowReconcile */
+    protected static final String EnableConfigKey = "enable";
+    protected boolean flowReconcileEnabled;
 
     @Override
     public synchronized void addFlowReconcileListener(IFlowReconcileListener listener) {
@@ -65,6 +69,10 @@ public class FlowReconcileManager
      * @param ofmRcIn the ofm rc in
      */
     public void reconcileFlow(OFMatchReconcile ofmRcIn) {
+    	if (!flowReconcileEnabled) {
+    		return;
+    	}
+    	
         if (logger.isTraceEnabled()) {
             logger.trace("Reconciling flow: {}", ofmRcIn.toString());
         }
@@ -145,6 +153,17 @@ public class FlowReconcileManager
             throws FloodlightModuleException {
         flowReconcileListeners = 
                 new ListenerDispatcher<OFType, IFlowReconcileListener>();
+        
+        Map<String, String> configParam = context.getConfigParams(this);
+        String enableValue = configParam.get(EnableConfigKey);
+        // Set flowReconcile default to true
+        flowReconcileEnabled = true;
+        if (enableValue != null &&
+            enableValue.equalsIgnoreCase("false")) {
+            flowReconcileEnabled = false;
+        }
+        
+        logger.debug("FlowReconcile is {}", flowReconcileEnabled);
     }
 
     @Override
diff --git a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java b/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java
index 08fe99305a26b9cae6c8b48e58e737f4229e332a..005708d135b1b9f04e9539a58952e6a4c3318711 100644
--- a/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java
+++ b/src/main/java/net/floodlightcontroller/learningswitch/LearningSwitch.java
@@ -436,6 +436,8 @@ public class LearningSwitch
             case ERROR:
                 log.info("received an error {} from switch {}", (OFError) msg, sw);
                 return Command.CONTINUE;
+            default:
+            	break;
         }
         log.error("received an unexpected message {} from switch {}", msg, sw);
         return Command.CONTINUE;
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
index 3e43b6c527ebe786e641d6a891ecf429369ddc0b..c4421acfcf4971431da1efa0f5686df4871cf54f 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkDiscoveryService.java
@@ -37,7 +37,7 @@ public interface ILinkDiscoveryService extends IFloodlightService {
      * @param info
      * @return
      */
-    public ILinkDiscovery.LinkType getLinkType(LinkInfo info);
+    public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info);
 
     /**
      * Returns an unmodifiable map from switch id to a set of all links with it 
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index 76a056010573b9accaf360a5a8cfb11d1de48bd2..b818e8f7b848be108218c92c1b007bbc68e8ed16 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -309,9 +309,6 @@ IFloodlightModule, IInfoProvider, IHAListener {
 
         if (lldpClock == 0) {
             discoverOnAllPorts();
-            return;
-        } else {
-            discoverOnKnownLinkPorts();
         }
     }
 
@@ -546,6 +543,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
                 return this.handlePacketIn(sw.getId(), (OFPacketIn) msg, cntx);
             case PORT_STATUS:
                 return this.handlePortStatus(sw.getId(), (OFPortStatus) msg);
+            default:
+            	break;
         }
 
         log.error("Received an unexpected message {} from switch {}", msg, sw);
@@ -741,17 +740,6 @@ IFloodlightModule, IInfoProvider, IHAListener {
         else return UpdateOperation.PORT_DOWN;
     }
 
-    @Override
-    public LinkType getLinkType(LinkInfo info) {
-
-        if (info.getUnicastValidTime() != null)
-            return LinkType.DIRECT_LINK;
-        else if (info.getMulticastValidTime() != null)
-            return LinkType.MULTIHOP_LINK;
-
-        return LinkType.INVALID_LINK;
-    }
-
     protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {
 
         NodePortTuple srcNpt, dstNpt;
@@ -789,11 +777,11 @@ IFloodlightModule, IInfoProvider, IHAListener {
                 switchLinks.get(lt.getDst()).add(lt);
 
                 // index both ends by switch:port
-                if (!portLinks.containsKey(lt.getSrc()))
+                if (!portLinks.containsKey(srcNpt))
                     portLinks.put(srcNpt, new HashSet<Link>());
                 portLinks.get(srcNpt).add(lt);
 
-                if (!portLinks.containsKey(lt.getDst()))
+                if (!portLinks.containsKey(dstNpt))
                     portLinks.put(dstNpt, new HashSet<Link>());
                 portLinks.get(dstNpt).add(lt);
 
@@ -1587,8 +1575,12 @@ IFloodlightModule, IInfoProvider, IHAListener {
                     log.error("Exception in LLDP send timer.", e);
                 } finally {
                     if (!shuttingDown) {
-                        discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
+                        // null role implies HA mode is not enabled.
+                         Role role = floodlightProvider.getRole();
+                         if (role == null || role == Role.MASTER) {
+                             discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
                                                 TimeUnit.SECONDS);
+                         }
                     }
                 }
             }
@@ -1607,6 +1599,10 @@ IFloodlightModule, IInfoProvider, IHAListener {
             }}, "Topology Updates");
         updatesThread.start();
 
+        // null role implies HA mode is not enabled.
+        Role role = floodlightProvider.getRole();
+        if (role == null || role == Role.MASTER)
+            discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS);
         // Register for the OpenFlow messages we want to receive
         floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
         floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
@@ -1712,19 +1708,17 @@ IFloodlightModule, IInfoProvider, IHAListener {
     }
 
     // IHARoleListener
-
     @Override
     public void roleChanged(Role oldRole, Role newRole) {
         switch(newRole) {
             case MASTER:
                 if (oldRole == Role.SLAVE) {
-                    clearAllLinks();
                     if (log.isTraceEnabled()) {
                         log.trace("Sending LLDPs " +
                                 "to HA change from SLAVE->MASTER");
                     }
                     clearAllLinks();
-                    discoverLinks();
+                    discoveryTask.reschedule(1, TimeUnit.MICROSECONDS);
                 }
                 break;
             case SLAVE:
@@ -1738,6 +1732,8 @@ IFloodlightModule, IInfoProvider, IHAListener {
                 portBroadcastDomainLinks.clear();
                 discoverOnAllPorts();
                 break;
+			default:
+				break;
         }
     }
 
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
index 514cfe4f62acd329e772879c38296f9c5f7b1ff4..893e4adf0175a491f6852cbab42a262bf24758bf 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinkWithType.java
@@ -21,18 +21,25 @@ import net.floodlightcontroller.routing.Link;
 public class LinkWithType extends JsonSerializer<LinkWithType> {
     public long srcSwDpid;
     public short srcPort;
+    public int srcPortState;
     public long dstSwDpid;
     public short dstPort;
+    public int dstPortState;
     public LinkType type;
 
     // Do NOT delete this, it's required for the serializer
     public LinkWithType() {}
     
-    public LinkWithType(Link link, LinkType type) {
+    public LinkWithType(Link link,
+                        int srcPortState,
+                        int dstPortState,
+                        LinkType type) {
         this.srcSwDpid = link.getSrc();
         this.srcPort = link.getSrcPort();
+        this.srcPortState = srcPortState;
         this.dstSwDpid = link.getDst();
         this.dstPort = link.getDstPort();
+        this.dstPortState = dstPortState;
         this.type = type;
     }
 
@@ -43,8 +50,10 @@ public class LinkWithType extends JsonSerializer<LinkWithType> {
 		jgen.writeStartObject();
 		jgen.writeStringField("src-switch", HexString.toHexString(lwt.srcSwDpid));
 		jgen.writeNumberField("src-port", lwt.srcPort);
+		jgen.writeNumberField("src-port-state", lwt.srcPortState);
 		jgen.writeStringField("dst-switch", HexString.toHexString(lwt.dstSwDpid));
 		jgen.writeNumberField("dst-port", lwt.dstPort);
+		jgen.writeNumberField("dst-port-state", lwt.dstPortState);
 		jgen.writeStringField("type", lwt.type.toString());
 		jgen.writeEndObject();
 	}
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
index 8fe1ff046f192cd0bcded0792a0bbf3a7030a737..4cad18e61db608eea3479003880ffe25cb9f3638 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/web/LinksResource.java
@@ -25,7 +25,10 @@ public class LinksResource extends ServerResource {
             links.putAll(ld.getLinks());
             for (Link link: links.keySet()) {
                 LinkInfo info = links.get(link);
-                LinkWithType lwt = new LinkWithType(link, ld.getLinkType(info));
+                LinkWithType lwt = new LinkWithType(link,
+                                                    info.getSrcPortState(),
+                                                    info.getDstPortState(),
+                                                    ld.getLinkType(link, 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 6df676d6bf5eb3e74eb0b14e9d3ea6189636fd6b..4ecfdedddd813b1fbd42a3ad1a2dbc48eafc45ed 100644
--- a/src/main/java/net/floodlightcontroller/packet/BasePacket.java
+++ b/src/main/java/net/floodlightcontroller/packet/BasePacket.java
@@ -29,6 +29,7 @@ public abstract class BasePacket implements IPacket {
     /**
      * @return the parent
      */
+    @Override
     public IPacket getParent() {
         return parent;
     }
@@ -36,6 +37,7 @@ public abstract class BasePacket implements IPacket {
     /**
      * @param parent the parent to set
      */
+    @Override
     public IPacket setParent(IPacket parent) {
         this.parent = parent;
         return this;
@@ -44,6 +46,7 @@ public abstract class BasePacket implements IPacket {
     /**
      * @return the payload
      */
+    @Override
     public IPacket getPayload() {
         return payload;
     }
@@ -51,10 +54,17 @@ public abstract class BasePacket implements IPacket {
     /**
      * @param payload the payload to set
      */
+    @Override
     public IPacket setPayload(IPacket payload) {
         this.payload = payload;
         return this;
     }
+    
+    @Override
+    public void resetChecksum() {
+        if (this.parent != null)
+            this.parent.resetChecksum();
+    }
 
     /* (non-Javadoc)
      * @see java.lang.Object#hashCode()
diff --git a/src/main/java/net/floodlightcontroller/packet/DHCP.java b/src/main/java/net/floodlightcontroller/packet/DHCP.java
index 2001b4ff9dca8de0e0838aeb6647966747e744d8..f73d9c968019ab99ebfb4d5712c0e2a95a01e297 100644
--- a/src/main/java/net/floodlightcontroller/packet/DHCP.java
+++ b/src/main/java/net/floodlightcontroller/packet/DHCP.java
@@ -355,6 +355,9 @@ public class DHCP extends BasePacket {
 
     @Override
     public byte[] serialize() {
+        // not guaranteed to retain length/exact format
+        resetChecksum();
+
         // minimum size 240 including magic cookie, options generally padded to 300
         int optionsLength = 0;
         for (DHCPOption option : this.options) {
diff --git a/src/main/java/net/floodlightcontroller/packet/Ethernet.java b/src/main/java/net/floodlightcontroller/packet/Ethernet.java
index 123c9e0d0eff5bb16e51f5d043b53f52b2130ce3..e547812efb87464ec4492d7f96f24de6218fead1 100644
--- a/src/main/java/net/floodlightcontroller/packet/Ethernet.java
+++ b/src/main/java/net/floodlightcontroller/packet/Ethernet.java
@@ -329,6 +329,8 @@ public class Ethernet extends BasePacket {
         int result = super.hashCode();
         result = prime * result + destinationMACAddress.hashCode();
         result = prime * result + etherType;
+        result = prime * result + vlanID;
+        result = prime * result + priorityCode;
         result = prime * result + (pad ? 1231 : 1237);
         result = prime * result + sourceMACAddress.hashCode();
         return result;
diff --git a/src/main/java/net/floodlightcontroller/packet/IPacket.java b/src/main/java/net/floodlightcontroller/packet/IPacket.java
index 094cfc700a10a4aab4d1ca7531333aed3309ace9..02376cd990cbd1c1980b78bb7815323a46480cf2 100644
--- a/src/main/java/net/floodlightcontroller/packet/IPacket.java
+++ b/src/main/java/net/floodlightcontroller/packet/IPacket.java
@@ -48,6 +48,11 @@ public interface IPacket {
      */
     public IPacket setParent(IPacket packet);
 
+    /**
+     * Reset any checksums as needed, and call resetChecksum on all parents
+     */
+    public void resetChecksum();
+    
     /**
      * Sets all payloads parent packet if applicable, then serializes this 
      * packet and all payloads
diff --git a/src/main/java/net/floodlightcontroller/packet/IPv4.java b/src/main/java/net/floodlightcontroller/packet/IPv4.java
index ccfce792b3271d2aff56aee32b816d2ea45d6277..01f886da252bd59fa641f56b4684a0ce28087fdb 100644
--- a/src/main/java/net/floodlightcontroller/packet/IPv4.java
+++ b/src/main/java/net/floodlightcontroller/packet/IPv4.java
@@ -209,6 +209,11 @@ public class IPv4 extends BasePacket {
         this.checksum = checksum;
         return this;
     }
+    @Override
+    public void resetChecksum() {
+        this.checksum = 0;
+        super.resetChecksum();
+    }
 
     /**
      * @return the sourceAddress
diff --git a/src/main/java/net/floodlightcontroller/packet/TCP.java b/src/main/java/net/floodlightcontroller/packet/TCP.java
index 5fc6279bc76f2d3aa66949c8b8f77b5a915e517d..889e4c6a88292d3e2ea704aa3b49e38e93054fdd 100644
--- a/src/main/java/net/floodlightcontroller/packet/TCP.java
+++ b/src/main/java/net/floodlightcontroller/packet/TCP.java
@@ -114,6 +114,13 @@ public class TCP extends BasePacket {
         this.checksum = checksum;
         return this;
     }
+    
+    @Override
+    public void resetChecksum() {
+        this.checksum = 0;
+        super.resetChecksum();
+    }
+    
     public short getUrgentPointer(short urgentPointer) {
         return this.urgentPointer;
     }
diff --git a/src/main/java/net/floodlightcontroller/packet/UDP.java b/src/main/java/net/floodlightcontroller/packet/UDP.java
index 66f6b63307b296ed0b93a116b4dfa52870f6d33d..cbeeedfd18add16d1f657c7930cadf4bf08da6b8 100644
--- a/src/main/java/net/floodlightcontroller/packet/UDP.java
+++ b/src/main/java/net/floodlightcontroller/packet/UDP.java
@@ -97,6 +97,12 @@ public class UDP extends BasePacket {
         return this;
     }
 
+    @Override
+    public void resetChecksum() {
+        this.checksum = 0;
+        super.resetChecksum();
+    }
+
     /**
      * Serializes the packet. Will compute and set the following fields if they
      * are set to specific values at the time serialize is called:
diff --git a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
index d56bbb67f06f5bb7152e9d610a275efd207d1295..32525a8c8b5654fae27ee345295864aceada1a71 100644
--- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
+++ b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
@@ -70,7 +70,8 @@ public abstract class ForwardingBase implements
     
     // for broadcast loop suppression
     protected boolean broadcastCacheFeature = true;
-    public final int prime = 2633;  // for hash calculation
+    public final int prime1 = 2633;  // for hash calculation
+    public final static int prime2 = 4357;  // for hash calculation
     public TimedCache<Long> broadcastCache =
     		new TimedCache<Long>(100, 5*1000);  // 5 seconds interval;
 
@@ -139,6 +140,8 @@ public abstract class ForwardingBase implements
                                                    (OFPacketIn) msg,
                                                    decision,
                                                    cntx);
+            default:
+            	break;
         }
         log.error("received an unexpected message {} from switch {}",
                   msg,
@@ -504,8 +507,8 @@ public abstract class ForwardingBase implements
             		IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
         
         Long broadcastHash;
-        broadcastHash = topology.getL2DomainId(sw.getId())
-        		* prime + eth.hashCode();
+        broadcastHash = topology.getL2DomainId(sw.getId()) * prime1 +
+                        pi.getInPort() * prime2 + eth.hashCode();
         if (broadcastCache.update(broadcastHash)) {
             sw.updateBroadcastCache(broadcastHash, pi.getInPort());
             return true;
@@ -519,16 +522,15 @@ public abstract class ForwardingBase implements
         
         // If the feature is disabled, always return false;
         if (!broadcastCacheFeature) return false;
-        
+
         // Get the hash of the Ethernet packet.
         Ethernet eth =
                 IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
 
-        // some FORWARD_OR_FLOOD packets are unicast with unknown destination mac
-        // if (eth.isBroadcast() || eth.isMulticast())
-            return sw.updateBroadcastCache(new Long(eth.hashCode()), pi.getInPort());
+        long hash =  pi.getInPort() * prime2 + eth.hashCode();
 
-        // return false;
+        // some FORWARD_OR_FLOOD packets are unicast with unknown destination mac
+        return sw.updateBroadcastCache(hash, pi.getInPort());
     }
 
     public static boolean
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java
index e2cc5ec2c38ecf738cecfcca846ba0701576148a..524757f181bf79333b91029c3d404cc0b17c6f23 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java
@@ -625,6 +625,8 @@ public class StaticFlowEntryPusher
                 entry2dpid.clear();
                 entriesFromStorage.clear();
                 break;
+            default:
+            	break;
         }
     }
     
diff --git a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
index c261a23a3b20977f1ebfed357d685d6786253389..71751f9950738f9a58460927c8175322ab08cb9a 100644
--- a/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/floodlightcontroller/topology/TopologyManager.java
@@ -106,11 +106,8 @@ public class TopologyManager implements
         @Override 
         public void run() {
             try {
-                boolean recomputeFlag = false;
-                recomputeFlag = applyUpdates();
-                if (recomputeFlag) {
-                    createNewInstance();
-                }
+                applyUpdates();
+                createNewInstance();
                 lastUpdateTime = new Date();
                 informListeners();
             }
@@ -525,6 +522,8 @@ public class TopologyManager implements
             case PACKET_IN:
                 return this.processPacketInMessage(sw, 
                                                    (OFPacketIn) msg, cntx);
+            default:
+            	break;
         }
 
         log.error("received an unexpected message {} from switch {}", 
@@ -551,6 +550,8 @@ public class TopologyManager implements
                         "HA change to SLAVE");
                 clearCurrentTopology();
                 break;
+            default:
+            	break;
         }
     }
 
@@ -798,9 +799,8 @@ public class TopologyManager implements
     }
 
 
-    public boolean applyUpdates() {
+    public void applyUpdates() {
 
-        boolean topologyRecomputeRequired = false;
         appliedUpdates.clear();
         LDUpdate update = null;
         while (ldUpdates.peek() != null) {
@@ -816,23 +816,18 @@ public class TopologyManager implements
                 addOrUpdateLink(update.getSrc(), update.getSrcPort(),
                                 update.getDst(), update.getDstPort(),
                                 update.getType());
-                topologyRecomputeRequired = true;
             } else if (update.getOperation() == UpdateOperation.LINK_REMOVED){
                 removeLink(update.getSrc(), update.getSrcPort(), 
                            update.getDst(), update.getDstPort());
-                topologyRecomputeRequired = true;
             } else if (update.getOperation() == UpdateOperation.SWITCH_REMOVED) {
-                topologyRecomputeRequired = removeSwitch(update.getSrc());
+                removeSwitch(update.getSrc());
             } else if (update.getOperation() == UpdateOperation.PORT_DOWN) {
-                topologyRecomputeRequired = removeSwitchPort(update.getSrc(),
-                                                             update.getSrcPort());
+                removeSwitchPort(update.getSrc(), update.getSrcPort());
             }
 
             // Add to the list of applied updates.
             appliedUpdates.add(update);
         }
-
-        return topologyRecomputeRequired;
     }
 
     /**
diff --git a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java b/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java
index 8edf5bd20a1efa3be4699469a3fc7906e2e30810..f52d27a0735e936fc8425c4a30e58a3b43517d21 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/SwitchClustersResource.java
@@ -28,6 +28,7 @@ import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.topology.ITopologyService;
 
 import org.openflow.util.HexString;
+import org.restlet.data.Form;
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 
@@ -43,10 +44,20 @@ public class SwitchClustersResource extends ServerResource {
         ITopologyService topology = 
                 (ITopologyService)getContext().getAttributes().
                     get(ITopologyService.class.getCanonicalName());
+
+        Form form = getQuery();
+        String queryType = form.getFirstValue("type", true);
+        boolean openflowDomain = true;
+        if (queryType != null && "l2".equals(queryType)) {
+            openflowDomain = false;
+        }
         
         Map<String, List<String>> switchClusterMap = new HashMap<String, List<String>>();
         for (Entry<Long, IOFSwitch> entry : floodlightProvider.getSwitches().entrySet()) {
-            Long clusterDpid = topology.getL2DomainId(entry.getValue().getId());
+            Long clusterDpid = 
+                    (openflowDomain
+                     ? topology.getOpenflowDomainId(entry.getValue().getId())
+                     :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/virtualnetwork/VirtualNetworkFilter.java b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java
index 486bc7b21b5b417ea52cd9ce11a2739ce67ccb04..78d650779f63ca5b930b5f073b07ff270ad01ed2 100644
--- a/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java
+++ b/src/main/java/net/floodlightcontroller/virtualnetwork/VirtualNetworkFilter.java
@@ -300,6 +300,8 @@ public class VirtualNetworkFilter
         switch (msg.getType()) {
             case PACKET_IN:
                 return processPacketIn(sw, (OFPacketIn)msg, cntx);
+            default:
+            	break;
         }
         log.warn("Received unexpected message {}", msg);
         return Command.CONTINUE;
diff --git a/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java b/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java
index 803db8a9167fee4918e7d795cb9b42b665191100..bea7f1e3b064a947a95d1398696462ae886cf697 100644
--- a/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java
+++ b/src/main/java/org/openflow/protocol/statistics/OFFlowStatisticsReply.java
@@ -270,6 +270,23 @@ public class OFFlowStatisticsReply implements OFStatistics, OFActionFactoryAware
         }
     }
 
+    @Override
+    public String toString() {
+    	String str = "match=" + this.match;
+    	str += " tableId=" + this.tableId;
+    	str += " durationSeconds=" + this.durationSeconds;
+    	str += " durationNanoseconds=" + this.durationNanoseconds;
+    	str += " priority=" + this.priority;
+    	str += " idleTimeout=" + this.idleTimeout;
+    	str += " hardTimeout=" + this.hardTimeout;
+    	str += " cookie=" + this.cookie;
+    	str += " packetCount=" + this.packetCount;
+    	str += " byteCount=" + this.byteCount;
+    	str += " action=" + this.actions;
+    	
+    	return str;
+    }
+    
     @Override
     public int hashCode() {
         final int prime = 419;
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 430f7c6b6ede5ae1062ed7e0b36c7c7640320d58..0225a2b25a00e0e13c491d4af6de790db232a072 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
@@ -19,4 +19,7 @@ net.floodlightcontroller.threadpool.ThreadPool
 net.floodlightcontroller.ui.web.StaticWebRoutable
 net.floodlightcontroller.virtualnetwork.VirtualNetworkFilter
 net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier
+net.floodlightcontroller.devicemanager.test.MockDeviceManager
+net.floodlightcontroller.core.test.MockFloodlightProvider
+net.floodlightcontroller.core.test.MockThreadPoolService
 net.floodlightcontroller.firewall.Firewall
\ No newline at end of file
diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties
index 2ac8d4a613323f8343ecc7cc5b1f22335998578e..811f860589ddd4eb114788228df418ba8356ce93 100644
--- a/src/main/resources/floodlightdefault.properties
+++ b/src/main/resources/floodlightdefault.properties
@@ -1,4 +1,7 @@
 floodlight.modules = net.floodlightcontroller.storage.memory.MemoryStorageSource,\
+net.floodlightcontroller.core.FloodlightProvider,\
+net.floodlightcontroller.threadpool.ThreadPool,\
+net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
 net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
 net.floodlightcontroller.firewall.Firewall,\
 net.floodlightcontroller.forwarding.Forwarding,\
diff --git a/src/main/resources/web/img/switch.png b/src/main/resources/web/img/switch.png
index d241d92d74d012aa886823a597936b7dcab759c3..f8e69108f7d9c26ae92fcc41d7fb286cfc390edb 100644
Binary files a/src/main/resources/web/img/switch.png and b/src/main/resources/web/img/switch.png differ
diff --git a/src/main/resources/web/index.html b/src/main/resources/web/index.html
index 1812037aed3ce286cdcd31ace15edd21f4a16e9c..cc2c2e8ed7cff9fd1a555589ea4f7c8b6bc9a712 100644
--- a/src/main/resources/web/index.html
+++ b/src/main/resources/web/index.html
@@ -50,37 +50,14 @@
 
 <div class="header"></div>
 
-<!-- FIXME closing these alerts returns to the dashboard; why? -->
-
-
 <div class="container">
 
-<!--
-<div class="row">
-<div class="span12">
-<div class="alert alert-info">
-Floodlight is the awesomest OpenFlow controller, and you're running it right now.
-<a class="close" data-dismiss="alert" href="#">&times;</a>
-</div>
-</div>
-</div>
-
-<div class="row">
-<div class="span12">
-<div class="alert alert-error">
-This Web interface is <strong>incomplete and buggy</strong>! Don't be surprised if you see errors or missing data.
-<a class="close" data-dismiss="alert" href="#">&times;</a>
-</div>
-</div>
-</div>
--->
-
 <div id="content"></div>
 
 <hr>
 <footer class="footer">
-	<p><a href="http://floodlight.openflowhub.org/">Floodlight </a> © <a href="http://www.bigswitch.com/">Big Switch Networks</a>, <a href="http://www.research.ibm.com/arl/">IBM</a>, et. al.
-	Powered by <a href="http://documentcloud.github.com/backbone/">Backbone.js</a>, <a href="http://twitter.github.com/bootstrap/">Bootstrap</a>, <a href="http://jquery.com/">jQuery</a>, <a href="http://mbostock.github.com/d3/">D3.js</a>, etc.</p>
+    <p><a href="http://floodlight.openflowhub.org/">Floodlight </a> &copy; <a href="http://www.bigswitch.com/">Big Switch Networks</a>, <a href="http://www.research.ibm.com/arl/">IBM</a>, et. al.
+    Powered by <a href="http://documentcloud.github.com/backbone/">Backbone.js</a>, <a href="http://twitter.github.com/bootstrap/">Bootstrap</a>, <a href="http://jquery.com/">jQuery</a>, <a href="http://mbostock.github.com/d3/">D3.js</a>, etc.</p>
 </footer>
 
 </div> <!-- /container -->
diff --git a/src/main/resources/web/js/main.js b/src/main/resources/web/js/main.js
index 7e0ac8106a78109f9b48da40c70f61d43c749ad3..2362757ac690fb3c27bc6a6a54fbe3e2eead68a6 100644
--- a/src/main/resources/web/js/main.js
+++ b/src/main/resources/web/js/main.js
@@ -47,8 +47,8 @@ var AppRouter = Backbone.Router.extend({
     },
 
     topology:function () {
-    	//console.log("switching to topology view");
-    	var topo = new Topology();
+        //console.log("switching to topology view");
+        var topo = new Topology();
         $('#content').html(new TopologyView({model:topo, hosts:hl}).render().el);
         // TODO factor this code out
         $('ul.nav > li').removeClass('active');
@@ -56,30 +56,30 @@ var AppRouter = Backbone.Router.extend({
     },
     
     switchDetails:function (id) {
-    	//console.log("switching [sic] to single switch view");
-    	var sw = swl.get(id);
-    	$('#content').html(new SwitchView({model:sw}).render().el);
+        //console.log("switching [sic] to single switch view");
+        var sw = swl.get(id);
+        $('#content').html(new SwitchView({model:sw}).render().el);
         $('ul.nav > li').removeClass('active');
         $('li > a[href*="/switches"]').parent().addClass('active');
     },
     
     switchList:function () {
-    	//console.log("switching [sic] to switch list view");
+        //console.log("switching [sic] to switch list view");
         $('#content').html(new SwitchListView({model:swl}).render().el);
         $('ul.nav > li').removeClass('active');
         $('li > a[href*="/switches"]').parent().addClass('active');
     },
 
     hostDetails:function (id) {
-    	//console.log("switching to single host view");
-    	var h = hl.get(id);
-    	$('#content').html(new HostView({model:h}).render().el);
+        //console.log("switching to single host view");
+        var h = hl.get(id);
+        $('#content').html(new HostView({model:h}).render().el);
         $('ul.nav > li').removeClass('active');
         $('li > a[href*="/hosts"]').parent().addClass('active');
     },
     
     hostList:function () {
-    	//console.log("switching to host list view");
+        //console.log("switching to host list view");
         $('#content').html(new HostListView({model:hl}).render().el);
         $('ul.nav > li').removeClass('active');
         $('li > a[href*="/hosts"]').parent().addClass('active');
@@ -99,21 +99,21 @@ tpl.loadTemplates(['home', 'status', 'topology', 'header', 'switch', 'switch-lis
         
         $(document).ready(function () {
             // trigger Backbone routing when clicking on links, thanks to Atinux and pbnv
-	    app.navigate("", true);
-
-                window.document.addEventListener('click', function(e) {
-        	    e = e || window.event
-        	    var target = e.target || e.srcElement
-        	    if ( target.nodeName.toLowerCase() === 'a' ) {
-        	        e.preventDefault()
-        	        var uri = target.getAttribute('href')
-        	        app.navigate(uri.substr(1), true)
-        	    }
-        	});
-        	window.addEventListener('popstate', function(e) {
-        	    app.navigate(location.pathname.substr(1), true);
-        	});
-	    
+            app.navigate("", true);
+
+            window.document.addEventListener('click', function(e) {
+                e = e || window.event
+                var target = e.target || e.srcElement
+                if ( target.nodeName.toLowerCase() === 'a' ) {
+                    e.preventDefault()
+                    var uri = target.getAttribute('href')
+                    app.navigate(uri.substr(1), true)
+                }
+            });
+            window.addEventListener('popstate', function(e) {
+                app.navigate(location.pathname.substr(1), true);
+            });
+
         });
     });
 
diff --git a/src/main/resources/web/js/models/flowmodel.js b/src/main/resources/web/js/models/flowmodel.js
index 4923f610c415ca1e8e518e02c5bd3229c00f5a6b..80777c334f15c01bf7590bdf456320a2657a23ad 100644
--- a/src/main/resources/web/js/models/flowmodel.js
+++ b/src/main/resources/web/js/models/flowmodel.js
@@ -16,13 +16,13 @@
 
 window.Flow = Backbone.Model.extend({
 
-	defaults: {
-		receiveBytes: 0,
-		receivePackets: 0,
-		transmitBytes: 0,
-		transmitPackets: 0,
-	},
-	
+    defaults: {
+        receiveBytes: 0,
+        receivePackets: 0,
+        transmitBytes: 0,
+        transmitPackets: 0,
+    },
+
     // initialize:function () {}
 
 });
diff --git a/src/main/resources/web/js/models/hostmodel.js b/src/main/resources/web/js/models/hostmodel.js
index ec37d1573c043dd9f61cbdb159696da2e7c49774..47ae4207e97fb2168c81e900e42f38ac853fe2c4 100644
--- a/src/main/resources/web/js/models/hostmodel.js
+++ b/src/main/resources/web/js/models/hostmodel.js
@@ -62,11 +62,11 @@ window.HostCollection = Backbone.Collection.extend({
     }
 
     /*
-	 * findByName:function (key) { // TODO: Modify service to include firstName
-	 * in search var url = (key == '') ? '/host/' : "/host/search/" + key;
-	 * console.log('findByName: ' + key); var self = this; $.ajax({ url:url,
-	 * dataType:"json", success:function (data) { console.log("search success: " +
-	 * data.length); self.reset(data); } }); }
-	 */
+     * findByName:function (key) { // TODO: Modify service to include firstName
+     * in search var url = (key == '') ? '/host/' : "/host/search/" + key;
+     * console.log('findByName: ' + key); var self = this; $.ajax({ url:url,
+     * dataType:"json", success:function (data) { console.log("search success: " +
+     * data.length); self.reset(data); } }); }
+     */
 
 });
diff --git a/src/main/resources/web/js/models/statusmodel.js b/src/main/resources/web/js/models/statusmodel.js
index aac2f8d2aab44609bae4805d2667ade896f058ce..31bdff37565b54d2ccd2a66d1cac348d5ac8a0b8 100644
--- a/src/main/resources/web/js/models/statusmodel.js
+++ b/src/main/resources/web/js/models/statusmodel.js
@@ -16,14 +16,14 @@
 
 window.Status = Backbone.Model.extend({    
     defaults: {
-    	host: 'localhost',
-    	ofport: 6633,
-    	uptime: 'unknown',
-    	free: 0,
-    	total: 0,
-    	healthy: 'unknown',
-    	modules: [],
-    	moduleText: ''
+        host: 'localhost',
+        ofport: 6633,
+        uptime: 'unknown',
+        free: 0,
+        total: 0,
+        healthy: 'unknown',
+        modules: [],
+        moduleText: ''
     },
     
     initialize:function () {
@@ -54,7 +54,8 @@ window.Status = Backbone.Model.extend({
                 console.log("fetched controller status: modules loaded");
                 // console.log(data);
                 self.set({modules:_.keys(data)});
-                self.set({moduleText:_.reduce(_.keys(data), function(s, m){return s+m.replace("net.floodlightcontroller", "n.f")+", "}, '')});
+                self.set({moduleText:_.reduce(_.keys(data), function(s, m)
+                    {return s+m.replace("net.floodlightcontroller", "n.f")+", "}, '')});
             }
         });
 
diff --git a/src/main/resources/web/js/models/switchmodel.js b/src/main/resources/web/js/models/switchmodel.js
index 252b316e45c605e02477a57a167827cdd560865d..285c912cd148478a1c0a3c627dd0ab208efe9dab 100644
--- a/src/main/resources/web/js/models/switchmodel.js
+++ b/src/main/resources/web/js/models/switchmodel.js
@@ -153,18 +153,92 @@ window.Switch = Backbone.Model.extend({
             dataType:"json",
             success:function (data) {
                 //console.log("fetched  switch " + self.id + " flows");
-                // console.log(data[self.id]);
+                var flows = data[self.id];
+                //console.log(flows);
+
                 // create flow models
                 var i = 0;
-                _.each(data[self.id], function(f) {
+                _.each(flows, function(f) {
                     f.id = self.id + '-' + i++;
-                    f.matchHTML = "src=<a href='/host/" + f.match.dataLayerSource + "'>" +
-                        f.match.dataLayerSource +
-                        "</a>, dst=<a href='/host/" + f.match.dataLayerDestination + "'>" +
-                        f.match.dataLayerDestination + 
-                        "</a>, port=" + f.match.inputPort; // FIXME
-                    f.actionText = f.actions[0].type + " " + f.actions[0].port; // FIXME
-                    // console.log(f);
+
+                    // build human-readable match
+                    f.matchHTML = '';
+                    if(!(f.match.wildcards & (1<<0))) { // input port
+                        f.matchHTML += "port=" + f.match.inputPort + ", ";
+                    }
+                    if(!(f.match.wildcards & (1<<1))) { // VLAN ID
+                        f.matchHTML += "VLAN=" + f.match.dataLayerVirtualLan + ", ";
+                    }
+                    if(!(f.match.wildcards & (1<<20))) { // VLAN prio
+                        f.matchHTML += "prio=" + f.match.dataLayerVirtualLanPriorityCodePoint  + ", ";
+                    }
+                    if(!(f.match.wildcards & (1<<2))) { // src MAC
+                        f.matchHTML += "src=<a href='/host/" + f.match.dataLayerSource + "'>" +
+                        f.match.dataLayerSource + "</a>, ";
+                    }
+                    if(!(f.match.wildcards & (1<<3))) { // dest MAC
+                        f.matchHTML =+ "dest=<a href='/host/" + f.match.dataLayerDestination + "'>" +
+                        f.match.dataLayerDestination + "</a>, ";
+                    }
+                    if(!(f.match.wildcards & (1<<4))) { // Ethertype
+                        // TODO print a human-readable name instead of hex
+                        f.matchHTML += "ethertype=" + f.match.dataLayerType + ", ";
+                    }
+                    if(!(f.match.wildcards & (1<<5))) { // IP protocol
+                        // TODO print a human-readable name
+                        f.matchHTML += "proto=" + f.match.networkProtocol + ", ";
+                    }
+                    if(!(f.match.wildcards & (1<<6))) { // TCP/UDP source port
+                        f.matchHTML += "IP src port=" + f.match.transportSource + ", ";
+                    }
+                    if(!(f.match.wildcards & (1<<7))) { // TCP/UDP dest port
+                        f.matchHTML += "IP dest port=" + f.match.transportDestination  + ", ";
+                    }
+                    if(!(f.match.wildcards & (32<<8))) { // src IP
+                        f.matchHTML += "src=" + f.match.networkSource  + ", ";
+                    }
+                    if(!(f.match.wildcards & (32<<14))) { // dest IP
+                        f.matchHTML += "dest=" + f.match.networkDestination  + ", ";
+                    }
+                    if(!(f.match.wildcards & (1<<21))) { // IP TOS
+                        f.matchHTML += "TOS=" + f.match.networkTypeOfService  + ", ";
+                    }
+                    // remove trailing ", "
+                    f.matchHTML = f.matchHTML.substr(0, f.matchHTML.length - 2);
+
+                    // build human-readable action list
+                    f.actionText = _.reduce(f.actions, function (memo, a) {
+                        switch (a.type) {
+                            case "OUTPUT":
+                                return memo + "output " + a.port + ', ';
+                            case "OPAQUE_ENQUEUE":
+                                return memo + "enqueue " + a.port + ':' + a.queueId +  ', ';
+                            case "STRIP_VLAN":
+                                return memo + "strip VLAN, ";
+                            case "SET_VLAN_ID":
+                                return memo + "VLAN=" + a.virtualLanIdentifier + ', ';
+                            case "SET_VLAN_PCP":
+                                return memo + "prio=" + a.virtualLanPriorityCodePoint + ', ';
+                            case "SET_DL_SRC":
+                                return memo + "src=" + a.dataLayerAddress + ', ';
+                            case "SET_DL_DST":
+                                return memo + "dest=" + a.dataLayerAddress + ', ';
+                            case "SET_NW_TOS":
+                                return memo + "TOS=" + a.networkTypeOfService + ', ';
+                            case "SET_NW_SRC":
+                                return memo + "src=" + a.networkAddress + ', ';
+                            case "SET_NW_DST":
+                                return memo + "dest=" + a.networkAddress + ', ';
+                            case "SET_TP_SRC":
+                                return memo + "src port=" + a.transportPort + ', ';
+                            case "SET_TP_DST":
+                                return memo + "dest port=" + a.transportPort + ', ';
+                        }
+                    }, "");
+                    // remove trailing ", "
+                    f.actionText = f.actionText.substr(0, f.actionText.length - 2);
+
+                    //console.log(f);
                     self.flows.add(f, {silent: true});
                 });
                 self.flows.trigger('add');
@@ -185,8 +259,10 @@ window.SwitchCollection = Backbone.Collection.extend({
             dataType:"json",
             success:function (data) {
                 //console.log("fetched  switch list: " + data.length);
-                // console.log(data);
-                _.each(data, function(sw) {self.add({id: sw['dpid']})});
+                //console.log(data);
+                _.each(data, function(sw) {self.add({id: sw['dpid'],
+                                                     inetAddress: sw.inetAddress,
+                                                     connectedSince: new Date(sw.connectedSince).toLocaleString()})});
             }
         });
     },
diff --git a/src/main/resources/web/js/models/topologymodel.js b/src/main/resources/web/js/models/topologymodel.js
index be9fa302fa2b78ed0260e04118acaddd9823ade9..c5d8f9bff2cc9bbf13a7ee615faca1f173f23457 100644
--- a/src/main/resources/web/js/models/topologymodel.js
+++ b/src/main/resources/web/js/models/topologymodel.js
@@ -19,8 +19,8 @@ window.Topology = Backbone.Model.extend({
     url:"/wm/topology/links/json",
     
     defaults:{
-    	nodes: [],
-    	links: [],
+        nodes: [],
+        links: [],
     },
 
     initialize:function () {
@@ -34,19 +34,25 @@ window.Topology = Backbone.Model.extend({
                 // console.log(data);
                 self.nodes = {};
                 self.links = [];
+
                 // step 1: build unique array of switch IDs
+                /* this doesn't work if there's only one switch,
+                   because there are no switch-switch links
                 _.each(data, function (l) {
-                	self.nodes[l['src-switch']] = true;
-                	self.nodes[l['dst-switch']] = true;
+                    self.nodes[l['src-switch']] = true;
+                    self.nodes[l['dst-switch']] = true;
                 });
                 // console.log(self.nodes);
                 var nl = _.keys(self.nodes);
+                */
+                var nl = swl.pluck('id');
                 self.nodes = _.map(nl, function (n) {return {name:n}});
+
                 // step 2: build array of links in format D3 expects
                 _.each(data, function (l) {
-                	self.links.push({source:nl.indexOf(l['src-switch']),
-                					 target:nl.indexOf(l['dst-switch']),
-                					 value:10});
+                    self.links.push({source:nl.indexOf(l['src-switch']),
+                                     target:nl.indexOf(l['dst-switch']),
+                                     value:10});
                 });
                 // console.log(self.nodes);
                 // console.log(self.links);
diff --git a/src/main/resources/web/js/views/flow.js b/src/main/resources/web/js/views/flow.js
index 3d0609240edef0e4281d6b9741cea1d36e39d5d7..65e0b71d9e70a4522250e9c53f26499f68ad4c1e 100644
--- a/src/main/resources/web/js/views/flow.js
+++ b/src/main/resources/web/js/views/flow.js
@@ -48,7 +48,7 @@ window.FlowListItemView = Backbone.View.extend({
 // TODO throughput (bps) and pps sparklines would be nice here
 // TODO hovering over a MAC address could show a compact view of that host
 window.FlowListView = Backbone.View.extend({
-	
+
     initialize:function () {
         this.template = _.template(tpl.get('flow-list'));
         this.model.bind("change", this.render, this);
@@ -56,11 +56,11 @@ window.FlowListView = Backbone.View.extend({
     },
 
     render:function (eventName) {
-    	// console.log("rendering flow list view: " + this.model.models.length);
+        // console.log("rendering flow list view: " + this.model.models.length);
         $(this.el).html(this.template({nflows:this.model.length}));
         _.each(this.model.models, function (f) {
             $(this.el).find('table.flow-table > tbody')
-            	.append(new FlowListItemView({model:f}).render().el);
+                .append(new FlowListItemView({model:f}).render().el);
         }, this);
         return this;
     },
diff --git a/src/main/resources/web/js/views/port.js b/src/main/resources/web/js/views/port.js
index e6001e334df06e0d219a08a69af8f67dae2d7892..e9aadb9103a13b320e9131add8e0dfc68ca015fe 100644
--- a/src/main/resources/web/js/views/port.js
+++ b/src/main/resources/web/js/views/port.js
@@ -49,7 +49,7 @@ window.PortListItemView = Backbone.View.extend({
 
 // TODO throughput sparklines would be nice here
 window.PortListView = Backbone.View.extend({
-	
+
     initialize:function () {
         this.template = _.template(tpl.get('port-list'));
         this.model.bind("change", this.render, this);
@@ -57,11 +57,11 @@ window.PortListView = Backbone.View.extend({
     },
 
     render:function (eventName) {
-    	// console.log("rendering port list view");
+        // console.log("rendering port list view");
         $(this.el).html(this.template({nports:this.model.length}));
         _.each(this.model.models, function (p) {
             $(this.el).find('table.port-table > tbody')
-            	.append(new PortListItemView({model:p}).render().el);
+                .append(new PortListItemView({model:p}).render().el);
         }, this);
         return this;
     },
diff --git a/src/main/resources/web/js/views/status.js b/src/main/resources/web/js/views/status.js
index d56507e29e142be3993f0d708fbd1fe5ed1d5c64..52c6c1cbaa3e5a3279983979f625086ebe742f67 100644
--- a/src/main/resources/web/js/views/status.js
+++ b/src/main/resources/web/js/views/status.js
@@ -22,7 +22,7 @@ window.StatusView = Backbone.View.extend({
     },
 
     render:function (eventName) {
-    	// console.log("rendering status");
+        // console.log("rendering status");
         $(this.el).html(this.template(this.model.toJSON()));
         //$(this.el).html(this.template());
         return this;
diff --git a/src/main/resources/web/js/views/switch.js b/src/main/resources/web/js/views/switch.js
index 9aa850a364ced8f85374fa1522268127da8c9590..178dd99bba9021ac1675a17a46af2e77dc90e7f3 100644
--- a/src/main/resources/web/js/views/switch.js
+++ b/src/main/resources/web/js/views/switch.js
@@ -42,7 +42,7 @@ window.SwitchListItemView = Backbone.View.extend({
     initialize:function () {
         this.template = _.template(tpl.get('switch-list-item'));
         this.model.bind("change", this.render, this);
-	//this.model.bind("destroy", this.close, this);
+    //this.model.bind("destroy", this.close, this);
     },
 
     render:function (eventName) {
@@ -53,7 +53,7 @@ window.SwitchListItemView = Backbone.View.extend({
 });
 
 window.SwitchListView = Backbone.View.extend({
-	
+
     initialize:function () {
         this.template = _.template(tpl.get('switch-list'));
         this.model.bind("change", this.render, this);
@@ -63,7 +63,7 @@ window.SwitchListView = Backbone.View.extend({
         $(this.el).html(this.template({nswitches:swl.length}));
         _.each(this.model.models, function (sw) {
             $(this.el).find('table.switch-table > tbody')
-            	.append(new SwitchListItemView({model:sw}).render().el);
+                .append(new SwitchListItemView({model:sw}).render().el);
         }, this);
         return this;
     },
diff --git a/src/main/resources/web/tpl/flow-list-item.html b/src/main/resources/web/tpl/flow-list-item.html
index 59734906aacb0e2e830c113dcd24ba312c9e7815..7c099c3e7e0e43c9612412dc7b4220fcbe7b1001 100644
--- a/src/main/resources/web/tpl/flow-list-item.html
+++ b/src/main/resources/web/tpl/flow-list-item.html
@@ -1 +1 @@
-<td><%= cookie %></td><td><%= priority %></td><td><%= matchHTML %></td><td><%= actionText %></td><td><%= packetCount %></td><td><%= byteCount %></td><td><%= durationSeconds %> s</td><td><%= idleTimeout %> s</td>
+        <td><%= cookie %></td><td><%= priority %></td><td><%= matchHTML %></td><td><%= actionText %></td><td><%= packetCount %></td><td><%= byteCount %></td><td><%= durationSeconds %> s</td><td><%= idleTimeout %> s</td>
diff --git a/src/main/resources/web/tpl/flow-list.html b/src/main/resources/web/tpl/flow-list.html
index 4b6e4065b97cbdd5fe3b98c4eeea92c270bb804c..21a30cf8d1b67633cb5869e68e88c51f96db82ec 100644
--- a/src/main/resources/web/tpl/flow-list.html
+++ b/src/main/resources/web/tpl/flow-list.html
@@ -1,19 +1,19 @@
 <div class="page-header">
-	<h1>Flows (<%= nflows %>)</h1>
+    <h1>Flows (<%= nflows %>)</h1>
 </div>
-<table class="table striped-table flow-table">
-	<thead><tr><th>Cookie</th><th>Priority</th><th>Match</th><th>Action</th><th>Packets</th><th>Bytes</th><th>Age</th><th>Timeout</th></tr></thead>
-	<tbody>
-		<!-- flows will be inserted here by FlowListView:render -->
-	</tbody>
+<table class="table table-striped flow-table">
+    <thead><tr><th>Cookie</th><th>Priority</th><th>Match</th><th>Action</th><th>Packets</th><th>Bytes</th><th>Age</th><th>Timeout</th></tr></thead>
+    <tbody>
+        <!-- flows will be inserted here by FlowListView:render -->
+    </tbody>
 </table>
 <!-- TODO implement pagination -->
 <!-- 
 <div class="pagination pagination-right"><ul>
-	<li><a href="">&larr;</a></li>
-	<li class="active"><a href="">1</a></li>
-	<li><a href="">2</a></li>
-	<li><a href="">&rarr;</a>
+    <li><a href="">&larr;</a></li>
+    <li class="active"><a href="">1</a></li>
+    <li><a href="">2</a></li>
+    <li><a href="">&rarr;</a>
 </ul></div>
  -->
  
\ No newline at end of file
diff --git a/src/main/resources/web/tpl/header.html b/src/main/resources/web/tpl/header.html
index ae4545bab75917dea2a1783b4f38146140c153a6..78045ef69aa31ab758eda3716232c18230a205dc 100644
--- a/src/main/resources/web/tpl/header.html
+++ b/src/main/resources/web/tpl/header.html
@@ -1,4 +1,3 @@
-
 <div class="navbar navbar-fixed-top">
     <div class="navbar-inner">
         <div class="container">
@@ -7,8 +6,7 @@
                 <span class="icon-bar"></span>
                 <span class="icon-bar"></span>
             </a>
-            <!-- TODO we could use a better version of the OF logo without the drop shadow -->
-	    <img src="img/floodlight.png" style="float:left;">
+            <img src="img/floodlight.png" style="float:left;">
 
             <div class="nav-collapse">
                 <ul class="nav">
@@ -19,10 +17,10 @@
                     <!-- <li><a href="/vlans">VLANs</a></li> -->
                 </ul>
                 <form id="searchForm" class="navbar-search pull-right dropdown">
-                    <input id="searchText" type="text" class="search-query dropdown-toggle" placeholder="Search (try an IP or MAC address)">
+                    <input id="searchText" type="text" class="search-query dropdown-toggle"
+                           placeholder="Search (try an IP or MAC address)">
                 </form>
-            </div>
-            <!--/.nav-collapse -->
+            </div> <!--/.nav-collapse -->
         </div>
     </div>
 </div>
diff --git a/src/main/resources/web/tpl/home.html b/src/main/resources/web/tpl/home.html
index 1530c0f19f819a3b7ec9051d2822be0c612b0c22..6abf49441fef2210ae9866f74dd3a6e920dbfc8d 100644
--- a/src/main/resources/web/tpl/home.html
+++ b/src/main/resources/web/tpl/home.html
@@ -5,20 +5,3 @@
 <div id="host-list"></div>
 
 <!--  <div id="vlan-list"></div> -->
-
-<!--  Floodlight doesn't provide an API for this
-<div class="row">
-<div class="span12">
-<div class="page-header">
-	<h1>Recent Events</h1>
-</div>
-<table class="table striped-table">
-	<thead><tr><th>Time</th><th>Device</th><th>Message</th></tr></thead>
-	<tbody>
-		<tr><td>Fri Mar 30 15:16:52 CDT 2012</td><td>Switch <a href="">C</a></td><td><i class="icon-fire"></i> caught on fire.</td></tr> 
-		<tr><td>Fri Mar 30 15:14:15 CDT 2012</td><td>Host <a href="">BroVM</a></td><td><i class="icon-resize-horizontal"></i> moved from <a href="">switch a port x</a> to <a href="">switch b port y</a>.</td></tr>
-	</tbody>
-</table>
-</div>
-</div>
--->
diff --git a/src/main/resources/web/tpl/host-list-item.html b/src/main/resources/web/tpl/host-list-item.html
index bf6797f871ceab879b9a8795637a5d424c48d0f6..169477e3601ab775dc9a74782ef4c4571521b09b 100644
--- a/src/main/resources/web/tpl/host-list-item.html
+++ b/src/main/resources/web/tpl/host-list-item.html
@@ -1 +1 @@
-		<td><a href="/host/<%= mac %>"><%= mac %></a></td><!-- <td><%= vlan %></td> --><td><%= ipv4 %></td><td><%= swport %></td><td><%= lastSeen %></td>
+        <td><a href="/host/<%= mac %>"><%= mac %></a></td><!-- <td><%= vlan %></td> --><td><%= ipv4 %></td><td><%= swport %></td><td><%= lastSeen %></td>
diff --git a/src/main/resources/web/tpl/host-list.html b/src/main/resources/web/tpl/host-list.html
index ec63b3a76cab06455e251644f4e61736b209e0f8..bc1f36437e40aeab513eac8e483cee065fc1ae1d 100644
--- a/src/main/resources/web/tpl/host-list.html
+++ b/src/main/resources/web/tpl/host-list.html
@@ -1,21 +1,22 @@
 <div class="row">
 <div class="span12">
 <div class="page-header">
-	<h1>Hosts (<%= nhosts %>)</h1>
+    <h1>Hosts (<%= nhosts %>)</h1>
 </div>
-<table class="table striped-table host-table">
-	<thead><tr><th>MAC Address</th><!-- <th>VLAN</th> --><th>IP Address</th><th>Switch Port</th><th>Last Seen</th></tr></thead>
-	<tbody>
-		<!-- hosts will be inserted here by HostListView.render -->
-	</tbody>
+<table class="table table-striped host-table">
+    <thead><tr><th>MAC Address</th><!-- <th>VLAN</th> --><th>IP Address</th><th>Switch Port</th><th>Last Seen</th>
+           </tr></thead>
+    <tbody>
+        <!-- hosts will be inserted here by HostListView.render -->
+    </tbody>
 </table>
 <!-- TODO implement pagination -->
-<!-- 
+<!--
 <div class="pagination pagination-right"><ul>
-	<li><a href="">&larr;</a></li>
-	<li class="active"><a href="">1</a></li>
-	<li><a href="">2</a></li>
-	<li><a href="">&rarr;</a>
+    <li><a href="">&larr;</a></li>
+    <li class="active"><a href="">1</a></li>
+    <li><a href="">2</a></li>
+    <li><a href="">&rarr;</a>
 </ul></div>
 -->
 </div>
diff --git a/src/main/resources/web/tpl/host.html b/src/main/resources/web/tpl/host.html
index 1aa38015a1bedd1748b3f8c9da131e00e035bf07..985940f4bd54ace32a162db35f5fb524c89e3ddf 100644
--- a/src/main/resources/web/tpl/host.html
+++ b/src/main/resources/web/tpl/host.html
@@ -1,7 +1,7 @@
 <div class="row">
 <div class="span12">
 <div class="page-header">
-	<h1>Host <%= id %></h1>
+    <h1>Host <%= id %></h1>
 </div>
 <p>
 <!-- VLAN: <a href="/vlan/<%= vlan %>"><%= vlan %></a><br> -->
diff --git a/src/main/resources/web/tpl/port-list-item.html b/src/main/resources/web/tpl/port-list-item.html
index 93252c961359c64769d9288c64ae1eee20f05324..bfc197844591a942baf2bd6807be2516683f0ec6 100644
--- a/src/main/resources/web/tpl/port-list-item.html
+++ b/src/main/resources/web/tpl/port-list-item.html
@@ -1 +1 @@
-		<td><a id="<%= portNumber %>"><%= name %></a></td><td><%= status %></td><td><%= transmitBytes %></td><td><%= receiveBytes %></td><td><%= transmitPackets %></td><td><%= receivePackets %></td><td><%= dropped %></td><td><%= errors %></td>
+        <td><a id="<%= portNumber %>"><%= name %></a></td><td><%= status %></td><td><%= transmitBytes %></td><td><%= receiveBytes %></td><td><%= transmitPackets %></td><td><%= receivePackets %></td><td><%= dropped %></td><td><%= errors %></td>
diff --git a/src/main/resources/web/tpl/port-list.html b/src/main/resources/web/tpl/port-list.html
index d4c30606af8270b512d537497c8c144e732e377d..9ceb6c3346a78583b713bc0f5d30aa7867b82a20 100644
--- a/src/main/resources/web/tpl/port-list.html
+++ b/src/main/resources/web/tpl/port-list.html
@@ -1,19 +1,19 @@
 <div class="page-header">
-	<h1>Ports (<%= nports %>)</h1>
+    <h1>Ports (<%= nports %>)</h1>
 </div>
-<table class="table striped-table port-table">
-	<thead><tr><th>#</th><th>Link Status</th><th>TX Bytes</th><th>RX Bytes</th><th>TX Pkts</th><th>RX Pkts</th><th>Dropped</th><th>Errors</th></tr></thead>
-	<tbody>
-		<!-- ports will be inserted here by PortListView:render -->
-	</tbody>
+<table class="table table-striped port-table">
+    <thead><tr><th>#</th><th>Link Status</th><th>TX Bytes</th><th>RX Bytes</th><th>TX Pkts</th><th>RX Pkts</th><th>Dropped</th><th>Errors</th></tr></thead>
+    <tbody>
+        <!-- ports will be inserted here by PortListView:render -->
+    </tbody>
 </table>
 <!-- TODO implement pagination -->
-<!-- 
+<!--
 <div class="pagination pagination-right"><ul>
-	<li><a href="">&larr;</a></li>
-	<li class="active"><a href="">1</a></li>
-	<li><a href="">2</a></li>
-	<li><a href="">&rarr;</a>
+    <li><a href="">&larr;</a></li>
+    <li class="active"><a href="">1</a></li>
+    <li><a href="">2</a></li>
+    <li><a href="">&rarr;</a>
 </ul></div>
 -->
  
\ No newline at end of file
diff --git a/src/main/resources/web/tpl/status.html b/src/main/resources/web/tpl/status.html
index 86b77bf396f5a30cfb946bf7a6f13c06bd69395a..5a768697476a047bf734aec5281aaf993475b1b0 100644
--- a/src/main/resources/web/tpl/status.html
+++ b/src/main/resources/web/tpl/status.html
@@ -1,13 +1,13 @@
 <div class="row">
 <div class="span12">
 <div class="page-header">
-	<h1>Controller Status</h1>
+    <h1>Controller Status</h1>
 </div>
 <table class="status-table">
-  <tr><td class="status-head">Hostname:<td><%= host %>:<%= ofport %></td></tr>
-  <tr><td class="status-head">Healthy:<td><%= healthy %></td>
-  <tr><td class="status-head">Uptime:<td><%= uptime %><td>
-  <tr><td class="status-head">JVM memory bloat:<td><%= free %> free out of <%= total %></td>
-  <Tr><td class="status-head">Modules loaded:<td><%= moduleText %></td>
+    <tr><td class="status-head">Hostname:<td><%= host %>:<%= ofport %></td></tr>
+    <tr><td class="status-head">Healthy:<td><%= healthy %></td>
+    <tr><td class="status-head">Uptime:<td><%= uptime %><td>
+    <tr><td class="status-head">JVM memory bloat:<td><%= free %> free out of <%= total %></td>
+    <Tr><td class="status-head">Modules loaded:<td><%= moduleText %></td>
 </div>
 </div>
diff --git a/src/main/resources/web/tpl/switch-list-item.html b/src/main/resources/web/tpl/switch-list-item.html
index 7a20a5a09ad02cb3123d38e4029ddb7c4c0e98c9..7ce026278f23f7e060214a660576bd8ce1ef79bf 100644
--- a/src/main/resources/web/tpl/switch-list-item.html
+++ b/src/main/resources/web/tpl/switch-list-item.html
@@ -1 +1 @@
-<td><a href="/switch/<%= id %>"><%= id %></a></td><td><%= manufacturerDescription %><td><%= packetCount %></td><td><%= byteCount %></td><td><%= flowCount %></td>
+        <td><a href="/switch/<%= id %>"><%= id %></a></td><td><%= inetAddress %></td><td><%= manufacturerDescription %><td><%= packetCount %></td><td><%= byteCount %></td><td><%= flowCount %></td><td><%= connectedSince %></td>
diff --git a/src/main/resources/web/tpl/switch-list.html b/src/main/resources/web/tpl/switch-list.html
index 45c02f55f13b1024d9882bb489cda6cce8f6c8f4..e7dac09c1d84bc23d50724de1dd46e547fc9fb66 100644
--- a/src/main/resources/web/tpl/switch-list.html
+++ b/src/main/resources/web/tpl/switch-list.html
@@ -1,21 +1,21 @@
 <div class="row">
 <div class="span12">
 <div class="page-header">
-	<h1>Switches (<%= nswitches %>)</h1>
+    <h1>Switches (<%= nswitches %>)</h1>
 </div>
-<table class="table striped-table switch-table">
-    <thead><tr><th>DPID</th><th>Vendor</th><th>Packets</th><th>Bytes</th><th>Flows</th></tr></thead>
-	<tbody>
-		<!-- switches will be inserted here by SwitchListView:render -->
-	</tbody>
+<table class="table table-striped switch-table">
+    <thead><tr><th>DPID</th><th>IP Address</th><th>Vendor</th><th>Packets</th><th>Bytes</th><th>Flows</th><th>Connected Since</th></tr></thead>
+    <tbody>
+        <!-- switches will be inserted here by SwitchListView:render -->
+    </tbody>
 </table>
 <!-- TODO implement pagination -->
-<!-- 
+<!--
 <div class="pagination pagination-right"><ul>
-	<li><a href="">&larr;</a></li>
-	<li class="active"><a href="">1</a></li>
-	<li><a href="">2</a></li>
-	<li><a href="">&rarr;</a>
+    <li><a href="">&larr;</a></li>
+    <li class="active"><a href="">1</a></li>
+    <li><a href="">2</a></li>
+    <li><a href="">&rarr;</a>
 </ul></div>
 -->
 </div>
diff --git a/src/main/resources/web/tpl/switch.html b/src/main/resources/web/tpl/switch.html
index bfba96795031241c30500042d1331bd6ba5b400e..af89797e9c7bbef6d5f7e80ce7b6e35f08a609d3 100644
--- a/src/main/resources/web/tpl/switch.html
+++ b/src/main/resources/web/tpl/switch.html
@@ -1,13 +1,13 @@
 <div class="row">
 <div class="span12">
 <div class="page-header">
-	<h1>Switch <%= id %></h1>
+    <h1>Switch <%= id %> <%= inetAddress %></h1>
 </div>
-<p><%= manufacturerDescription %><br>
+<p>Connected since <%= connectedSince %><br>
+<%= manufacturerDescription %><br>
 <%= hardwareDescription %><br>
 <%= softwareDescription %><br>
 S/N: <%= serialNumber %><br>
-<!-- <%= flowCount %> flows -->
 </p>
 
 <div id="port-list"></div> <!-- TODO would be nice to make this collapsible -->
diff --git a/src/main/resources/web/tpl/topology.html b/src/main/resources/web/tpl/topology.html
index feb88df84431f305dad86691cea877f7b566f4aa..ce77cc75b550a8c64973eb96d403a2ea943d66ec 100644
--- a/src/main/resources/web/tpl/topology.html
+++ b/src/main/resources/web/tpl/topology.html
@@ -1,7 +1,7 @@
 <div class="row">
 <div class="span12">
 <div class="page-header">
-	<h1>Network Topology</h1>
+    <h1>Network Topology</h1>
 </div>
 <div id="topology-graph"></div>
 </div>
diff --git a/src/main/resources/web/tpl/vlan-list-item.html b/src/main/resources/web/tpl/vlan-list-item.html
index 785517b0ac42ad319e064e2e434f0a9f5680d39f..55a2f35567b78f6497c7ce2ce43538fc6b699c40 100644
--- a/src/main/resources/web/tpl/vlan-list-item.html
+++ b/src/main/resources/web/tpl/vlan-list-item.html
@@ -1 +1 @@
-		<tr><td><a href="/vlan/<%= id %>"><%= id %></a></td><td><%= name %></td><td><%= nhosts %></td></tr>
+        <tr><td><a href="/vlan/<%= id %>"><%= id %></a></td><td><%= name %></td><td><%= nhosts %></td></tr>
diff --git a/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java b/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ba838e51fc268ac0a7ea7086b90d9476950a638
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/core/module/FloodlightTestModuleLoader.java
@@ -0,0 +1,182 @@
+package net.floodlightcontroller.core.module;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.floodlightcontroller.core.module.FloodlightModuleLoader;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.test.MockFloodlightProvider;
+import net.floodlightcontroller.core.test.MockThreadPoolService;
+import net.floodlightcontroller.counter.NullCounterStore;
+import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier;
+import net.floodlightcontroller.devicemanager.test.MockDeviceManager;
+import net.floodlightcontroller.perfmon.NullPktInProcessingTime;
+import net.floodlightcontroller.storage.memory.MemoryStorageSource;
+import net.floodlightcontroller.topology.TopologyManager;
+
+public class FloodlightTestModuleLoader extends FloodlightModuleLoader {
+	protected static Logger log = LoggerFactory.getLogger(FloodlightTestModuleLoader.class);
+	
+	// List of default modules to use unless specified otherwise
+	public static final Class<? extends IFloodlightModule> DEFAULT_STORAGE_SOURCE =
+			MemoryStorageSource.class;
+	public static final Class<? extends IFloodlightModule> DEFAULT_FLOODLIGHT_PRPOVIDER =
+			MockFloodlightProvider.class;
+	public static final Class<? extends IFloodlightModule> DEFAULT_TOPOLOGY_PROVIDER =
+			TopologyManager.class;
+	public static final Class<? extends IFloodlightModule> DEFAULT_DEVICE_SERVICE =
+			MockDeviceManager.class;
+	public static final Class<? extends IFloodlightModule> DEFAULT_COUNTER_STORE =
+			NullCounterStore.class;
+	public static final Class<? extends IFloodlightModule> DEFAULT_THREADPOOL =
+			MockThreadPoolService.class;
+	public static final Class<? extends IFloodlightModule> DEFAULT_ENTITY_CLASSIFIER =
+			DefaultEntityClassifier.class;
+	public static final Class<? extends IFloodlightModule> DEFAULT_PERFMON =
+			NullPktInProcessingTime.class;
+	
+	protected static final Collection<Class<? extends IFloodlightModule>> DEFAULT_MODULE_LIST;
+	
+	static {
+		DEFAULT_MODULE_LIST = new ArrayList<Class<? extends IFloodlightModule>>();
+		DEFAULT_MODULE_LIST.add(DEFAULT_DEVICE_SERVICE);
+		DEFAULT_MODULE_LIST.add(DEFAULT_FLOODLIGHT_PRPOVIDER);
+		DEFAULT_MODULE_LIST.add(DEFAULT_STORAGE_SOURCE);
+		DEFAULT_MODULE_LIST.add(DEFAULT_TOPOLOGY_PROVIDER);
+		DEFAULT_MODULE_LIST.add(DEFAULT_COUNTER_STORE);
+		DEFAULT_MODULE_LIST.add(DEFAULT_THREADPOOL);
+		DEFAULT_MODULE_LIST.add(DEFAULT_ENTITY_CLASSIFIER);
+		DEFAULT_MODULE_LIST.add(DEFAULT_PERFMON);
+	}
+	
+	protected IFloodlightModuleContext fmc;
+	
+	/**
+	 * Adds default modules to the list of modules to load. This is done
+	 * in order to avoid the module loader throwing errors about duplicate
+	 * modules and neither one is specified by the user.
+	 * @param userModules The list of user specified modules to add to.
+	 */
+	protected void addDefaultModules(Collection<Class<? extends IFloodlightModule>> userModules) {
+		Collection<Class<? extends IFloodlightModule>> defaultModules =
+				new ArrayList<Class<? extends IFloodlightModule>>(DEFAULT_MODULE_LIST.size());
+		defaultModules.addAll(DEFAULT_MODULE_LIST);
+		
+		Iterator<Class<? extends IFloodlightModule>> modIter = userModules.iterator();
+		while (modIter.hasNext()) {
+			Class<? extends IFloodlightModule> userMod = modIter.next();
+			Iterator<Class<? extends IFloodlightModule>> dmIter = defaultModules.iterator();
+			while (dmIter.hasNext()) {
+				Class<? extends IFloodlightModule> dmMod = dmIter.next();
+				Collection<Class<? extends IFloodlightService>> userModServs;
+				Collection<Class<? extends IFloodlightService>> dmModServs;
+				try {
+					dmModServs = dmMod.newInstance().getModuleServices();
+					userModServs = userMod.newInstance().getModuleServices();
+				} catch (InstantiationException e) {
+					log.error(e.getMessage());
+					break;
+				} catch (IllegalAccessException e) {
+					log.error(e.getMessage());
+					break;
+				}
+				
+				// If either of these are null continue as they have no services
+				if (dmModServs == null || userModServs == null) continue;
+				
+				// If the user supplied modules has a service
+				// that is in the default module list we remove
+				// the default module from the list.
+				boolean shouldBreak = false;
+				Iterator<Class<? extends IFloodlightService>> userModServsIter 
+					= userModServs.iterator();
+				while (userModServsIter.hasNext()) {
+					Class<? extends IFloodlightService> userModServIntf = userModServsIter.next();
+					Iterator<Class<? extends IFloodlightService>> dmModsServsIter 
+						= dmModServs.iterator();
+					while (dmModsServsIter.hasNext()) {
+						Class<? extends IFloodlightService> dmModServIntf 
+							= dmModsServsIter.next();
+						
+						if (dmModServIntf.getCanonicalName().equals(
+								userModServIntf.getCanonicalName())) {
+							logger.debug("Removing default module {} because it was " +
+									"overriden by an explicitly specified module",
+									dmModServIntf.getCanonicalName());
+							dmIter.remove();
+							shouldBreak = true;
+							break;
+						}
+					}
+					if (shouldBreak) break;
+				}
+				if (shouldBreak) break;
+			}
+		}
+		
+		// Append the remaining default modules to the user specified ones.
+		// This avoids the module loader throwing duplicate module errors.
+		userModules.addAll(defaultModules);
+		log.debug("Using module set " + userModules.toString());
+	}
+	
+	/**
+	 * Sets up all modules and their dependencies.
+	 * @param modules The list of modules that the user wants to load.
+	 * @param mockedServices The list of services that will be mocked. Any
+	 * module that provides this service will not be loaded.
+	 */
+	public void setupModules(Collection<Class<? extends IFloodlightModule>> modules,
+			Collection<IFloodlightService> mockedServices) {
+		addDefaultModules(modules);
+		Collection<String> modulesAsString = new ArrayList<String>();
+		for (Class<? extends IFloodlightModule> m : modules) {
+			modulesAsString.add(m.getCanonicalName());
+		}
+		
+		try {
+			fmc = loadModulesFromList(modulesAsString, null, mockedServices);
+		} catch (FloodlightModuleException e) {
+			log.error(e.getMessage());
+		}
+	}
+	
+	/**
+	 * Gets the inited/started instance of a module from the context.
+	 * @param ifl The name if the module to get, i.e. "LearningSwitch.class".
+	 * @return The inited/started instance of the module.
+	 */
+	public IFloodlightModule getModuleByName(Class<? extends IFloodlightModule> ifl) {
+		Collection<IFloodlightModule> modules = fmc.getAllModules();
+		for (IFloodlightModule m : modules) {
+			if (ifl.getCanonicalName().equals(m.getClass().getCanonicalName())) {
+				return m;
+			}
+		}
+		return null;
+	}
+	
+	/**
+	 * Gets an inited/started instance of a service from the context.
+	 * @param ifs The name of the service to get, i.e. "ITopologyService.class".
+	 * @return The inited/started instance of the service from teh context.
+	 */
+	public IFloodlightService getModuleByService(Class<? extends IFloodlightService> ifs) {
+		Collection<IFloodlightModule> modules = fmc.getAllModules();
+		for (IFloodlightModule m : modules) {
+			Collection<Class<? extends IFloodlightService>> mServs = m.getModuleServices();
+			if (mServs == null) continue;
+			for (Class<? extends IFloodlightService> mServClass : mServs) {
+				if (mServClass.getCanonicalName().equals(ifs.getCanonicalName())) {
+					assert(m instanceof IFloodlightService);
+					return (IFloodlightService)m;
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
index 577e5ded581e9326e9d30fd452e4fbb73c8b2ba9..3daa04f5248c19190a68658746051134651ac0a8 100644
--- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
+++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java
@@ -19,6 +19,7 @@ package net.floodlightcontroller.core.test;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -199,28 +200,31 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro
 
     @Override
     public Collection<Class<? extends IFloodlightService>> getModuleServices() {
-        // TODO Auto-generated method stub
-        return null;
+    	Collection<Class<? extends IFloodlightService>> services =
+                new ArrayList<Class<? extends IFloodlightService>>(1);
+        services.add(IFloodlightProviderService.class);
+        return services;
     }
 
     @Override
     public Map<Class<? extends IFloodlightService>, IFloodlightService>
             getServiceImpls() {
-        // TODO Auto-generated method stub
-        return null;
+    	Map<Class<? extends IFloodlightService>,
+        	IFloodlightService> m = 
+            	new HashMap<Class<? extends IFloodlightService>,
+                        IFloodlightService>();
+    	m.put(IFloodlightProviderService.class, this);
+    	return m;
     }
 
     @Override
     public Collection<Class<? extends IFloodlightService>>
             getModuleDependencies() {
-        // TODO Auto-generated method stub
-        return null;
+    	return null;
     }
     
     @Override
-    public
-            void
-            init(FloodlightModuleContext context)
+    public void init(FloodlightModuleContext context)
                                                  throws FloodlightModuleException {
         // TODO Auto-generated method stub
         
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index 2efcd4cf6b4bedad26da9908a8d3a3ef63a77269..5626a543ace242a99ee027b68d375d664930a58b 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -19,13 +19,17 @@ package net.floodlightcontroller.devicemanager.internal;
 
 
 import static org.easymock.EasyMock.*;
+
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.Date;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import static org.easymock.EasyMock.expectLastCall;
 import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -779,12 +783,12 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         assertEquals(device, rdevice);
     }
 
+    
     /**
      * Note: Entity expiration does not result in device moved notification.
      * @throws Exception
      */
-    @Test
-    public void testEntityExpiration() throws Exception {
+    public void doTestEntityExpiration() throws Exception {
         IDeviceListener mockListener =
                 createStrictMock(IDeviceListener.class);
         mockListener.deviceIPV4AddrChanged(isA(IDevice.class));
@@ -854,8 +858,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         verify(mockListener);
     }
 
-    @Test
-    public void testDeviceExpiration() throws Exception {
+    public void doTestDeviceExpiration() throws Exception {
         Calendar c = Calendar.getInstance();
         c.add(Calendar.MILLISECOND, -DeviceManagerImpl.ENTITY_TIMEOUT-1);
         Entity entity1 = new Entity(1L, null, 1, 1L, 1, c.getTime());
@@ -895,7 +898,104 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
         r = deviceManager.findDevice(1L, null, null, null, null);
         assertNull(r);
     }
-
+    
+    /*
+     * A ConcurrentHashMap for devices (deviceMap) that can be used to test 
+     * code that specially handles concurrent modification situations. In
+     * particular, we overwrite values() and will replace / remove all the
+     * elements returned by values. 
+     * 
+     * The remove flag in the constructor specifies if devices returned by 
+     * values() should be removed or replaced.
+     */
+    protected static class ConcurrentlyModifiedDeviceMap
+                            extends ConcurrentHashMap<Long, Device> {
+        private static final long serialVersionUID = 7784938535441180562L;
+        protected boolean remove;
+        public ConcurrentlyModifiedDeviceMap(boolean remove) {
+            super();
+            this.remove = remove;
+        }
+        
+        @Override
+        public Collection<Device> values() {
+            // Get the values from the real map and copy them since
+            // the collection returned by values can reflect changed
+            Collection<Device> devs = new ArrayList<Device>(super.values());
+            for (Device d: devs) {
+                if (remove) {
+                    // We remove the device from the underlying map 
+                    super.remove(d.getDeviceKey());
+                } else {
+                    super.remove(d.getDeviceKey());
+                    // We add a different Device instance with the same
+                    // key to the map. We'll do some hackery so the device
+                    // is different enough to compare differently in equals 
+                    // but otherwise looks the same.
+                    // It's ugly but it works. 
+                    Entity[] curEntities = new Entity[d.getEntities().length];
+                    int i = 0;
+                    // clone entities
+                    for (Entity e: d.getEntities()) {
+                        curEntities[i] = new Entity (e.macAddress,
+                                                     e.vlan,
+                                                     e.ipv4Address,
+                                                     e.switchDPID,
+                                                     e.switchPort,
+                                                     e.lastSeenTimestamp);
+                        if (e.vlan == null) 
+                            curEntities[i].vlan = (short)1;
+                        else 
+                            curEntities[i].vlan = (short)((e.vlan + 1 % 4095)+1);
+                        i++;
+                    }
+                    Device newDevice = new Device(d, curEntities[0]);
+                    newDevice.entities = curEntities;
+                    assertEquals(false, newDevice.equals(d));
+                    super.put(newDevice.getDeviceKey(), newDevice);
+                }
+            }
+            return devs; 
+        }
+    }
+   
+    @Test
+    public void testEntityExpiration() throws Exception {
+        doTestEntityExpiration();
+    }
+    
+    @Test
+    public void testDeviceExpiration() throws Exception {
+        doTestDeviceExpiration();
+    }
+    
+    /* Test correct entity cleanup behavior when a concurrent modification
+     * occurs. 
+     */
+    @Test
+    public void testEntityExpirationConcurrentModification() throws Exception {
+        deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(false);
+        doTestEntityExpiration();
+    }
+    
+    /* Test correct entity cleanup behavior when a concurrent remove
+     * occurs. 
+     */
+    @Test
+    public void testDeviceExpirationConcurrentRemove() throws Exception {
+        deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(true);
+        doTestDeviceExpiration();
+    }
+    
+    /* Test correct entity cleanup behavior when a concurrent modification
+     * occurs. 
+     */
+    @Test
+    public void testDeviceExpirationConcurrentModification() throws Exception {
+        deviceManager.deviceMap = new ConcurrentlyModifiedDeviceMap(false);
+        doTestDeviceExpiration();
+    }
+    
     /*
     @Test
     public void testAttachmentPointFlapping() throws Exception {
diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
index 2f952254c310c2216a489d0b9d606311e4b8b60f..9da4359cf8a34aa4f771e72ec433364a1169003b 100644
--- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
+++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
@@ -97,10 +97,30 @@ public class ForwardingTest extends FloodlightTestCase {
     public void setUp() throws Exception {
         super.setUp();
 
-        // Mock context
         cntx = new FloodlightContext();
+        
+        // Module loader setup
+        /*
+        Collection<Class<? extends IFloodlightModule>> mods = new ArrayList<Class<? extends IFloodlightModule>>();
+        Collection<IFloodlightService> mockedServices = new ArrayList<IFloodlightService>();
+        mods.add(Forwarding.class);
+        routingEngine = createMock(IRoutingService.class);
+        topology = createMock(ITopologyService.class);
+        mockedServices.add(routingEngine);
+        mockedServices.add(topology);
+        FloodlightTestModuleLoader fml = new FloodlightTestModuleLoader();
+        fml.setupModules(mods, mockedServices);
+        mockFloodlightProvider =
+        		(MockFloodlightProvider) fml.getModuleByName(MockFloodlightProvider.class);
+        deviceManager =
+        		(MockDeviceManager) fml.getModuleByName(MockDeviceManager.class);
+        threadPool =
+        		(MockThreadPoolService) fml.getModuleByName(MockThreadPoolService.class);
+        forwarding =
+        		(Forwarding) fml.getModuleByName(Forwarding.class);
+        */
         mockFloodlightProvider = getMockFloodlightProvider();
-        forwarding = getForwarding();
+        forwarding = new Forwarding();
         threadPool = new MockThreadPoolService();
         deviceManager = new MockDeviceManager();
         flowReconcileMgr = new FlowReconcileManager();
@@ -251,10 +271,6 @@ public class ForwardingTest extends FloodlightTestCase {
                 srcDevice);
     }
 
-    private Forwarding getForwarding() {
-        return new Forwarding();
-    }
-
     @Test
     public void testForwardMultiSwitchPath() throws Exception {
         
diff --git a/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java b/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java
index 0272de2dac25cb6f6cd6839522d692f023201ae2..a68a1b8734fca292dddedb3121d76ef64b7fe346 100644
--- a/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java
+++ b/src/test/java/net/floodlightcontroller/learningswitch/LearningSwitchTest.java
@@ -22,21 +22,20 @@ import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 
-import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.module.FloodlightModuleContext;
-import net.floodlightcontroller.counter.CounterStore;
-import net.floodlightcontroller.counter.ICounterStoreService;
+import net.floodlightcontroller.core.module.FloodlightTestModuleLoader;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.test.MockFloodlightProvider;
 import net.floodlightcontroller.packet.Data;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
 import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.packet.UDP;
-import net.floodlightcontroller.restserver.IRestApiService;
-import net.floodlightcontroller.restserver.RestApiServer;
 import net.floodlightcontroller.test.FloodlightTestCase;
 
 import org.junit.Before;
@@ -69,18 +68,15 @@ public class LearningSwitchTest extends FloodlightTestCase {
     @Before
     public void setUp() throws Exception {
         super.setUp();
-
-        FloodlightModuleContext fmc = new FloodlightModuleContext();
-        fmc.addService(IFloodlightProviderService.class, getMockFloodlightProvider());
-        fmc.addService(ICounterStoreService.class, new CounterStore());
-        RestApiServer restApi = new RestApiServer();
-        fmc.addService(IRestApiService.class, restApi);
-        restApi.init(fmc);
-        restApi.startUp(fmc);
-        learningSwitch = new LearningSwitch();
-        learningSwitch.init(fmc);
-        learningSwitch.startUp(fmc);
-        
+        FloodlightTestModuleLoader fml = new FloodlightTestModuleLoader();
+        Collection<Class<? extends IFloodlightModule>> mods 
+        	= new ArrayList<Class<? extends IFloodlightModule>>();
+        mods.add(LearningSwitch.class);
+        fml.setupModules(mods, null);
+        learningSwitch = (LearningSwitch) fml.getModuleByName(LearningSwitch.class);
+        mockFloodlightProvider = 
+        		(MockFloodlightProvider) fml.getModuleByName(MockFloodlightProvider.class);
+       
         // Build our test packet
         this.testPacket = new Ethernet()
             .setDestinationMACAddress("00:11:22:33:44:55")
@@ -153,7 +149,7 @@ public class LearningSwitchTest extends FloodlightTestCase {
 
         // Mock up our expected behavior
         IOFSwitch mockSwitch = createMock(IOFSwitch.class);
-        expect(mockSwitch.getStringId()).andReturn("00:11:22:33:44:55:66:77");
+        expect(mockSwitch.getStringId()).andReturn("00:11:22:33:44:55:66:77").anyTimes();
         mockSwitch.write(po, null);
 
         // Start recording the replay on the mocks
@@ -161,6 +157,7 @@ public class LearningSwitchTest extends FloodlightTestCase {
         // Get the listener and trigger the packet in
         IOFMessageListener listener = mockFloodlightProvider.getListeners().get(
                 OFType.PACKET_IN).get(0);
+        // Make sure it's the right listener
         listener.receive(mockSwitch, this.packetIn, parseAndAnnotate(this.packetIn));
 
         // Verify the replay matched our expectations      
@@ -214,7 +211,6 @@ public class LearningSwitchTest extends FloodlightTestCase {
         expect(mockSwitch.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn((Integer) (OFMatch.OFPFW_IN_PORT | OFMatch.OFPFW_NW_PROTO
                 | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST | OFMatch.OFPFW_NW_SRC_ALL
                 | OFMatch.OFPFW_NW_DST_ALL | OFMatch.OFPFW_NW_TOS));
-        expect(mockSwitch.getStringId()).andReturn("00:11:22:33:44:55:66:77").anyTimes();
         mockSwitch.write(fm1, null);
         mockSwitch.write(fm2, null);
 
diff --git a/src/test/java/net/floodlightcontroller/packet/DHCPTest.java b/src/test/java/net/floodlightcontroller/packet/DHCPTest.java
index 1f3a48585bcfa2b949dec07570ae25e71d912949..b83ffa816e196873b00158426a0177347c92905a 100644
--- a/src/test/java/net/floodlightcontroller/packet/DHCPTest.java
+++ b/src/test/java/net/floodlightcontroller/packet/DHCPTest.java
@@ -216,7 +216,71 @@ public class DHCPTest extends TestCase {
             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
             (byte) 0x00, (byte) 0x00, (byte) 0x00 };
-
+    
+    public byte[] dhcpPacket3 = new byte[] { 
+            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+            (byte) 0xff, (byte) 0x74, (byte) 0x44, (byte) 0x01, (byte) 0x72, 
+            (byte) 0xd8, (byte) 0x41, (byte) 0x08, (byte) 0x00, (byte) 0x45, 
+            (byte) 0x00, (byte) 0x01, (byte) 0x1f, (byte) 0x48, (byte) 0xcd, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x11, (byte) 0x6f, 
+            (byte) 0x6a, (byte) 0xc0, (byte) 0xa8, (byte) 0x00, (byte) 0xef, 
+            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, 
+            (byte) 0x44, (byte) 0x00, (byte) 0x43, (byte) 0x01, (byte) 0x0b, 
+            (byte) 0xb3, (byte) 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0x06, 
+            (byte) 0x00, (byte) 0x82, (byte) 0x88, (byte) 0xa6, (byte) 0xc9, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x74, (byte) 0x44, (byte) 0x01, (byte) 0x72, (byte) 0xd8, 
+            (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x63, (byte) 0x82, 
+            (byte) 0x53, (byte) 0x63, (byte) 0x35, (byte) 0x01, (byte) 0x01, 
+            (byte) 0x32, (byte) 0x04, (byte) 0xc0, (byte) 0xa8, (byte) 0x0a, 
+            (byte) 0xa9, (byte) 0x39, (byte) 0x02, (byte) 0x02, (byte) 0x40, 
+            (byte) 0x37, (byte) 0x03, (byte) 0x01, (byte) 0x03, (byte) 0x06, 
+            (byte) 0xff                               
+    };
+    
     public byte[] dhcpPacketPXE = new byte[] { (byte) 0xff, (byte) 0xff,
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00,
             (byte) 0x19, (byte) 0xb9, (byte) 0xb0, (byte) 0x01, (byte) 0x44,
@@ -444,6 +508,24 @@ public class DHCPTest extends TestCase {
         resetChecksumsAndLengths(ipv4, udp);
         assertEquals(DHCP.OPCODE_REQUEST, dhcp.getOpCode());
     }
+    
+    public void testDeSerializeReSerialize() {
+        Ethernet eth = new Ethernet();
+        eth.deserialize(dhcpPacket3, 0, dhcpPacket3.length);
+        assertTrue(eth.getPayload() instanceof IPv4);
+        IPv4 ipv4 = (IPv4) eth.getPayload();
+        assertTrue(ipv4.getPayload() instanceof UDP);
+        
+        byte[] serializedPacket = eth.serialize();
+        Ethernet eth2 = new Ethernet();
+        eth2.deserialize(serializedPacket, 0, serializedPacket.length);
+        IPv4 ipv42 = (IPv4) eth2.getPayload();
+
+        short ipchecksum = ipv42.getChecksum();
+        ipv42.setChecksum((short) 0);
+        eth2.serialize();        
+        assertEquals(ipchecksum, ipv42.getChecksum());
+    }
 
     public void testDeSerializePXE() {
         Ethernet eth = new Ethernet();
diff --git a/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java b/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java
index 550cd1f520dc5f6ee6b8b9816adbfba07c7d501e..b0e83cc115fbc7293be6ec70dae7a78dbd325a3e 100644
--- a/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java
+++ b/src/test/java/net/floodlightcontroller/test/FloodlightTestCase.java
@@ -87,9 +87,9 @@ public class FloodlightTestCase extends TestCase {
     public void setUp() throws Exception {
         mockFloodlightProvider = new MockFloodlightProvider();
     }
-
+    
     @Test
-    public void testSanity() {
-        assertTrue(true);
+    public void testSanity() throws Exception {
+    	assertTrue(true);
     }
 }