Merge pull request #3 from y-higuchi/RAMCloud-yoshi

merge latest
diff --git a/conf/checkstyle/sun_checks.xml b/conf/checkstyle/sun_checks.xml
new file mode 100644
index 0000000..51a7f8c
--- /dev/null
+++ b/conf/checkstyle/sun_checks.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0"?>

+<!DOCTYPE module PUBLIC

+          "-//Puppy Crawl//DTD Check Configuration 1.3//EN"

+          "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">

+

+<!--

+

+  Checkstyle configuration that checks the sun coding conventions from:

+

+    - the Java Language Specification at

+      http://java.sun.com/docs/books/jls/second_edition/html/index.html

+

+    - the Sun Code Conventions at http://java.sun.com/docs/codeconv/

+

+    - the Javadoc guidelines at

+      http://java.sun.com/j2se/javadoc/writingdoccomments/index.html

+

+    - the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html

+

+    - some best practices

+

+  Checkstyle is very configurable. Be sure to read the documentation at

+  http://checkstyle.sf.net (or in your downloaded distribution).

+

+  Most Checks are configurable, be sure to consult the documentation.

+

+  To completely disable a check, just comment it out or delete it from the file.

+

+  Finally, it is worth reading the documentation.

+

+-->

+

+<module name="Checker">

+    <!--

+        If you set the basedir property below, then all reported file

+        names will be relative to the specified directory. See

+        http://checkstyle.sourceforge.net/5.x/config.html#Checker

+

+        <property name="basedir" value="${basedir}"/>

+    -->

+

+    <!-- Checks that a package-info.java file exists for each package.     -->

+    <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage -->

+    <module name="JavadocPackage"/>

+

+    <!-- Checks whether files end with a new line.                        -->

+    <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->

+    <module name="NewlineAtEndOfFile"/>

+

+    <!-- Checks that property files contain the same keys.         -->

+    <!-- See http://checkstyle.sf.net/config_misc.html#Translation -->

+    <module name="Translation"/>

+    

+    <!-- Checks for Size Violations.                    -->

+    <!-- See http://checkstyle.sf.net/config_sizes.html -->

+    <module name="FileLength"/>

+    

+    <!-- Checks for whitespace                               -->

+    <!-- See http://checkstyle.sf.net/config_whitespace.html -->

+    <module name="FileTabCharacter"/>

+

+    <!-- Miscellaneous other checks.                   -->

+    <!-- See http://checkstyle.sf.net/config_misc.html -->

+    <module name="RegexpSingleline">

+       <property name="format" value="\s+$"/>

+       <property name="minimum" value="0"/>

+       <property name="maximum" value="0"/>

+       <property name="message" value="Line has trailing spaces."/>

+    </module>

+

+    <!-- Checks for Headers                                -->

+    <!-- See http://checkstyle.sf.net/config_header.html   -->

+    <!-- <module name="Header"> -->

+    <!--   <property name="headerFile" value="${checkstyle.header.file}"/> -->

+    <!--   <property name="fileExtensions" value="java"/> -->

+    <!-- </module> -->

+

+    <module name="TreeWalker">

+

+        <!-- Checks for Javadoc comments.                     -->

+        <!-- See http://checkstyle.sf.net/config_javadoc.html -->

+        <module name="JavadocMethod"/>

+        <module name="JavadocType"/>

+        <module name="JavadocVariable"/>

+        <module name="JavadocStyle"/>

+

+

+        <!-- Checks for Naming Conventions.                  -->

+        <!-- See http://checkstyle.sf.net/config_naming.html -->

+        <module name="ConstantName"/>

+        <module name="LocalFinalVariableName"/>

+        <module name="LocalVariableName"/>

+        <module name="MemberName"/>

+        <module name="MethodName"/>

+        <module name="PackageName"/>

+        <module name="ParameterName"/>

+        <module name="StaticVariableName"/>

+        <module name="TypeName"/>

+

+

+        <!-- Checks for imports                              -->

+        <!-- See http://checkstyle.sf.net/config_import.html -->

+        <module name="AvoidStarImport"/>

+        <module name="IllegalImport"/> <!-- defaults to sun.* packages -->

+        <module name="RedundantImport"/>

+        <module name="UnusedImports"/>

+

+

+        <!-- Checks for Size Violations.                    -->

+        <!-- See http://checkstyle.sf.net/config_sizes.html -->

+        <module name="LineLength"/>

+        <module name="MethodLength"/>

+        <module name="ParameterNumber"/>

+

+

+        <!-- Checks for whitespace                               -->

+        <!-- See http://checkstyle.sf.net/config_whitespace.html -->

+        <module name="EmptyForIteratorPad"/>

+        <module name="GenericWhitespace"/>

+        <module name="MethodParamPad"/>

+        <module name="NoWhitespaceAfter"/>

+        <module name="NoWhitespaceBefore"/>

+        <module name="OperatorWrap"/>

+        <module name="ParenPad"/>

+        <module name="TypecastParenPad"/>

+        <module name="WhitespaceAfter"/>

+        <module name="WhitespaceAround"/>

+

+

+        <!-- Modifier Checks                                    -->

+        <!-- See http://checkstyle.sf.net/config_modifiers.html -->

+        <module name="ModifierOrder"/>

+        <module name="RedundantModifier"/>

+

+

+        <!-- Checks for blocks. You know, those {}'s         -->

+        <!-- See http://checkstyle.sf.net/config_blocks.html -->

+        <module name="AvoidNestedBlocks"/>

+        <module name="EmptyBlock"/>

+        <module name="LeftCurly"/>

+        <module name="NeedBraces"/>

+        <module name="RightCurly"/>

+

+

+        <!-- Checks for common coding problems               -->

+        <!-- See http://checkstyle.sf.net/config_coding.html -->

+        <module name="AvoidInlineConditionals"/>

+        <module name="EmptyStatement"/>

+        <module name="EqualsHashCode"/>

+        <module name="HiddenField"/>

+        <module name="IllegalInstantiation"/>

+        <module name="InnerAssignment"/>

+        <module name="MagicNumber"/>

+        <module name="MissingSwitchDefault"/>

+        <module name="RedundantThrows"/>

+        <module name="SimplifyBooleanExpression"/>

+        <module name="SimplifyBooleanReturn"/>

+

+        <!-- Checks for class design                         -->

+        <!-- See http://checkstyle.sf.net/config_design.html -->

+        <module name="DesignForExtension"/>

+        <module name="FinalClass"/>

+        <module name="HideUtilityClassConstructor"/>

+        <module name="InterfaceIsType"/>

+        <module name="VisibilityModifier"/>

+

+

+        <!-- Miscellaneous other checks.                   -->

+        <!-- See http://checkstyle.sf.net/config_misc.html -->

+        <module name="ArrayTypeStyle"/>

+        <module name="FinalParameters"/>

+        <module name="TodoComment"/>

+        <module name="UpperEll"/>

+

+    </module>

+

+</module>

diff --git a/conf/onos-embedded.properties b/conf/onos-embedded.properties
index 8ae143e..dddacdb 100644
--- a/conf/onos-embedded.properties
+++ b/conf/onos-embedded.properties
@@ -1,7 +1,6 @@
 floodlight.modules = net.floodlightcontroller.core.FloodlightProvider,\
 net.floodlightcontroller.threadpool.ThreadPool,\
 net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher, \
-net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
 net.floodlightcontroller.ui.web.StaticWebRoutable,\
 net.onrc.onos.datagrid.HazelcastDatagrid,\
 net.onrc.onos.ofcontroller.flowmanager.FlowManager,\
diff --git a/conf/onos.properties b/conf/onos.properties
index ec04622..f1244df 100644
--- a/conf/onos.properties
+++ b/conf/onos.properties
@@ -1,7 +1,6 @@
 floodlight.modules = net.floodlightcontroller.core.FloodlightProvider,\
 net.floodlightcontroller.threadpool.ThreadPool,\
 net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher, \
-net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
 net.floodlightcontroller.ui.web.StaticWebRoutable,\
 net.onrc.onos.datagrid.HazelcastDatagrid,\
 net.onrc.onos.ofcontroller.flowmanager.FlowManager,\
diff --git a/perf-scripts/flow-sync-perf.py b/perf-scripts/flow-sync-perf.py
index f0af050..b782333 100755
--- a/perf-scripts/flow-sync-perf.py
+++ b/perf-scripts/flow-sync-perf.py
@@ -203,7 +203,7 @@
   setLogLevel( 'output' )
   resultDir = strftime( '%Y%m%d-%H%M%S' )
   os.mkdir( resultDir )
-  tests = sys.argv[1:]
+  tests = map(int, sys.argv[1:])
   if not tests:
     tests = [1, 10, 100, 1000, 10000]
   runPerf( resultDir, tests )
diff --git a/pom.xml b/pom.xml
index af6c709..87816b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,11 +32,20 @@
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <powermock.version>1.5.1</powermock.version>
     <restlet.version>2.1.4</restlet.version>
-    <github.global.server>github</github.global.server>
+    <!-- <github.global.server>github</github.global.server> -->
   </properties>
   <build>
     <plugins>
       <plugin>
+	<!-- Note: the checkstyle configuration is also in the reporting section -->
+	<groupId>org.apache.maven.plugins</groupId>
+	<artifactId>maven-checkstyle-plugin</artifactId>
+	<version>2.11</version>
+	<configuration>
+	  <configLocation>conf/checkstyle/sun_checks.xml</configLocation>
+	</configuration>
+      </plugin>
+      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-install-plugin</artifactId>
         <version>2.3.1</version>
@@ -145,6 +154,7 @@
           </execution>
         </executions>
       </plugin>
+      <!--
       <plugin>
         <groupId>com.github.github</groupId>
         <artifactId>site-maven-plugin</artifactId>
@@ -164,6 +174,7 @@
           </execution>
         </executions>
       </plugin>
+      -->
       <plugin>
 	<artifactId>maven-assembly-plugin</artifactId>
 	<configuration>
@@ -213,6 +224,27 @@
           <locale>en</locale>
         </configuration>
       </plugin>
+      <plugin>
+	<!-- Note: the checkstyle configuration is also in the build section -->
+	<groupId>org.apache.maven.plugins</groupId>
+	<artifactId>maven-checkstyle-plugin</artifactId>
+	<version>2.11</version>
+	<configuration>
+	  <configLocation>conf/checkstyle/sun_checks.xml</configLocation>
+	</configuration>
+	<reportSets>
+	  <reportSet>
+	    <reports>
+	      <report>checkstyle</report>
+	    </reports>
+	  </reportSet>
+	</reportSets>
+      </plugin>
+      <plugin>
+	<groupId>org.apache.maven.plugins</groupId>
+	<artifactId>maven-jxr-plugin</artifactId>
+	<version>2.3</version>
+    </plugin>
     </plugins>
   </reporting>
   <dependencies>
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 39bdf3c..42fb3c6 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -61,6 +61,7 @@
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.onrc.onos.ofcontroller.core.IOFSwitchPortListener;
+import net.onrc.onos.ofcontroller.core.web.OnosInternalWebRoutable;
 import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.onrc.onos.registry.controller.IControllerRegistryService;
 import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
@@ -1831,6 +1832,7 @@
        
         // Add our REST API
         restApi.addRestletRoutable(new CoreWebRoutable());
+        restApi.addRestletRoutable(new OnosInternalWebRoutable());
     }
     
     @Override
diff --git a/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java b/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java
index 9b22617..0e48975 100644
--- a/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java
@@ -19,10 +19,6 @@
 
 import net.floodlightcontroller.core.module.ModuleLoaderResource;
 import net.floodlightcontroller.restserver.RestletRoutable;
-import net.onrc.onos.ofcontroller.core.web.ClearFlowTableResource;
-import net.onrc.onos.ofcontroller.core.web.TopoLinksResource;
-import net.onrc.onos.ofcontroller.core.web.TopoSwitchesResource;
-import net.onrc.onos.ofcontroller.devicemanager.web.TopoDevicesResource;
 
 import org.restlet.Context;
 import org.restlet.Restlet;
@@ -35,7 +31,7 @@
 public class CoreWebRoutable implements RestletRoutable {
     @Override
     public String basePath() {
-        return "/wm/core";
+        return "/wm/floodlight/core";
     }
 
     @Override
@@ -57,11 +53,6 @@
                 EventHistoryTopologyClusterResource.class);
         router.attach("/health/json", HealthCheckResource.class);
         router.attach("/system/uptime/json", SystemUptimeResource.class);
-        // Following added by ONOS
-        router.attach("/topology/switches/{filter}/json", TopoSwitchesResource.class);
-        router.attach("/topology/links/json", TopoLinksResource.class);
-        router.attach("/topology/devices/json", TopoDevicesResource.class);
-        router.attach("/clearflowtable/json", ClearFlowTableResource.class);
         return router;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceRoutable.java b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceRoutable.java
index 9a76505..3648569 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceRoutable.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/web/DeviceRoutable.java
@@ -30,7 +30,7 @@
 
     @Override
     public String basePath() {
-        return "/wm/device";
+        return "/wm/floodlight/device";
     }
     
     @Override
diff --git a/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java b/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java
index 4f844b2..363a194 100644
--- a/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/topology/web/TopologyWebRoutable.java
@@ -4,8 +4,6 @@
 import org.restlet.routing.Router;
 
 import net.floodlightcontroller.restserver.RestletRoutable;
-import net.onrc.onos.ofcontroller.linkdiscovery.web.LinksResource;
-import net.onrc.onos.ofcontroller.topology.web.RouteResource;
 
 public class TopologyWebRoutable implements RestletRoutable {
     /**
@@ -14,13 +12,11 @@
     @Override
     public Router getRestlet(Context context) {
         Router router = new Router(context);
-        router.attach("/links/json", LinksResource.class);
         router.attach("/tunnellinks/json", TunnelLinksResource.class);
         router.attach("/switchclusters/json", SwitchClustersResource.class);
         router.attach("/broadcastdomainports/json", BroadcastDomainPortsResource.class);
         router.attach("/enabledports/json", EnabledPortsResource.class);
         router.attach("/blockedports/json", BlockedPortsResource.class);
-        router.attach("/route/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", RouteResource.class);
         return router;
     }
 
@@ -29,6 +25,6 @@
      */
     @Override
     public String basePath() {
-        return "/wm/topology";
+        return "/wm/floodlight/topology";
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/ui/web/StaticWebRoutable.java b/src/main/java/net/floodlightcontroller/ui/web/StaticWebRoutable.java
index c1d5b5f..e89f0be 100644
--- a/src/main/java/net/floodlightcontroller/ui/web/StaticWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/ui/web/StaticWebRoutable.java
@@ -64,7 +64,7 @@
 
 	@Override
 	public String basePath() {
-		return "/ui/";
+		return "/wm/floodlight/ui/";
 	}
 
 }
diff --git a/src/main/java/net/floodlightcontroller/util/MACAddress.java b/src/main/java/net/floodlightcontroller/util/MACAddress.java
index b143bda..fc144bb 100644
--- a/src/main/java/net/floodlightcontroller/util/MACAddress.java
+++ b/src/main/java/net/floodlightcontroller/util/MACAddress.java
@@ -8,6 +8,7 @@
 
 import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.openflow.util.HexString;
 
 /**
  * The class representing MAC address.
@@ -167,13 +168,6 @@
 
     @Override
     public String toString() {
-        StringBuilder builder = new StringBuilder();
-        for (byte b: address) {
-            if (builder.length() > 0) {
-                builder.append(":");
-            }
-            builder.append(String.format("%02X", b & 0xFF));
-        }
-        return builder.toString();
+    	return HexString.toHexString(address);
     }
 }
diff --git a/src/main/java/net/onrc/onos/datagrid/web/DatagridWebRoutable.java b/src/main/java/net/onrc/onos/datagrid/web/DatagridWebRoutable.java
index 2c99ece..1d3afe7 100644
--- a/src/main/java/net/onrc/onos/datagrid/web/DatagridWebRoutable.java
+++ b/src/main/java/net/onrc/onos/datagrid/web/DatagridWebRoutable.java
@@ -25,6 +25,6 @@
      */
     @Override
     public String basePath() {
-        return "/wm/datagrid";
+        return "/wm/onos/datagrid";
     }
 }
diff --git a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
index 0b5c9c6..ab775b9 100644
--- a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
+++ b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
@@ -44,8 +44,9 @@
 	 * Create a new switch and return the created switch object.
 	 * @param dpid DPID of the switch
 	 */
+	@Override
 	public ISwitchObject newSwitch(String dpid) {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		ISwitchObject obj = fg.addVertex(null,ISwitchObject.class);
 		if (obj != null) {
 			obj.setType("switch");
@@ -56,8 +57,9 @@
 
 	/**
 	 * Search and get a switch object with DPID.
-	 * @param dpid DPID of the switch 
+	 * @param dpid DPID of the switch
 	 */
+	@Override
 	public ISwitchObject searchSwitch(String dpid) {
 
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
@@ -69,10 +71,11 @@
 
 	/**
 	 * Search and get an active switch object with DPID.
-	 * @param dpid DPID of the switch 
+	 * @param dpid DPID of the switch
 	 */
+	@Override
 	public ISwitchObject searchActiveSwitch(String dpid) {
-	
+
 	    ISwitchObject sw = searchSwitch(dpid);
 	    if ((sw != null) &&
 	        sw.getState().equals(SwitchState.ACTIVE.toString())) {
@@ -84,6 +87,7 @@
 	/**
 	 * Get all switch objects.
 	 */
+	@Override
 	public Iterable<ISwitchObject> getAllSwitches() {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		Iterable<ISwitchObject> switches =  fg.getVertices("type","switch",ISwitchObject.class);
@@ -93,11 +97,12 @@
 	/**
 	 * Get all active switch objects.
 	 */
+	@Override
 	public Iterable<ISwitchObject> getActiveSwitches() {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		Iterable<ISwitchObject> switches =  fg.getVertices("type","switch",ISwitchObject.class);
 		List<ISwitchObject> activeSwitches = new ArrayList<ISwitchObject>();
-	
+
 		for (ISwitchObject sw: switches) {
 			if(sw.getState().equals(SwitchState.ACTIVE.toString())) {
 				activeSwitches.add(sw);
@@ -109,11 +114,12 @@
 	/**
 	 * Get all inactive switch objects.
 	 */
+	@Override
 	public Iterable<ISwitchObject> getInactiveSwitches() {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		Iterable<ISwitchObject> switches =  fg.getVertices("type","switch",ISwitchObject.class);
 		List<ISwitchObject> inactiveSwitches = new ArrayList<ISwitchObject>();
-	
+
 		for (ISwitchObject sw: switches) {
 			if(sw.getState().equals(SwitchState.INACTIVE.toString())) {
 				inactiveSwitches.add(sw);
@@ -125,6 +131,7 @@
 	/**
 	 * Get all flow entries' objects where their switches are not updated.
 	 */
+	@Override
 	public Iterable<IFlowEntry> getAllSwitchNotUpdatedFlowEntries() {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		//TODO: Should use an enum for flow_switch_state
@@ -135,14 +142,15 @@
 	 * Remove specified switch.
 	 * @param sw switch object to remove
 	 */
+	@Override
 	public void removeSwitch(ISwitchObject sw) {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
-		fg.removeVertex(sw.asVertex());		
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+		fg.removeVertex(sw.asVertex());
 	}
-	
+
 	@Override
 	public IPortObject newPort(String dpid, Short portNumber) {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		IPortObject obj = fg.addVertex(null,IPortObject.class);
 		if (obj != null) {
 			obj.setType("port");
@@ -150,17 +158,18 @@
 			obj.setPortId(id);
 			obj.setNumber(portNumber);
 		}
-		return obj;	
-		
+		return obj;
+
 	}
 
 	/**
 	 * Create a port having specified port number.
 	 * @param portNumber port number
 	 */
+	@Override
 	@Deprecated
 	public IPortObject newPort(Short portNumber) {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		IPortObject obj = fg.addVertex(null,IPortObject.class);
 		if (obj != null) {
 			obj.setType("port");
@@ -174,6 +183,7 @@
 	 * @param dpid DPID of a switch
 	 * @param number port number of the switch's port
 	 */
+	@Override
 	public IPortObject searchPort(String dpid, Short number) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		if ( fg == null ) return null;
@@ -190,17 +200,19 @@
 	 * Remove the specified switch port.
 	 * @param port switch port object to remove
 	 */
+	@Override
 	public void removePort(IPortObject port) {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 //		EventGraph<TitanGraph> eg = conn.getEventGraph();
-		if (fg != null) fg.removeVertex(port.asVertex());		
+		if (fg != null) fg.removeVertex(port.asVertex());
 	}
 
 	/**
 	 * Create and return a device object.
 	 */
+	@Override
 	public IDeviceObject newDevice() {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		IDeviceObject obj = fg.addVertex(null,IDeviceObject.class);
 		if (obj != null) obj.setType("device");
 		return obj;
@@ -210,6 +222,7 @@
 	 * Search and get a device object having specified MAC address.
 	 * @param macAddr MAC address to search and get
 	 */
+	@Override
 	public IDeviceObject searchDevice(String macAddr) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		if ( fg == null ) return null;
@@ -224,8 +237,9 @@
 	/**
 	 * Get all devices.
 	 */
+	@Override
 	public Iterable<IDeviceObject> getDevices() {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		return fg != null ? fg.getVertices("type","device",IDeviceObject.class) : null;
 	}
 
@@ -233,15 +247,16 @@
 	 * Remove the specified device.
 	 * @param dev a device object to remove
 	 */
+	@Override
 	public void removeDevice(IDeviceObject dev) {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
-		if (fg != null) fg.removeVertex(dev.asVertex());		
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+		if (fg != null) fg.removeVertex(dev.asVertex());
 	}
-	
+
 	public IIpv4Address newIpv4Address() {
 		return newVertex("ipv4Address", IIpv4Address.class);
 	}
-	
+
 	private <T extends IBaseObject> T newVertex(String type, Class<T> vertexType) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		T newVertex = fg.addVertex(null, vertexType);
@@ -250,15 +265,15 @@
 		}
 		return newVertex;
 	}
-	
+
 	public IIpv4Address searchIpv4Address(int intIpv4Address) {
 		return searchForVertex("ipv4_address", intIpv4Address, IIpv4Address.class);
 	}
-	
+
 	private <T> T searchForVertex(String propertyName, Object propertyValue, Class<T> vertexType) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		if (fg != null) {
-			Iterator<T> it = 
+			Iterator<T> it =
 					fg.getVertices(propertyName, propertyValue, vertexType).iterator();
 			if (it.hasNext()) {
 				return it.next();
@@ -266,7 +281,7 @@
 		}
 		return null;
 	}
-	
+
 	public IIpv4Address ensureIpv4Address(int intIpv4Address) {
 		IIpv4Address ipv4Vertex = searchIpv4Address(intIpv4Address);
 		if (ipv4Vertex == null) {
@@ -275,7 +290,7 @@
 		}
 		return ipv4Vertex;
 	}
-	
+
 	public void removeIpv4Address(IIpv4Address ipv4Address) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		fg.removeVertex(ipv4Address.asVertex());
@@ -284,8 +299,9 @@
 	/**
 	 * Create and return a flow path object.
 	 */
+	@Override
 	public IFlowPath newFlowPath() {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		IFlowPath flowPath = fg.addVertex(null, IFlowPath.class);
 		if (flowPath != null) flowPath.setType("flow");
 		return flowPath;
@@ -295,6 +311,7 @@
 	 * Search and get a flow path object with specified flow ID.
 	 * @param flowId flow ID to search
 	 */
+	@Override
 	public IFlowPath searchFlowPath(FlowId flowId) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		if ( fg == null ) return null;
@@ -310,21 +327,23 @@
 	 * Get a flow path object with a flow entry.
 	 * @param flowEntry flow entry object
 	 */
+	@Override
 	public IFlowPath getFlowPathByFlowEntry(IFlowEntry flowEntry) {
 		GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
 		pipe.start(flowEntry.asVertex()).out("flow");
 		FramedVertexIterable<IFlowPath> r = new FramedVertexIterable<IFlowPath>(conn.getFramedGraph(),
-				(Iterable<Vertex>) pipe, IFlowPath.class);
+				pipe, IFlowPath.class);
 		return r.iterator().hasNext() ? r.iterator().next() : null;
 	}
 
 	/**
 	 * Get all flow path objects.
 	 */
-    public Iterable<IFlowPath> getAllFlowPaths() {
+	@Override
+	public Iterable<IFlowPath> getAllFlowPaths() {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		Iterable<IFlowPath> flowPaths = fg.getVertices("type", "flow", IFlowPath.class);
-		
+
 		List<IFlowPath> nonNullFlows = new ArrayList<IFlowPath>();
 
 		for (IFlowPath fp: flowPaths) {
@@ -339,6 +358,7 @@
      * Remove the specified flow path.
      * @param flowPath flow path object to remove
      */
+	@Override
 	public void removeFlowPath(IFlowPath flowPath) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		fg.removeVertex(flowPath.asVertex());
@@ -347,8 +367,9 @@
 	/**
 	 * Create and return a flow entry object.
 	 */
+	@Override
 	public IFlowEntry newFlowEntry() {
-		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		IFlowEntry flowEntry = fg.addVertex(null, IFlowEntry.class);
 		if (flowEntry != null) flowEntry.setType("flow_entry");
 		return flowEntry;
@@ -358,6 +379,7 @@
 	 * Search and get a flow entry object with flow entry ID.
 	 * @param flowEntryId flow entry ID to search
 	 */
+	@Override
 	public IFlowEntry searchFlowEntry(FlowEntryId flowEntryId) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		if ( fg == null ) return null;
@@ -372,9 +394,10 @@
 	/**
 	 * Get all flow entry objects.
 	 */
+	@Override
 	public Iterable<IFlowEntry> getAllFlowEntries() {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
-		
+
 		return fg.getVertices("type", "flow_entry", IFlowEntry.class);
 	}
 
@@ -382,21 +405,24 @@
 	 * Remove the specified flow entry.
 	 * @param flowEntry flow entry object to remove
 	 */
+	@Override
 	public void removeFlowEntry(IFlowEntry flowEntry) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
 		fg.removeVertex(flowEntry.asVertex());
 	}
-	
+
 	/**
 	 * Get the instance of GraphDBConnection assigned to this class.
 	 */
+	@Override
 	public IDBConnection getDBConnection() {
 		return conn;
 	}
-	
+
 	/**
 	 * Commit changes for the graph.
 	 */
+	@Override
 	public void commit() {
 		conn.commit();
 	}
@@ -404,6 +430,7 @@
 	/**
 	 * Rollback changes for the graph.
 	 */
+	@Override
 	public void rollback() {
 		conn.rollback();
 	}
@@ -411,6 +438,7 @@
 	/**
 	 * Close the connection of the assigned GraphDBConnection.
 	 */
+	@Override
 	public void close() {
 		conn.close();
 	}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/web/TopoDevicesResource.java b/src/main/java/net/onrc/onos/graph/web/TopoDevicesResource.java
similarity index 90%
rename from src/main/java/net/onrc/onos/ofcontroller/devicemanager/web/TopoDevicesResource.java
rename to src/main/java/net/onrc/onos/graph/web/TopoDevicesResource.java
index 0d95e49..10e250e 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/web/TopoDevicesResource.java
+++ b/src/main/java/net/onrc/onos/graph/web/TopoDevicesResource.java
@@ -1,4 +1,4 @@
-package net.onrc.onos.ofcontroller.devicemanager.web;
+package net.onrc.onos.graph.web;
 
 import java.util.Iterator;
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java b/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java
index 13b9182..2eddadf 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java
@@ -2,6 +2,7 @@
 
 import net.floodlightcontroller.devicemanager.IDevice;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
+import net.onrc.onos.ofcontroller.devicemanager.OnosDevice;
 
 public interface IDeviceStorage extends INetMapStorage {
 	
@@ -12,5 +13,7 @@
 	public IDeviceObject getDeviceByMac(String mac);
 	public IDeviceObject getDeviceByIP(int ipv4Address);
 	public void changeDeviceAttachments(IDevice device);
-	public void changeDeviceIPv4Address(IDevice device);	
+	public void changeDeviceIPv4Address(IDevice device);
+	
+	public void addOnosDevice(OnosDevice onosDevice);
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
index a6203ba..65750e2 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
@@ -213,6 +213,7 @@
 		public void setIpv4Address(int ipv4Address);
 		
 		@JsonIgnore
+		//@GremlinGroovy("it.in('hasAddress')")
 		@Adjacency(label = "hasAddress", direction = Direction.IN)
 		public IDeviceObject getDevice();
 	}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
index 3eaf79d..e915614 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
@@ -2,6 +2,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 
 import net.floodlightcontroller.devicemanager.IDevice;
@@ -13,6 +14,8 @@
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IIpv4Address;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.onrc.onos.ofcontroller.devicemanager.OnosDevice;
 
 import org.openflow.util.HexString;
 import org.slf4j.Logger;
@@ -327,4 +330,102 @@
 			}
 		}
 	}
+	
+	/**
+	 * Takes an {@link OnosDevice} and adds it into the database. There is no
+	 * checking of the database data and removing old data - an 
+	 * {@link OnosDevice} basically corresponds to a packet we've just seen,
+	 * and we need to add that information into the database.
+	 */
+	@Override
+	public void addOnosDevice(OnosDevice onosDevice) {
+		String macAddress = HexString.toHexString(onosDevice.getMacAddress().toBytes());
+		
+		//if the switch port we try to attach a new device already has a link, then stop adding device
+		IPortObject portObject1 = ope.searchPort(HexString.toHexString(
+				onosDevice.getSwitchDPID()), onosDevice.getSwitchPort());
+
+		if (portObject1.getLinkedPorts().iterator().hasNext()) {
+			log.debug("stop adding OnosDevice: {} due to there is a link to: {}",
+					onosDevice, portObject1.getLinkedPorts().iterator().next().getPortId());
+			return;
+		}
+		
+		log.debug("addOnosDevice: {}", onosDevice);
+
+		try {
+			IDeviceObject device = ope.searchDevice(macAddress);
+			
+			if (device == null) {
+				device = ope.newDevice();
+				device.setType("device");
+				device.setState("ACTIVE");
+				device.setMACAddress(macAddress);
+			}
+			
+			// Check if the device has the IP address, add it if it doesn't
+			if (onosDevice.getIpv4Address() != null) {
+				boolean hasIpAddress = false;
+				for (IIpv4Address ipv4Address : device.getIpv4Addresses()) {
+					if (ipv4Address.getIpv4Address() == onosDevice.getIpv4Address().intValue()) {
+						hasIpAddress = true;
+						break;
+					}
+				}
+				
+				if (!hasIpAddress) {
+					IIpv4Address ipv4Address = ope.ensureIpv4Address(onosDevice.getIpv4Address().intValue());
+					IDeviceObject oldDevice = ipv4Address.getDevice();
+					if (oldDevice != null && oldDevice.getMACAddress() != macAddress) {
+						oldDevice.removeIpv4Address(ipv4Address);
+					}
+					device.addIpv4Address(ipv4Address);
+				}
+			}
+			
+			// Check if the device has the attachment point, add it if not
+			// TODO single attachment point for now, extend to multiple later
+			String switchDpid = HexString.toHexString(onosDevice.getSwitchDPID());
+			boolean hasAttachmentPoint = false;
+			Iterator<IPortObject> it = device.getAttachedPorts().iterator();
+			if (it.hasNext()) {
+				IPortObject existingPort = it.next();
+				if (existingPort != null) {
+					ISwitchObject existingSwitch = existingPort.getSwitch();
+					if (!existingSwitch.getDPID().equals(switchDpid) ||
+							existingPort.getNumber() != onosDevice.getSwitchPort()) {
+						existingPort.removeDevice(device);
+					}
+					else {
+						hasAttachmentPoint = true;
+					}
+				}
+			}
+			
+			/*
+			for (IPortObject portObject : device.getAttachedPorts()) {
+				ISwitchObject switchObject = portObject.getSwitch();
+				if (switchObject.getDPID().equals(switchDpid)
+						&& portObject.getNumber() == onosDevice.getSwitchPort()) {
+					hasAttachmentPoint = true;
+					break;
+				}
+			}
+			*/
+			
+			if (!hasAttachmentPoint) {
+				IPortObject portObject = ope.searchPort(switchDpid, onosDevice.getSwitchPort());
+				if (portObject != null) {
+					portObject.setDevice(device);
+				}
+			}
+			
+			ope.commit();
+		}
+		catch (TitanException e) {
+			log.error("addOnosDevice {} failed:", macAddress, e);
+			ope.rollback();
+		}
+	}
+
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
index 67b3ff0..bf6e2e9 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/LinkStorageImpl.java
@@ -6,6 +6,7 @@
 import net.floodlightcontroller.routing.Link;
 import net.onrc.onos.graph.DBOperation;
 import net.onrc.onos.ofcontroller.core.ILinkStorage;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.onrc.onos.ofcontroller.linkdiscovery.LinkInfo;
@@ -113,11 +114,28 @@
 		return addLink(link, null);
 	}
 
+	private void deleteDeviceOnPort(Long dpid, Short number)
+	{
+		IPortObject srcPortObject = op.searchPort(HexString.toHexString(dpid), number);
+		if (srcPortObject.getDevices().iterator().hasNext()) {
+			for (IDeviceObject deviceObject: srcPortObject.getDevices()) {
+				srcPortObject.removeDevice(deviceObject);
+				log.debug("delete Device "+ deviceObject.getMACAddress() +
+						" from sw: {} port: {} due to a new link added",
+						dpid, number);
+			}
+		}
+	}
+
 	@Override
 	public boolean addLink(Link link, LinkInfo linfo) {
 		boolean success = false;
 		
 		try {
+			//delete the Device attachment points for the related switch and port
+			deleteDeviceOnPort(link.getSrc(),link.getSrcPort());
+			deleteDeviceOnPort(link.getDst(),link.getDstPort());
+
 			if (addLinkImpl(link)) {
 				// Set LinkInfo only if linfo is non-null.
 				if (linfo != null && (! setLinkInfoImpl(link, linfo))) {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
index 1f7f783..cb535b2 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
@@ -26,12 +26,10 @@
 	protected DBOperation op;
 	protected final static Logger log = LoggerFactory.getLogger(SwitchStorageImpl.class);
 
-	/**
-	* *
-	* Initialize function. Before you use this class, please call this method
-	*
-	* @param conf configuration file for Cassandra DB
-	*/
+	/***
+	 * Initialize function. Before you use this class, please call this method
+	 * @param conf configuration file for Cassandra DB
+	 */
 	@Override
 	public void init(final String dbStore, final String conf) {
 		op = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
@@ -43,25 +41,26 @@
 	 * Finalize/close function. After you use this class, please call this method.
 	 * It will close the DB connection.
 	 */
+	@Override
 	public void finalize() {
 		close();
 	}
-	
+
 	/***
 	 * Finalize/close function. After you use this class, please call this method.
 	 * It will close the DB connection. This is for Java garbage collection.
 	 */
 	@Override
 	public void close() {
-		op.close();		
+		op.close();
 	}
-	
+
 	// Method designing policy:
 	//  op.commit() and op.rollback() MUST called in public (first-class) methods.
 	//  A first-class method MUST NOT call other first-class method.
 	//  Routine process should be implemented in private method.
 	//  A private method MUST NOT call commit or rollback.
-	
+
 	/***
 	 * This function is for updating the switch into the DB.
 	 * @param dpid The switch dpid you want to update from the DB
@@ -72,7 +71,7 @@
 	 * Jono, 11/8/2013
 	 * We don't need this update method that demultiplexes DM_OPERATIONS,
 	 * we can have clients just call the required methods directly.
-	 * We especially don't need this update method to re-implement 
+	 * We especially don't need this update method to re-implement
 	 * the functions of other methods.
 	 */
 	@Deprecated
@@ -80,7 +79,7 @@
 	public boolean updateSwitch(String dpid, SwitchState state, DM_OPERATION dmope) {
 		boolean success = false;
 		ISwitchObject sw = null;
-		
+
 		log.info("SwitchStorage:update {} dpid:{}", dmope, dpid);
 	    switch(dmope) {
 	    	case UPDATE:
@@ -130,33 +129,33 @@
 	            break;
 	    	default:
 	    }
-	    
+
 	    return success;
 	}
-	
+
 	@Override
 	public boolean addSwitch(IOFSwitch sw) {
 		boolean success = false;
-		
+
 		String dpid = sw.getStringId();
 		log.info("SwitchStorage:addSwitch(): dpid {} ", dpid);
-		
+
 		try {
 			ISwitchObject curr = op.searchSwitch(dpid);
 			if (curr != null) {
-				//If existing the switch. set The SW state ACTIVE. 
+				//If existing the switch. set The SW state ACTIVE.
 				log.info("SwitchStorage:addSwitch dpid:{} already exists", dpid);
 				setSwitchStateImpl(curr, SwitchState.ACTIVE);
 			} else {
 				curr = addSwitchImpl(dpid);
 			}
-	
+
 			for (OFPhysicalPort port: sw.getPorts()) {
 				//addPort(dpid, port);
 				addPortImpl(curr, port);
 
 			}
-			
+
 			// XXX for now delete devices when we change a port to prevent
 			// having stale devices.
 			DeviceStorageImpl deviceStorage = new DeviceStorageImpl();
@@ -168,14 +167,14 @@
 					deviceStorage.removeDeviceImpl(deviceStorage.getDeviceByMac(deviceObject.getMACAddress()));
 				}
 			}
-			
+
 			op.commit();
 			success = true;
 		} catch (Exception e) {
 			op.rollback();
 			log.error("SwitchStorage:addSwitch dpid:{} failed", dpid, e);
 		}
-		
+
 		return success;
 	}
 
@@ -186,16 +185,16 @@
 	// This method is only called by tests, so we probably don't need it.
 	// If we need both addSwitch interfaces, one should call the other
 	// rather than implementing the same logic twice.
-	@Deprecated 
+	@Deprecated
 	@Override
 	public boolean addSwitch(String dpid) {
 		boolean success = false;
-		
+
 		log.info("SwitchStorage:addSwitch(): dpid {} ", dpid);
 		try {
 			ISwitchObject sw = op.searchSwitch(dpid);
 			if (sw != null) {
-				//If existing the switch. set The SW state ACTIVE. 
+				//If existing the switch. set The SW state ACTIVE.
 				log.info("SwitchStorage:addSwitch dpid:{} already exists", dpid);
 				setSwitchStateImpl(sw, SwitchState.ACTIVE);
 			} else {
@@ -208,7 +207,7 @@
 			e.printStackTrace();
 			log.error("SwitchStorage:addSwitch dpid:{} failed", dpid, e);
 		}
-		
+
 		return success;
 	}
 
@@ -219,7 +218,7 @@
 	@Override
 	public boolean deleteSwitch(String dpid) {
 		boolean success = false;
-		
+
 		try {
 			ISwitchObject sw = op.searchSwitch(dpid);
 			if (sw != null) {
@@ -232,18 +231,19 @@
 			e.printStackTrace();
 			log.error("SwitchStorage:deleteSwitch {} failed", dpid);
 		}
-	
+
 		return success;
 	}
-	
+
+	@Override
 	public boolean deactivateSwitch(String dpid) {
 		boolean success = false;
-		
+
 		try {
 			ISwitchObject switchObject = op.searchSwitch(dpid);
 			if (switchObject != null) {
 				setSwitchStateImpl(switchObject, SwitchState.INACTIVE);
-				
+
 				for (IPortObject portObject : switchObject.getPorts()) {
 					portObject.setState("INACTIVE");
 				}
@@ -258,16 +258,17 @@
 			op.rollback();
 			log.error("SwitchStorage:deactivateSwitch {} failed", dpid, e);
 		}
-		
+
 		return success;
 	}
 
+	@Override
 	public boolean updatePort(String dpid, short portNum, int state, String desc) {
 		boolean success = false;
-		
+
 		try {
 			ISwitchObject sw = op.searchSwitch(dpid);
-	
+
 	        if (sw != null) {
 	        	IPortObject p = sw.getPort(portNum);
 	        	log.info("SwitchStorage:updatePort dpid:{} port:{}", dpid, portNum);
@@ -283,7 +284,7 @@
 			op.rollback();
 			e.printStackTrace();
 			log.error("SwitchStorage:addPort dpid:{} port:{} failed", dpid, portNum);
-		}	
+		}
 
 		return success;
 	}
@@ -296,7 +297,7 @@
 	@Override
 	public boolean addPort(String dpid, OFPhysicalPort phport) {
 		boolean success = false;
-		
+
 		if(((OFPortConfig.OFPPC_PORT_DOWN.getValue() & phport.getConfig()) > 0) ||
 				((OFPortState.OFPPS_LINK_DOWN.getValue() & phport.getState()) > 0)) {
 			// just dispatch to deletePort()
@@ -304,22 +305,22 @@
 			// DB with the correct info and port state.
 			return deletePort(dpid, phport.getPortNumber());
 		}
-	
+
 		try {
 			ISwitchObject sw = op.searchSwitch(dpid);
-	
+
 	        if (sw != null) {
 	        	IPortObject portObject = addPortImpl(sw, phport);
-	        	
+
 	        	// XXX for now delete devices when we change a port to prevent
 	    		// having stale devices.
 	    		DeviceStorageImpl deviceStorage = new DeviceStorageImpl();
 	    		deviceStorage.init("","");
-	    		
+
 	    		for (IDeviceObject deviceObject : portObject.getDevices()) {
 	    			deviceStorage.removeDevice(deviceObject);
 	    		}
-	        	
+
         		op.commit();
         		success = true;
 	        } else {
@@ -330,7 +331,7 @@
 			e.printStackTrace();
 			log.error("SwitchStorage:addPort dpid:{} port:{} failed", dpid, phport.getPortNumber());
 		}
-		
+
 		return success;
 	}
 
@@ -342,19 +343,19 @@
 	@Override
 	public boolean deletePort(String dpid, short port) {
 		boolean success = false;
-		
+
 		DeviceStorageImpl deviceStorage = new DeviceStorageImpl();
 		deviceStorage.init("","");
-		
+
 		try {
 			ISwitchObject sw = op.searchSwitch(dpid);
-	
+
 	        if (sw != null) {
 	        	IPortObject p = sw.getPort(port);
 	            if (p != null) {
 	        		log.info("SwitchStorage:deletePort dpid:{} port:{} found and set INACTIVE", dpid, port);
 	        		p.setState("INACTIVE");
-	        		
+
 	        		// XXX for now delete devices when we change a port to prevent
 	        		// having stale devices.
 	        		for (IDeviceObject d : p.getDevices()) {
@@ -363,7 +364,7 @@
 	        		op.commit();
 	        	}
 	        }
-	        
+
 	        success = true;
 		} catch (Exception e) {
 			op.rollback();
@@ -404,7 +405,7 @@
 			return null;
 		}
 	}
-	
+
 	private void setSwitchStateImpl(ISwitchObject sw, SwitchState state) {
 		if (sw != null && state != null) {
 			sw.setState(state.toString());
@@ -412,7 +413,7 @@
 					sw.getDPID(), state.toString());
 		}
 	}
-	
+
 	private void deleteSwitchImpl(ISwitchObject sw) {
         if (sw  != null) {
         	op.removeSwitch(sw);
@@ -421,40 +422,40 @@
         }
 	}
 
-	
+
 	private IPortObject addPortImpl(ISwitchObject sw, OFPhysicalPort phport) {
 		IPortObject portObject = op.searchPort(sw.getDPID(), phport.getPortNumber());
-		
-    	log.info("SwitchStorage:addPort dpid:{} port:{}", 
+
+    	log.info("SwitchStorage:addPort dpid:{} port:{}",
     			sw.getDPID(), phport.getPortNumber());
-    	
+
     	if (portObject != null) {
     		setPortStateImpl(portObject, phport.getState(), phport.getName());
     		portObject.setState("ACTIVE");
-    		
+
     		// This a convoluted way of checking if the port is attached
-    		// or not, but doing it this way avoids using the 
+    		// or not, but doing it this way avoids using the
     		// ISwitchObject.getPort method which uses GremlinGroovy query
     		// and takes forever.
     		boolean attached = false;
     		for (IPortObject portsOnSwitch : sw.getPorts()) {
-    			if (portsOnSwitch.getPortId().equals(portObject.getPortId())) {
+    			if (portsOnSwitch.getPortId().equals( portObject.getPortId() )) {
     				attached = true;
     				break;
     			}
     		}
-    		
+
     		if (!attached) {
     			sw.addPort(portObject);
     		}
-    		
+
     		/*
     		if (sw.getPort(phport.getPortNumber()) == null) {
     			// The port exists but the switch has no "on" link to it
     			sw.addPort(portObject);
     		}*/
-    		
-    		log.info("SwitchStorage:addPort dpid:{} port:{} exists setting as ACTIVE", 
+
+    		log.info("SwitchStorage:addPort dpid:{} port:{} exists setting as ACTIVE",
     				sw.getDPID(), phport.getPortNumber());
     	} else {
     		//addPortImpl(sw, phport.getPortNumber());
@@ -465,13 +466,13 @@
         	log.info("SwitchStorage:addPort dpid:{} port:{} done",
         			sw.getDPID(), phport.getPortNumber());
     	}
-    	
+
     	return portObject;
 	}
 	// TODO There's an issue here where a port with that ID could already
 	// exist when we try to add this one (because it's left over from an
 	// old topology). We need to remove an old port with the same ID when
-	// we add the new port. Also it seems that old ports like this are 
+	// we add the new port. Also it seems that old ports like this are
 	// never cleaned up and will remain in the DB in the ACTIVE state forever.
 	/*private IPortObject addPortImpl(ISwitchObject sw, short portNum) {
 		IPortObject p = op.newPort(sw.getDPID(), portNum);
@@ -479,7 +480,7 @@
 		sw.addPort(p);
     	log.info("SwitchStorage:addPortImpl dpid:{} port:{} done",
     			sw.getDPID(), portNum);
-		
+
 		return p;
 	}*/
 
@@ -491,9 +492,9 @@
 			if (desc != null) {
 				port.setDesc(desc);
 			}
-			
+
 	    	log.info("SwitchStorage:setPortStateImpl port:{} state:{} desc:{} done",
 	    			new Object[] {port.getPortId(), state, desc});
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/web/OnosInternalWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/core/web/OnosInternalWebRoutable.java
new file mode 100644
index 0000000..78bb02b
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/web/OnosInternalWebRoutable.java
@@ -0,0 +1,22 @@
+package net.onrc.onos.ofcontroller.core.web;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+
+public class OnosInternalWebRoutable implements RestletRoutable {
+    @Override
+    public String basePath() {
+        return "/wm/onos/internal";
+    }
+
+    @Override
+    public Restlet getRestlet(Context context) {
+        Router router = new Router(context);
+        // Following added by ONOS
+        router.attach("/clearflowtable/json", ClearFlowTableResource.class);
+        return router;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/IOnosDeviceService.java b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/IOnosDeviceService.java
new file mode 100644
index 0000000..1e40aa5
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/IOnosDeviceService.java
@@ -0,0 +1,14 @@
+package net.onrc.onos.ofcontroller.devicemanager;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+
+/**
+ * {@link OnosDeviceManager} doesn't yet provide any API to fellow modules,
+ * however making it export a dummy service means we can specify it as 
+ * a dependency of Forwarding
+ * @author jono
+ *
+ */
+public interface IOnosDeviceService extends IFloodlightService {
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDevice.java b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDevice.java
new file mode 100644
index 0000000..34d2c38
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDevice.java
@@ -0,0 +1,274 @@
+/**
+*    Copyright 2011,2012, Big Switch Networks, Inc. 
+*    Originally created by David Erickson, Stanford University
+* 
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package net.onrc.onos.ofcontroller.devicemanager;
+
+import java.util.Date;
+
+import net.floodlightcontroller.devicemanager.internal.Entity;
+import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.util.MACAddress;
+
+/**
+ * An entity on the network is a visible trace of a device that corresponds
+ * to a packet received from a particular interface on the edge of a network,
+ * with a particular VLAN tag, and a particular MAC address, along with any
+ * other packet characteristics we might want to consider as helpful for
+ * disambiguating devices.
+ * 
+ * Entities are the most basic element of devices; devices consist of one or
+ * more entities.  Entities are immutable once created, except for the last
+ * seen timestamp.
+ *  
+ * @author readams
+ *
+ */
+public class OnosDevice { //implements Comparable<OnosDevice> {
+    /**
+     * Timeout for computing {@link Entity#activeSince}.
+     * @see {@link Entity#activeSince}
+     */
+    private static int ACTIVITY_TIMEOUT = 30000;
+    
+    /**
+     * The MAC address associated with this entity
+     */
+    private MACAddress macAddress;
+    
+    /**
+     * The IP address associated with this entity, or null if no IP learned
+     * from the network observation associated with this entity
+     */
+    private Integer ipv4Address;
+    
+    /**
+     * The VLAN tag on this entity, or null if untagged
+     */
+    private Short vlan;
+    
+    /**
+     * The DPID of the switch for the ingress point for this entity,
+     * or null if not present
+     */
+    private long switchDPID;
+    
+    /**
+     * The port number of the switch for the ingress point for this entity,
+     * or null if not present
+     */
+    private short switchPort;
+    
+    /**
+     * The last time we observed this entity on the network
+     */
+    private Date lastSeenTimestamp;
+
+    /**
+     * The time between {@link Entity#activeSince} and 
+     * {@link Entity#lastSeenTimestamp} is a period of activity for this
+     * entity where it was observed repeatedly.  If, when the entity is
+     * observed, the  is longer ago than the activity timeout, 
+     * {@link Entity#lastSeenTimestamp} and {@link Entity#activeSince} will 
+     * be set to the current time.
+     */
+    private Date activeSince;
+    
+    private int hashCode = 0;
+
+    // ************
+    // Constructors
+    // ************
+    
+    /**
+     * Create a new entity
+     * 
+     * @param macAddress
+     * @param vlan
+     * @param ipv4Address
+     * @param switchDPID
+     * @param switchPort
+     * @param lastSeenTimestamp
+     */
+    public OnosDevice(MACAddress macAddress, Short vlan, 
+                  Integer ipv4Address, Long switchDPID, short switchPort, 
+                  Date lastSeenTimestamp) {
+        this.macAddress = macAddress;
+        this.ipv4Address = ipv4Address;
+        this.vlan = vlan;
+        this.switchDPID = switchDPID;
+        this.switchPort = switchPort;
+        this.lastSeenTimestamp = lastSeenTimestamp;
+        this.activeSince = lastSeenTimestamp;
+    }
+
+    // ***************
+    // Getters/Setters
+    // ***************
+
+    public MACAddress getMacAddress() {
+        return macAddress;
+    }
+
+    public Integer getIpv4Address() {
+        return ipv4Address;
+    }
+
+    public Short getVlan() {
+        return vlan;
+    }
+
+    public Long getSwitchDPID() {
+        return switchDPID;
+    }
+
+    public short getSwitchPort() {
+        return switchPort;
+    }
+
+    public Date getLastSeenTimestamp() {
+        return lastSeenTimestamp;
+    }
+
+    /**
+     * Set the last seen timestamp and also update {@link Entity#activeSince}
+     * if appropriate
+     * @param lastSeenTimestamp the new last seen timestamp
+     * @see {@link Entity#activeSince}
+     */
+    public void setLastSeenTimestamp(Date lastSeenTimestamp) {
+        if (activeSince == null ||
+            (activeSince.getTime() +  ACTIVITY_TIMEOUT) <
+                lastSeenTimestamp.getTime())
+            this.activeSince = lastSeenTimestamp;
+        this.lastSeenTimestamp = lastSeenTimestamp;
+    }
+
+    public Date getActiveSince() {
+        return activeSince;
+    }
+
+    public void setActiveSince(Date activeSince) {
+        this.activeSince = activeSince;
+    }
+    
+    /*
+    @Override
+    public int hashCode() {
+        if (hashCode != 0) return hashCode;
+        final int prime = 31;
+        hashCode = 1;
+        hashCode = prime * hashCode
+                 + ((ipv4Address == null) ? 0 : ipv4Address.hashCode());
+        //hashCode = prime * hashCode + (int) (macAddress ^ (macAddress >>> 32));
+        hashCode = prime * macAddress.hashCode();
+        hashCode = prime * hashCode + (int) (switchDPID ^ (switchDPID >>> 32));
+        hashCode = prime * hashCode + switchPort;
+        hashCode = prime * hashCode + ((vlan == null) ? 0 : vlan.hashCode());
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        Entity other = (Entity) obj;
+        if (hashCode() != other.hashCode()) return false;
+        if (ipv4Address == null) {
+            if (other.ipv4Address != null) return false;
+        } else if (!ipv4Address.equals(other.ipv4Address)) return false;
+        if (macAddress != other.macAddress) return false;
+        if (switchDPID == null) {
+            if (other.switchDPID != null) return false;
+        } else if (!switchDPID.equals(other.switchDPID)) return false;
+        if (switchPort == null) {
+            if (other.switchPort != null) return false;
+        } else if (!switchPort.equals(other.switchPort)) return false;
+        if (vlan == null) {
+            if (other.vlan != null) return false;
+        } else if (!vlan.equals(other.vlan)) return false;
+        return true;
+    }
+    */
+
+    
+    
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("Entity [macAddress=");
+        builder.append(macAddress.toString());
+        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 == null? "null" : lastSeenTimestamp.getTime());
+        builder.append(", activeSince=");
+        builder.append(activeSince == null? "null" : activeSince.getTime());
+        builder.append("]");
+        return builder.toString();
+    }
+
+    /*
+    @Override
+    public int compareTo(OnosDevice o) {
+        if (macAddress < o.macAddress) return -1;
+        if (macAddress > o.macAddress) return 1;
+
+        int r;
+        if (switchDPID == null)
+            r = o.switchDPID == null ? 0 : -1;
+        else if (o.switchDPID == null)
+            r = 1;
+        else
+            r = switchDPID.compareTo(o.switchDPID);
+        if (r != 0) return r;
+
+        if (switchPort == null)
+            r = o.switchPort == null ? 0 : -1;
+        else if (o.switchPort == null)
+            r = 1;
+        else
+            r = switchPort.compareTo(o.switchPort);
+        if (r != 0) return r;
+
+        if (ipv4Address == null)
+            r = o.ipv4Address == null ? 0 : -1;
+        else if (o.ipv4Address == null)
+            r = 1;
+        else
+            r = ipv4Address.compareTo(o.ipv4Address);
+        if (r != 0) return r;
+
+        if (vlan == null)
+            r = o.vlan == null ? 0 : -1;
+        else if (o.vlan == null)
+            r = 1;
+        else
+            r = vlan.compareTo(o.vlan);
+        if (r != 0) return r;
+
+        return 0;
+    }*/
+    
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDeviceManager.java b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDeviceManager.java
new file mode 100644
index 0000000..f75a2b0
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDeviceManager.java
@@ -0,0 +1,190 @@
+package net.onrc.onos.ofcontroller.devicemanager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFMessageListener;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.IUpdate;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.packet.ARP;
+import net.floodlightcontroller.packet.DHCP;
+import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.packet.UDP;
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.core.IDeviceStorage;
+import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
+
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFPacketIn;
+import org.openflow.protocol.OFType;
+
+public class OnosDeviceManager implements IFloodlightModule, IOFMessageListener,
+										IOnosDeviceService {
+	private IDeviceStorage deviceStorage;
+	
+	private IFloodlightProviderService floodlightProvider;
+
+	private class OnosDeviceUpdate implements IUpdate {
+		private OnosDevice device;
+		
+		public OnosDeviceUpdate(OnosDevice device) {
+			this.device = device;
+		}
+		
+		@Override
+		public void dispatch() {
+			deviceStorage.addOnosDevice(device);
+		}
+	}
+	
+	@Override
+	public String getName() {
+		return "onosdevicemanager";
+	}
+
+	@Override
+	public boolean isCallbackOrderingPrereq(OFType type, String name) {
+		// We want link discovery to consume LLDP first otherwise we'll
+		// end up reading bad device info from LLDP packets
+		return type == OFType.PACKET_IN && "linkdiscovery".equals(name);
+	}
+
+	@Override
+	public boolean isCallbackOrderingPostreq(OFType type, String name) {
+		return type == OFType.PACKET_IN && 
+				("proxyarpmanager".equals(name) || "onosforwarding".equals(name));
+	}
+
+	@Override
+	public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+		if (msg.getType().equals(OFType.PACKET_IN)) {
+			OFPacketIn pi = (OFPacketIn) msg;
+			
+			Ethernet eth = IFloodlightProviderService.bcStore.
+					get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+			
+			return processPacketIn(sw, pi, eth);
+		}
+		
+		return Command.CONTINUE;
+	}
+	
+	private Command processPacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
+		
+        // Extract source entity information
+        OnosDevice srcDevice =
+                getSourceDeviceFromPacket(eth, sw.getId(), pi.getInPort());
+        if (srcDevice == null)
+            return Command.STOP;
+        
+        floodlightProvider.publishUpdate(new OnosDeviceUpdate(srcDevice));
+        
+        return Command.CONTINUE;
+	}
+	
+    /**
+     * Get IP address from packet if the packet is either an ARP 
+     * or a DHCP packet
+     * @param eth
+     * @param dlAddr
+     * @return
+     */
+    private int getSrcNwAddr(Ethernet eth, long dlAddr) {
+        if (eth.getPayload() instanceof ARP) {
+            ARP arp = (ARP) eth.getPayload();
+            if ((arp.getProtocolType() == ARP.PROTO_TYPE_IP) &&
+                    (Ethernet.toLong(arp.getSenderHardwareAddress()) == dlAddr)) {
+                return IPv4.toIPv4Address(arp.getSenderProtocolAddress());
+            }
+        } else if (eth.getPayload() instanceof IPv4) {
+            IPv4 ipv4 = (IPv4) eth.getPayload();
+            if (ipv4.getPayload() instanceof UDP) {
+                UDP udp = (UDP)ipv4.getPayload();
+                if (udp.getPayload() instanceof DHCP) {
+                    DHCP dhcp = (DHCP)udp.getPayload();
+                    if (dhcp.getOpCode() == DHCP.OPCODE_REPLY) {
+                        return ipv4.getSourceAddress();
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Parse an entity from an {@link Ethernet} packet.
+     * @param eth the packet to parse
+     * @param sw the switch on which the packet arrived
+     * @param pi the original packetin
+     * @return the entity from the packet
+     */
+    private OnosDevice getSourceDeviceFromPacket(Ethernet eth,
+                                             long swdpid,
+                                             short port) {
+        byte[] dlAddrArr = eth.getSourceMACAddress();
+        long dlAddr = Ethernet.toLong(dlAddrArr);
+
+        // Ignore broadcast/multicast source
+        if ((dlAddrArr[0] & 0x1) != 0)
+            return null;
+
+        short vlan = eth.getVlanID();
+        int nwSrc = getSrcNwAddr(eth, dlAddr);
+        return new OnosDevice(MACAddress.valueOf(dlAddr),
+                          ((vlan >= 0) ? vlan : null),
+                          ((nwSrc != 0) ? nwSrc : null),
+                          swdpid,
+                          port,
+                          new Date());
+    }
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		List<Class<? extends IFloodlightService>> services = 
+				new ArrayList<Class<? extends IFloodlightService>>();
+		services.add(IOnosDeviceService.class);
+		return services;
+	}
+
+	@Override
+	public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+		Map<Class<? extends IFloodlightService>, IFloodlightService> impls = 
+				new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
+		impls.put(IOnosDeviceService.class, this);
+		return impls;
+	}
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+		List<Class<? extends IFloodlightService>> dependencies = 
+				new ArrayList<Class<? extends IFloodlightService>>();
+		dependencies.add(IFloodlightProviderService.class);
+		return dependencies;
+	}
+
+	@Override
+	public void init(FloodlightModuleContext context)
+			throws FloodlightModuleException {
+		floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+		
+		deviceStorage = new DeviceStorageImpl();
+		deviceStorage.init("");
+	}
+
+	@Override
+	public void startUp(FloodlightModuleContext context) {
+		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
+	}
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
index f458603..3337cf8 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/floodlightlistener/NetworkGraphPublisher.java
@@ -8,13 +8,6 @@
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
-import org.openflow.protocol.OFPhysicalPort;
-import org.openflow.util.HexString;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.net.InetAddresses;
-
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.IOFSwitchListener;
@@ -25,7 +18,6 @@
 import net.floodlightcontroller.core.util.SingletonTask;
 import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.IDeviceListener;
-import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.routing.Link;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
 import net.onrc.onos.graph.DBOperation;
@@ -36,10 +28,10 @@
 import net.onrc.onos.graph.LocalTopologyEventListener;
 import net.onrc.onos.ofcontroller.core.IDeviceStorage;
 import net.onrc.onos.ofcontroller.core.ILinkStorage;
-import net.onrc.onos.ofcontroller.core.IOFSwitchPortListener;
-import net.onrc.onos.ofcontroller.core.ISwitchStorage;
 import net.onrc.onos.ofcontroller.core.INetMapStorage.DM_OPERATION;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.onrc.onos.ofcontroller.core.IOFSwitchPortListener;
+import net.onrc.onos.ofcontroller.core.ISwitchStorage;
 import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
 import net.onrc.onos.ofcontroller.core.internal.LinkStorageImpl;
 import net.onrc.onos.ofcontroller.core.internal.SwitchStorageImpl;
@@ -52,6 +44,13 @@
 import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
 import net.onrc.onos.registry.controller.RegistryException;
 
+import org.openflow.protocol.OFPhysicalPort;
+import org.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.net.InetAddresses;
+
 public class NetworkGraphPublisher implements IDeviceListener,
 					      IOFSwitchListener,
 					      IOFSwitchPortListener,
@@ -63,7 +62,7 @@
 	protected ISwitchStorage swStore;
 	protected ILinkStorage linkStore;
 	protected final static Logger log = LoggerFactory.getLogger(NetworkGraphPublisher.class);
-	protected IDeviceService deviceService;
+	//protected IDeviceService deviceService;
 	protected IControllerRegistryService registryService;
 	protected DBOperation op;
 	
@@ -177,62 +176,63 @@
     	op.close();
     }
 
-	@Override
-	public void linkDiscoveryUpdate(LDUpdate update) {
-		Link lt = new Link(update.getSrc(),update.getSrcPort(),update.getDst(),update.getDstPort());
-		//log.debug("{}:LinkDicoveryUpdate(): Updating Link {}",this.getClass(), lt);
-		
-		switch (update.getOperation()) {
-			case LINK_REMOVED:
-				log.debug("LinkDiscoveryUpdate(): Removing link {}", lt);
-				
-				if (linkStore.deleteLink(lt)) {
-				    // TODO publish DELETE_LINK event here
-				    TopologyElement topologyElement =
-					new TopologyElement(update.getSrc(),
-							    update.getSrcPort(),
-							    update.getDst(),
-							    update.getDstPort());
-				    datagridService.notificationSendTopologyElementRemoved(topologyElement);
-				}
-				break;
-			case LINK_UPDATED:
-				log.debug("LinkDiscoveryUpdate(): Updating link {}", lt);
-				
-				LinkInfo linfo = linkStore.getLinkInfo(lt);
-				// TODO update "linfo" using portState derived using "update"
-				if (linkStore.update(lt, linfo, DM_OPERATION.UPDATE)) {
-				    // TODO publish UPDATE_LINK event here
-				    //
-				    // TODO NOTE: Here we assume that updated
-				    // link is UP.
-				    //
-				    TopologyElement topologyElement =
-					new TopologyElement(update.getSrc(),
-							    update.getSrcPort(),
-							    update.getDst(),
-							    update.getDstPort());
-				    datagridService.notificationSendTopologyElementUpdated(topologyElement);
-				}
-				break;
-			case LINK_ADDED:
-				log.debug("LinkDiscoveryUpdate(): Adding link {}", lt);
-				
-				if (linkStore.addLink(lt)) {
-				    // TODO publish ADD_LINK event here
-				    TopologyElement topologyElement =
-					new TopologyElement(update.getSrc(),
-							    update.getSrcPort(),
-							    update.getDst(),
-							    update.getDstPort());
-				    datagridService.notificationSendTopologyElementAdded(topologyElement);
-				}
-				break;
-			default:
-				break;
-		}
+    @Override
+    public void linkDiscoveryUpdate(LDUpdate update) {
+    	Link lt = new Link(update.getSrc(),update.getSrcPort(),update.getDst(),update.getDstPort());
+    	//log.debug("{}:LinkDicoveryUpdate(): Updating Link {}",this.getClass(), lt);
 
-	}
+    	switch (update.getOperation()) {
+    	case LINK_REMOVED:
+    		log.debug("LinkDiscoveryUpdate(): Removing link {}", lt);
+
+    		if (linkStore.deleteLink(lt)) {
+    			// TODO publish DELETE_LINK event here
+    			TopologyElement topologyElement =
+    					new TopologyElement(update.getSrc(),
+    							update.getSrcPort(),
+    							update.getDst(),
+    							update.getDstPort());
+    			datagridService.notificationSendTopologyElementRemoved(topologyElement);
+    		}
+    		break;
+    	case LINK_UPDATED:
+    		log.debug("LinkDiscoveryUpdate(): Updating link {}", lt);
+
+    		LinkInfo linfo = linkStore.getLinkInfo(lt);
+    		// TODO update "linfo" using portState derived using "update"
+    		if (linkStore.update(lt, linfo, DM_OPERATION.UPDATE)) {
+    			// TODO publish UPDATE_LINK event here
+    			//
+    			// TODO NOTE: Here we assume that updated
+    			// link is UP.
+    			//
+    			TopologyElement topologyElement =
+    					new TopologyElement(update.getSrc(),
+    							update.getSrcPort(),
+    							update.getDst(),
+    							update.getDstPort());
+    			datagridService.notificationSendTopologyElementUpdated(topologyElement);
+    		}
+    		break;
+    	case LINK_ADDED:
+    		log.debug("LinkDiscoveryUpdate(): Adding link {}", lt);
+
+    		if (linkStore.addLink(lt)) {
+    			// TODO publish ADD_LINK event here
+    			TopologyElement topologyElement =
+    					new TopologyElement(update.getSrc(),
+    							update.getSrcPort(),
+    							update.getDst(),
+    							update.getDstPort());
+    			datagridService.notificationSendTopologyElementAdded(topologyElement);
+    		}
+
+    		break;
+    	default:
+    		break;
+    	}
+
+    }
 
 	@Override
 	public void addedSwitch(IOFSwitch sw) {
@@ -434,7 +434,7 @@
 	    Collection<Class<? extends IFloodlightService>> l =
 	            new ArrayList<Class<? extends IFloodlightService>>();
 	        l.add(IFloodlightProviderService.class);
-	        l.add(IDeviceService.class);
+	        //l.add(IDeviceService.class);
 	        l.add(IDatagridService.class);
 	        l.add(IThreadPoolService.class);
 	        return l;
@@ -455,7 +455,7 @@
 		
 		floodlightProvider =
 	            context.getServiceImpl(IFloodlightProviderService.class);
-		deviceService = context.getServiceImpl(IDeviceService.class);
+		//deviceService = context.getServiceImpl(IDeviceService.class);
 		linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
 		threadPool = context.getServiceImpl(IThreadPoolService.class);
 		registryService = context.getServiceImpl(IControllerRegistryService.class);
@@ -479,7 +479,7 @@
 		Map<String, String> configMap = context.getConfigParams(this);
 		String cleanupNeeded = configMap.get(CleanupEnabled);
 
-		deviceService.addListener(this);
+		//deviceService.addListener(this);
 		floodlightProvider.addOFSwitchListener(this);
 		linkDiscovery.addListener(this);
 		
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
index ec27a0f..194922b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowDatabaseOperation.java
@@ -622,6 +622,12 @@
      * @return the extracted Flow Entry State.
      */
     public static FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
+	IFlowPath flowObj = flowEntryObj.getFlow();
+	if (flowObj == null)
+	    return null;
+
+	String flowIdStr = flowObj.getFlowId();
+	//
 	String flowEntryIdStr = flowEntryObj.getFlowEntryId();
 	Integer idleTimeout = flowEntryObj.getIdleTimeout();
 	Integer hardTimeout = flowEntryObj.getHardTimeout();
@@ -629,7 +635,8 @@
 	String userState = flowEntryObj.getUserState();
 	String switchState = flowEntryObj.getSwitchState();
 
-	if ((flowEntryIdStr == null) ||
+	if ((flowIdStr == null) ||
+	    (flowEntryIdStr == null) ||
 	    (idleTimeout == null) ||
 	    (hardTimeout == null) ||
 	    (switchDpidStr == null) ||
@@ -641,10 +648,11 @@
 
 	FlowEntry flowEntry = new FlowEntry();
 	flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
+	flowEntry.setFlowId(new FlowId(flowIdStr));
 	flowEntry.setDpid(new Dpid(switchDpidStr));
 	flowEntry.setIdleTimeout(idleTimeout);
 	flowEntry.setHardTimeout(hardTimeout);
-	
+
 	//
 	// Extract the match conditions
 	//
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
index 3538eb4..c36c53a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowEventHandler.java
@@ -460,7 +460,7 @@
      */
     private void processFlowEntryEvents() {
 	FlowPath flowPath;
-	FlowEntry updatedFlowEntry;
+	FlowEntry localFlowEntry;
 
 	//
 	// Update Flow Entries with previously unmatched Flow Entry updates
@@ -471,13 +471,15 @@
 		flowPath = allFlowPaths.get(flowEntry.flowId().value());
 		if (flowPath == null)
 		    continue;
-		updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
-		if (updatedFlowEntry == null) {
+		localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
+		if (localFlowEntry == null) {
 		    remainingUpdates.put(flowEntry.flowEntryId().value(),
 					 flowEntry);
 		    continue;
 		}
-		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
+		if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
+		    modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
+		}
 	    }
 	    unmatchedFlowEntryAdd = remainingUpdates;
 	}
@@ -505,15 +507,17 @@
 					      flowEntry);
 		    break;
 		}
-		updatedFlowEntry = updateFlowEntryAdd(flowPath, flowEntry);
-		if (updatedFlowEntry == null) {
+		localFlowEntry = findFlowEntryAdd(flowPath, flowEntry);
+		if (localFlowEntry == null) {
 		    // Flow Entry not found: keep the entry for later matching
 		    unmatchedFlowEntryAdd.put(flowEntry.flowEntryId().value(),
 					      flowEntry);
 		    break;
 		}
-		// Add the updated entry to the list of updated Flow Entries
-		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
+		if (updateFlowEntryAdd(flowPath, localFlowEntry, flowEntry)) {
+		    // Add the updated Flow Path to the list of updated paths
+		    modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
+		}
 		break;
 
 	    case ENTRY_REMOVE:
@@ -527,32 +531,37 @@
 		    // Flow Path not found: ignore the update
 		    break;
 		}
-		updatedFlowEntry = updateFlowEntryRemove(flowPath, flowEntry);
-		if (updatedFlowEntry == null) {
+		localFlowEntry = findFlowEntryRemove(flowPath, flowEntry);
+		if (localFlowEntry == null) {
 		    // Flow Entry not found: ignore it
 		    break;
 		}
-		modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
+		if (updateFlowEntryRemove(flowPath, localFlowEntry,
+					  flowEntry)) {
+		    // Add the updated Flow Path to the list of updated paths
+		    modifiedFlowPaths.put(flowPath.flowId().value(), flowPath);
+		}
 		break;
 	    }
 	}
     }
 
     /**
-     * Update a Flow Entry because of an external ENTRY_ADD event.
+     * Find a Flow Entry that should be updated because of an external
+     * ENTRY_ADD event.
      *
      * @param flowPath the FlowPath for the Flow Entry to update.
-     * @param flowEntry the FlowEntry with the new state.
-     * @return the updated Flow Entry if found, otherwise null.
+     * @param newFlowEntry the FlowEntry with the new state.
+     * @return the Flow Entry that should be updated if found, otherwise null.
      */
-    private FlowEntry updateFlowEntryAdd(FlowPath flowPath,
-					 FlowEntry flowEntry) {
+    private FlowEntry findFlowEntryAdd(FlowPath flowPath,
+				       FlowEntry newFlowEntry) {
 	//
 	// Iterate over all Flow Entries and find a match.
 	//
 	for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
 	    if (! TopologyManager.isSameFlowEntryDataPath(localFlowEntry,
-							  flowEntry)) {
+							  newFlowEntry)) {
 		continue;
 	    }
 
@@ -561,27 +570,89 @@
 	    //
 	    if (localFlowEntry.isValidFlowEntryId()) {
 		if (localFlowEntry.flowEntryId().value() !=
-		    flowEntry.flowEntryId().value()) {
+		    newFlowEntry.flowEntryId().value()) {
 		    //
 		    // Find a local Flow Entry, but the Flow Entry ID doesn't
 		    // match. Keep looking.
 		    //
 		    continue;
 		}
-	    } else {
-		// Update the Flow Entry ID
-		FlowEntryId flowEntryId =
-		    new FlowEntryId(flowEntry.flowEntryId().value());
-		localFlowEntry.setFlowEntryId(flowEntryId);
 	    }
+	    return localFlowEntry;
+	}
 
-	    //
-	    // Update the local Flow Entry, and keep state to check
-	    // if the Flow Path has been installed.
-	    //
-	    localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
-	    localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
+	return null;		// Entry not found
+    }
+
+    /**
+     * Update a Flow Entry because of an external ENTRY_ADD event.
+     *
+     * @param flowPath the FlowPath for the Flow Entry to update.
+     * @param localFlowEntry the local Flow Entry to update.
+     * @param newFlowEntry the FlowEntry with the new state.
+     * @return true if the local Flow Entry was updated, otherwise false.
+     */
+    private boolean updateFlowEntryAdd(FlowPath flowPath,
+				       FlowEntry localFlowEntry,
+				       FlowEntry newFlowEntry) {
+	boolean updated = false;
+
+	if (localFlowEntry.flowEntryUserState() ==
+	    FlowEntryUserState.FE_USER_DELETE) {
+	    // Don't add-back a Flow Entry that is already deleted
+	    return false;
+	}
+
+	if (! localFlowEntry.isValidFlowEntryId()) {
+	    // Update the Flow Entry ID
+	    FlowEntryId flowEntryId =
+		new FlowEntryId(newFlowEntry.flowEntryId().value());
+	    localFlowEntry.setFlowEntryId(flowEntryId);
+	    updated = true;
+	}
+
+	//
+	// Update the local Flow Entry, and keep state to check
+	// if the Flow Path has been installed.
+	//
+	if (localFlowEntry.flowEntryUserState() !=
+	    newFlowEntry.flowEntryUserState()) {
+	    localFlowEntry.setFlowEntryUserState(
+			 newFlowEntry.flowEntryUserState());
+	    updated = true;
+	}
+	if (localFlowEntry.flowEntrySwitchState() !=
+	    newFlowEntry.flowEntrySwitchState()) {
+	    localFlowEntry.setFlowEntrySwitchState(
+			newFlowEntry.flowEntrySwitchState());
 	    checkIfInstalledFlowPaths.put(flowPath.flowId().value(), flowPath);
+	    updated = true;
+	}
+
+	return updated;
+    }
+
+    /**
+     * Find a Flow Entry that should be updated because of an external
+     * ENTRY_REMOVE event.
+     *
+     * @param flowPath the FlowPath for the Flow Entry to update.
+     * @param newFlowEntry the FlowEntry with the new state.
+     * @return the Flow Entry that should be updated if found, otherwise null.
+     */
+    private FlowEntry findFlowEntryRemove(FlowPath flowPath,
+					  FlowEntry newFlowEntry) {
+	//
+	// Iterate over all Flow Entries and find a match based on
+	// the Flow Entry ID.
+	//
+	for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
+	    if (! localFlowEntry.isValidFlowEntryId())
+		continue;
+	    if (localFlowEntry.flowEntryId().value() !=
+		newFlowEntry.flowEntryId().value()) {
+		continue;
+	    }
 	    return localFlowEntry;
 	}
 
@@ -592,31 +663,32 @@
      * Update a Flow Entry because of an external ENTRY_REMOVE event.
      *
      * @param flowPath the FlowPath for the Flow Entry to update.
-     * @param flowEntry the FlowEntry with the new state.
-     * @return the updated Flow Entry if found, otherwise null.
+     * @param localFlowEntry the local Flow Entry to update.
+     * @param newFlowEntry the FlowEntry with the new state.
+     * @return true if the local Flow Entry was updated, otherwise false.
      */
-    private FlowEntry updateFlowEntryRemove(FlowPath flowPath,
-					    FlowEntry flowEntry) {
+    private boolean updateFlowEntryRemove(FlowPath flowPath,
+					  FlowEntry localFlowEntry,
+					  FlowEntry newFlowEntry) {
+	boolean updated = false;
+
 	//
-	// Iterate over all Flow Entries and find a match based on
-	// the Flow Entry ID.
+	// Update the local Flow Entry.
 	//
-	for (FlowEntry localFlowEntry : flowPath.flowEntries()) {
-	    if (! localFlowEntry.isValidFlowEntryId())
-		continue;
-	    if (localFlowEntry.flowEntryId().value() !=
-		flowEntry.flowEntryId().value()) {
-		    continue;
-	    }
-	    //
-	    // Update the local Flow Entry.
-	    //
-	    localFlowEntry.setFlowEntryUserState(flowEntry.flowEntryUserState());
-	    localFlowEntry.setFlowEntrySwitchState(flowEntry.flowEntrySwitchState());
-	    return localFlowEntry;
+	if (localFlowEntry.flowEntryUserState() !=
+	    newFlowEntry.flowEntryUserState()) {
+	    localFlowEntry.setFlowEntryUserState(
+			newFlowEntry.flowEntryUserState());
+	    updated = true;
+	}
+	if (localFlowEntry.flowEntrySwitchState() !=
+	    newFlowEntry.flowEntrySwitchState()) {
+	    localFlowEntry.setFlowEntrySwitchState(
+			newFlowEntry.flowEntrySwitchState());
+	    updated = true;
 	}
 
-	return null;		// Entry not found
+	return updated;
     }
 
     /**
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
index 9df6cae..072e34f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/FlowManager.java
@@ -249,10 +249,17 @@
 	// in case the application didn't do it.
 	//
 	for (FlowEntry flowEntry : flowPath.flowEntries()) {
+	    // The Flow Entry switch state
 	    if (flowEntry.flowEntrySwitchState() ==
 		FlowEntrySwitchState.FE_SWITCH_UNKNOWN) {
 		flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_NOT_UPDATED);
 	    }
+	    // The Flow Entry ID
+	    if (! flowEntry.isValidFlowEntryId()) {
+		long id = getNextFlowEntryId();
+		flowEntry.setFlowEntryId(new FlowEntryId(id));
+	    }
+	    // The Flow ID
 	    if (! flowEntry.isValidFlowId())
 		flowEntry.setFlowId(new FlowId(flowPath.flowId().value()));
 	}
@@ -406,32 +413,40 @@
 	//
 	// Process all entries
 	//
+	// TODO: For now we have to create an explicit FlowEntry copy so
+	// we don't modify the original FlowEntry.
+	// This should go away after we start using the OpenFlow Barrier
+	// mechnanism in the FlowPusher.
+	//
+	Kryo kryo = kryoFactory.newKryo();
 	for (Pair<IOFSwitch, FlowEntry> entry : entries) {
 	    FlowEntry flowEntry = entry.second;
 
 	    //
 	    // Mark the Flow Entry that it has been pushed to the switch
 	    //
-	    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
+	    FlowEntry copyFlowEntry = kryo.copy(flowEntry);
+	    copyFlowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.FE_SWITCH_UPDATED);
 
 	    //
 	    // Write the Flow Entry to the Datagrid
 	    //
-	    switch (flowEntry.flowEntryUserState()) {
+	    switch (copyFlowEntry.flowEntryUserState()) {
 	    case FE_USER_ADD:
-		datagridService.notificationSendFlowEntryAdded(flowEntry);
+		datagridService.notificationSendFlowEntryAdded(copyFlowEntry);
 		break;
 	    case FE_USER_MODIFY:
-		datagridService.notificationSendFlowEntryUpdated(flowEntry);
+		datagridService.notificationSendFlowEntryUpdated(copyFlowEntry);
 		break;
 	    case FE_USER_DELETE:
-		datagridService.notificationSendFlowEntryRemoved(flowEntry.flowEntryId());
+		datagridService.notificationSendFlowEntryRemoved(copyFlowEntry.flowEntryId());
 		break;
 	    case FE_USER_UNKNOWN:
 		assert(false);
 		break;
 	    }
 	}
+	kryoFactory.deleteKryo(kryo);
     }
 
     /**
@@ -688,6 +703,11 @@
 		    allValid = false;
 		    break;
 		}
+		if (flowEntry.flowEntrySwitchState() !=
+		    FlowEntrySwitchState.FE_SWITCH_UPDATED) {
+		    allValid = false;
+		    break;
+		}
 	    }
 	    if (! allValid)
 		continue;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
deleted file mode 100644
index 4d03623..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/AddShortestPathFlowResource.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package net.onrc.onos.ofcontroller.flowmanager.web;
-
-import java.io.IOException;
-
-import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
-import net.onrc.onos.ofcontroller.util.FlowId;
-import net.onrc.onos.ofcontroller.util.FlowPath;
-
-import org.codehaus.jackson.JsonGenerationException;
-import org.codehaus.jackson.map.JsonMappingException;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.restlet.resource.Post;
-import org.restlet.resource.ServerResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Flow Manager REST API implementation: Add a Flow by delegating
- * the Shortest Path computation to ONOS:
- *
- *   POST /wm/flow/add-shortest-path/json
- */
-public class AddShortestPathFlowResource extends ServerResource {
-
-    protected final static Logger log = LoggerFactory.getLogger(AddShortestPathFlowResource.class);
-
-    /**
-     * Implement the API.
-     *
-     * @param flowJson a string with the JSON representation of the Flow to
-     * add.
-     * @return the Flow ID of the added flow.
-     */
-    @Post("json")
-    public FlowId store(String flowJson) {
-	FlowId result = new FlowId();
-
-        IFlowService flowService =
-                (IFlowService)getContext().getAttributes().
-                get(IFlowService.class.getCanonicalName());
-
-        if (flowService == null) {
-	    log.debug("ONOS Flow Service not found");
-            return result;
-	}
-
-	//
-	// Extract the arguments
-	// NOTE: The "flow" is specified in JSON format.
-	//
-	ObjectMapper mapper = new ObjectMapper();
-	String flowPathStr = flowJson;
-	FlowPath flowPath = null;
-	log.debug("Add Shortest Path Flow Path: " + flowPathStr);
-	try {
-	    flowPath = mapper.readValue(flowPathStr, FlowPath.class);
-	} catch (JsonGenerationException e) {
-	    e.printStackTrace();
-	} catch (JsonMappingException e) {
-	    e.printStackTrace();
-	} catch (IOException e) {
-	    e.printStackTrace();
-	}
-
-	// Process the request
-	if (flowPath != null) {
-	    FlowId addedFlowId = flowService.addFlow(flowPath);
-	    if (addedFlowId != null)
-		result = addedFlowId;
-	}
-
-        return result;
-    }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
index c358263..73a3936 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowmanager/web/FlowWebRoutable.java
@@ -17,7 +17,6 @@
     public Restlet getRestlet(Context context) {
         Router router = new Router(context);
         router.attach("/add/json", AddFlowResource.class);
-        router.attach("/add-shortest-path/json", AddShortestPathFlowResource.class);
         router.attach("/delete/{flow-id}/json", DeleteFlowResource.class);
         router.attach("/get/{flow-id}/json", GetFlowByIdResource.class);
         router.attach("/getall/json", GetAllFlowsResource.class);
@@ -30,6 +29,6 @@
      */
     @Override
     public String basePath() {
-        return "/wm/flow";
+        return "/wm/onos/flows";
     }
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
index a4f0a8c..641faaf 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowProgrammer.java
@@ -139,8 +139,8 @@
 	switch (msg.getType()) {
 	case FLOW_REMOVED:
 	    OFFlowRemoved flowMsg = (OFFlowRemoved) msg;
-	    log.debug("Got flow removed from "+ sw.getId() +": "+ flowMsg.getCookie());
 	    FlowEntryId id = new FlowEntryId(flowMsg.getCookie());
+	    log.debug("Got flow entry removed from " + sw.getId() + ": " + id);
 	    flowManager.flowEntryOnSwitchExpired(sw, id);
 	    break;
 	default:
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
index 3f61248..6485c5e 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/FlowPusher.java
@@ -735,10 +735,13 @@
 		}
 
 		//
-		// TODO: Set the following flag
-		// fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
-		// See method ForwardingBase::pushRoute()
+		// Set the OFPFF_SEND_FLOW_REM flag if the Flow Entry is not
+		// permanent.
 		//
+		if ((flowEntry.idleTimeout() != 0) ||
+		    (flowEntry.hardTimeout() != 0)) {
+		    fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
+		}
 
 		//
 		// Write the message to the switch
diff --git a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/FlowProgrammerWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/FlowProgrammerWebRoutable.java
index 22450f7..9325a00 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/FlowProgrammerWebRoutable.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/flowprogrammer/web/FlowProgrammerWebRoutable.java
@@ -22,7 +22,7 @@
 
 	@Override
 	public String basePath() {
-		return "/wm/fprog";
+		return "/wm/onos/flowprogrammer";
 	}
 
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java b/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
index b062e2b..65bc40b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/forwarding/Forwarding.java
@@ -7,7 +7,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -25,6 +24,7 @@
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
+import net.onrc.onos.ofcontroller.devicemanager.IOnosDeviceService;
 import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.flowprogrammer.IFlowPusherService;
 import net.onrc.onos.ofcontroller.proxyarp.ArpMessage;
@@ -51,8 +51,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.ListMultimap;
 import com.google.common.net.InetAddresses;
 
 public class Forwarding implements IOFMessageListener, IFloodlightModule,
@@ -61,6 +61,8 @@
 
 	private final int IDLE_TIMEOUT = 5; // seconds
 	private final int HARD_TIMEOUT = 0; // seconds
+
+	private final int PATH_PUSHED_TIMEOUT = 3000; // milliseconds
 	
 	private IFloodlightProviderService floodlightProvider;
 	private IFlowService flowService;
@@ -70,12 +72,15 @@
 	private IDeviceStorage deviceStorage;
 	private TopologyManager topologyService;
 	
-	private Map<Path, Long> pendingFlows;
-	private Multimap<Long, PacketToPush> waitingPackets;
+	//private Map<Path, Long> pendingFlows;
+	// TODO it seems there is a Guava collection that will time out entries.
+	// We should see if this will work here.
+	private Map<Path, PushedFlow> pendingFlows;
+	private ListMultimap<Long, PacketToPush> waitingPackets;
 	
 	private final Object lock = new Object();
 	
-	public class PacketToPush {
+	private class PacketToPush {
 		public final OFPacketOut packet;
 		public final long dpid;
 		
@@ -85,15 +90,35 @@
 		}
 	}
 	
-	public final class Path {
+	private class PushedFlow {
+		public final long flowId;
+		private final long pushedTime;
+		public short firstHopOutPort = OFPort.OFPP_NONE.getValue();
+		
+		public PushedFlow(long flowId) {
+			this.flowId = flowId;
+			pushedTime = System.currentTimeMillis();
+		}
+		
+		public boolean isExpired() {
+			return (System.currentTimeMillis() - pushedTime) > PATH_PUSHED_TIMEOUT;
+		}
+	}
+	
+	private final class Path {
 		public final SwitchPort srcPort;
 		public final SwitchPort dstPort;
+		public final MACAddress srcMac;
+		public final MACAddress dstMac;
 		
-		public Path(SwitchPort src, SwitchPort dst) {
+		public Path(SwitchPort src, SwitchPort dst, 
+				MACAddress srcMac, MACAddress dstMac) {
 			srcPort = new SwitchPort(new Dpid(src.dpid().value()), 
 					new Port(src.port().value()));
 			dstPort = new SwitchPort(new Dpid(dst.dpid().value()), 
 					new Port(dst.port().value()));
+			this.srcMac = srcMac;
+			this.dstMac = dstMac;
 		}
 		
 		@Override
@@ -104,7 +129,9 @@
 			
 			Path otherPath = (Path) other;
 			return srcPort.equals(otherPath.srcPort) && 
-					dstPort.equals(otherPath.dstPort);
+					dstPort.equals(otherPath.dstPort) &&
+					srcMac.equals(otherPath.srcMac) &&
+					dstMac.equals(otherPath.dstMac);
 		}
 		
 		@Override
@@ -112,8 +139,16 @@
 			int hash = 17;
 			hash = 31 * hash + srcPort.hashCode();
 			hash = 31 * hash + dstPort.hashCode();
+			hash = 31 * hash + srcMac.hashCode();
+			hash = 31 * hash + dstMac.hashCode();
 			return hash;
 		}
+		
+		@Override
+		public String toString() {
+			return "(" + srcMac + " at " + srcPort + ") => (" 
+					+ dstPort + " at " + dstMac + ")";
+		}
 	}
 	
 	@Override
@@ -139,6 +174,7 @@
 		dependencies.add(IFloodlightProviderService.class);
 		dependencies.add(IFlowService.class);
 		dependencies.add(IFlowPusherService.class);
+		dependencies.add(IOnosDeviceService.class);
 		return dependencies;
 	}
 	
@@ -152,10 +188,12 @@
 		
 		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
 		
-		pendingFlows = new ConcurrentHashMap<Path, Long>();
+		//pendingFlows = new ConcurrentHashMap<Path, Long>();
+		pendingFlows = new HashMap<Path, PushedFlow>();
 		//waitingPackets = Multimaps.synchronizedSetMultimap(
 				//HashMultimap.<Long, PacketToPush>create());
-		waitingPackets = HashMultimap.create();
+		//waitingPackets = HashMultimap.create();
+		waitingPackets = LinkedListMultimap.create();
 		
 		deviceStorage = new DeviceStorageImpl();
 		deviceStorage.init("","");
@@ -176,7 +214,8 @@
 	@Override
 	public boolean isCallbackOrderingPrereq(OFType type, String name) {
 		return (type == OFType.PACKET_IN) && 
-				(name.equals("devicemanager") || name.equals("proxyarpmanager"));
+				(name.equals("devicemanager") || name.equals("proxyarpmanager")
+				|| name.equals("onosdevicemanager"));
 	}
 
 	@Override
@@ -233,7 +272,8 @@
 		// actually ARP before broadcasting, so we can trick it into sending
 		// our non-ARP packets.
 		// TODO This should be refactored later to account for the new use case.
-		datagrid.sendArpRequest(ArpMessage.newRequest(targetAddress, eth.serialize()));
+		datagrid.sendArpRequest(ArpMessage.newRequest(targetAddress, eth.serialize(),
+				-1L, (short)-1, sw.getId(), pi.getInPort()));
 	}
 	
 	private void handlePacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
@@ -244,13 +284,17 @@
 				destinationMac);
 		
 		if (deviceObject == null) {
-			log.debug("No device entry found for {}", destinationMac);
+			log.debug("No device entry found for {} - broadcasting packet", 
+					destinationMac);
+			handleBroadcast(sw, pi, eth);
 			return;
 		}
 		
 		Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();	
 		if (!ports.hasNext()) {
-			log.debug("No attachment point found for device {}", destinationMac);
+			log.debug("No attachment point found for device {} - broadcasting packet", 
+					destinationMac);
+			handleBroadcast(sw, pi, eth);
 			return;
 		}
 		IPortObject portObject = ports.next();
@@ -271,20 +315,35 @@
 		
 		FlowPath flowPath, reverseFlowPath;
 		
-		Path pathspec = new Path(srcSwitchPort, dstSwitchPort);
+		Path pathspec = new Path(srcSwitchPort, dstSwitchPort, 
+				srcMacAddress, dstMacAddress);
 		// TODO check concurrency
 		synchronized (lock) {
-			Long existingFlowId = pendingFlows.get(pathspec);
+			PushedFlow existingFlow = pendingFlows.get(pathspec);
+			//Long existingFlowId = pendingFlows.get(pathspec);
 			
-			if (existingFlowId != null) {
+			if (existingFlow != null && !existingFlow.isExpired()) {
 				log.debug("Found existing flow {}", 
-						HexString.toHexString(existingFlowId));
+						HexString.toHexString(existingFlow.flowId));
 				
 				OFPacketOut po = constructPacketOut(pi, sw);
-				waitingPackets.put(existingFlowId, new PacketToPush(po, sw.getId()));
+				
+				if (existingFlow.firstHopOutPort != OFPort.OFPP_NONE.getValue()) {
+					// Flow has been sent to the switches so it is safe to
+					// send a packet out now
+					sendPacketOut(sw, po, existingFlow.firstHopOutPort);
+				}
+				else {
+					// Flow has not yet been sent to switches so save the
+					// packet out for later
+					waitingPackets.put(existingFlow.flowId, 
+							new PacketToPush(po, sw.getId()));
+				}
 				return;
 			}
 			
+			//log.debug("Couldn't match {} in {}", pathspec, pendingFlows);
+			
 			log.debug("Adding new flow between {} at {} and {} at {}",
 					new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
 			
@@ -338,11 +397,14 @@
 			reverseFlowPath.setFlowId(reverseFlowId);
 			
 			OFPacketOut po = constructPacketOut(pi, sw);
-			Path reversePathSpec = new Path(dstSwitchPort, srcSwitchPort);
+			Path reversePathSpec = new Path(dstSwitchPort, srcSwitchPort, 
+					dstMacAddress, srcMacAddress);
 			
 			// Add to waiting lists
-			pendingFlows.put(pathspec, flowId.value());
-			pendingFlows.put(reversePathSpec, reverseFlowId.value());
+			//pendingFlows.put(pathspec, flowId.value());
+			//pendingFlows.put(reversePathSpec, reverseFlowId.value());
+			pendingFlows.put(pathspec, new PushedFlow(flowId.value()));
+			pendingFlows.put(reversePathSpec, new PushedFlow(reverseFlowId.value()));
 			waitingPackets.put(flowId.value(), new PacketToPush(po, sw.getId()));
 		
 		}
@@ -407,33 +469,44 @@
 	}
 
 	private void flowInstalled(FlowPath installedFlowPath) {
-		// TODO check concurrency
-		// will need to sync and access both collections at once.
 		long flowId = installedFlowPath.flowId().value();
 		
+		short outPort = 
+				installedFlowPath.flowEntries().get(0).outPort().value();
+		
+		MACAddress srcMacAddress = installedFlowPath.flowEntryMatch().srcMac();
+		MACAddress dstMacAddress = installedFlowPath.flowEntryMatch().dstMac();
+		
 		Collection<PacketToPush> packets;
 		synchronized (lock) {
+			log.debug("Flow {} has been installed, sending queued packets",
+					installedFlowPath.flowId());
+			
 			packets = waitingPackets.removeAll(flowId);
 			
-			//remove pending flows entry
-			Path pathToRemove = new Path(installedFlowPath.dataPath().srcPort(),
-					installedFlowPath.dataPath().dstPort());
-			pendingFlows.remove(pathToRemove);
-			
+			// remove pending flows entry
+			Path installedPath = new Path(installedFlowPath.dataPath().srcPort(),
+					installedFlowPath.dataPath().dstPort(),
+					srcMacAddress, dstMacAddress);
+			//pendingFlows.remove(pathToRemove);
+			PushedFlow existingFlow = pendingFlows.get(installedPath);
+			if (existingFlow != null)
+			    existingFlow.firstHopOutPort = outPort;
 		}
 		
 		for (PacketToPush packet : packets) {
 			IOFSwitch sw = floodlightProvider.getSwitches().get(packet.dpid);
 			
-			OFPacketOut po = packet.packet;
-			short outPort = 
-					installedFlowPath.flowEntries().get(0).outPort().value();
-			po.getActions().add(new OFActionOutput(outPort));
-			po.setActionsLength((short)
-					(po.getActionsLength() + OFActionOutput.MINIMUM_LENGTH));
-			po.setLengthU(po.getLengthU() + OFActionOutput.MINIMUM_LENGTH);
-			
-			flowPusher.add(sw, po);
+			sendPacketOut(sw, packet.packet, outPort);
 		}
 	}
+	
+	private void sendPacketOut(IOFSwitch sw, OFPacketOut po, short outPort) {
+		po.getActions().add(new OFActionOutput(outPort));
+		po.setActionsLength((short)
+				(po.getActionsLength() + OFActionOutput.MINIMUM_LENGTH));
+		po.setLengthU(po.getLengthU() + OFActionOutput.MINIMUM_LENGTH);
+		
+		flowPusher.add(sw, po);
+	}
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java
index 8eae558..4350ba6 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/linkdiscovery/web/LinkDiscoveryWebRoutable.java
@@ -12,6 +12,7 @@
     @Override
     public Router getRestlet(Context context) {
         Router router = new Router(context);
+        router.attach("/links/json", LinksResource.class);
         router.attach("/autoportfast/{state}/json", AutoPortFast.class); // enable/true or disable/false
         return router;
     }
@@ -21,6 +22,6 @@
      */
     @Override
     public String basePath() {
-        return "/wm/linkdiscovery";
+        return "/wm/onos/linkdiscovery";
     }
 }
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java
index ee8f23d..44b9ea0 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ArpMessage.java
@@ -4,38 +4,40 @@
 import java.net.InetAddress;
 import net.floodlightcontroller.util.MACAddress;
 
+// TODO This is getting very messy!!! Needs refactoring
 public class ArpMessage implements Serializable {
 
-	/**
-	 * 
-	 */
 	private static final long serialVersionUID = 1L;
 	
 	private final Type type;
 	private final InetAddress forAddress;
 	private final byte[] packetData;
 	
-	//ARP reply message needs MAC info
+	// ARP reply message needs MAC info
 	private final MACAddress mac;
-	//only send the ARP request message to the device attachment needs the attachment switch and port. 
+	// Only send the ARP request message to the device attachment needs the 
+	// attachment switch and port. 
 	private final long outSwitch; 
 	private final short outPort;
 	
-
+	private final long inSwitch;
+	private final short inPort;
 
 	public enum Type {
 		REQUEST,
 		REPLY
 	}
 	
-	private ArpMessage(Type type, InetAddress address, byte[] eth) {
-		// TODO Auto-generated constructor stub
+	private ArpMessage(Type type, InetAddress address, byte[] eth, 
+			long outSwitch, short outPort, long inSwitch, short inPort) {
 		this.type = type;
 		this.forAddress = address;
 		this.packetData = eth;
 		this.mac = null;
 		this.outSwitch = -1;
 		this.outPort = -1;
+		this.inSwitch = inSwitch;
+		this.inPort = inPort;
 	}
 	
 	private ArpMessage(Type type, InetAddress address) {
@@ -46,6 +48,8 @@
 		this.outSwitch = -1;
 		this.outPort = -1;
 		
+		this.inSwitch = -1;
+		this.inPort = -1;
 	}
 	// the ARP reply message with MAC
 	private ArpMessage(Type type, InetAddress address, MACAddress mac) {
@@ -55,6 +59,9 @@
 		this.mac = mac;
 		this.outSwitch = -1;
 		this.outPort = -1;
+		
+		this.inSwitch = -1;
+		this.inPort = -1;
 	}
 	
 	// construct ARP request message with attachment switch and port
@@ -66,24 +73,32 @@
 		this.mac = null;
 		this.outSwitch = outSwitch; 
 		this.outPort = outPort;	
+		
+		this.inSwitch = -1;
+		this.inPort = -1;
 	}
 
-	public static ArpMessage newRequest(InetAddress forAddress, byte[] arpRequest) {
-		return new ArpMessage(Type.REQUEST, forAddress, arpRequest);
+	// TODO Awful quick fix - caller has to supply dummy outSwitch and outPort
+	public static ArpMessage newRequest(InetAddress forAddress, byte[] arpRequest,
+			long outSwitch, short outPort, long inSwitch, short inPort) {
+		return new ArpMessage(Type.REQUEST, forAddress, arpRequest, 
+				outSwitch, outPort, inSwitch, inPort);
 	}
 	
 	public static ArpMessage newReply(InetAddress forAddress) {
 		return new ArpMessage(Type.REPLY, forAddress);
 	}
+	
 	//ARP reply message with MAC
 	public static ArpMessage newReply(InetAddress forAddress, MACAddress mac) {
 		return new ArpMessage(Type.REPLY, forAddress, mac);
-
 	}
-	//ARP reqsuest message with attachment switch and port
-	public static ArpMessage newRequest(InetAddress forAddress, byte[] arpRequest, long outSwitch, short outPort ) {
-		return new ArpMessage(Type.REQUEST, forAddress, arpRequest, outSwitch, outPort);
-
+	
+	//ARP request message with attachment switch and port
+	public static ArpMessage newRequest(InetAddress forAddress, 
+			byte[] arpRequest, long outSwitch, short outPort ) {
+		return new ArpMessage(Type.REQUEST, forAddress, arpRequest, outSwitch, 
+				outPort);
 	}
 
 	public Type getType() {
@@ -97,6 +112,7 @@
 	public byte[] getPacket() {
 		return packetData;
 	}
+	
 	public MACAddress getMAC() {
 		return mac;
 	}
@@ -108,5 +124,12 @@
 	public short getOutPort() {
 		return outPort;
 	}
+	
+	public long getInSwitch() {
+		return inSwitch;
+	}
 
+	public short getInPort() {
+		return inPort;
+	}
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index 5e0b752..9d9e36d 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -63,7 +63,7 @@
 	
 	private final long ARP_TIMER_PERIOD = 100; //ms  
 
-	private static final int ARP_REQUEST_TIMEOUT = 500; //ms
+	private static final int ARP_REQUEST_TIMEOUT = 2000; //ms
 			
 	private IFloodlightProviderService floodlightProvider;
 	private ITopologyService topology;
@@ -77,7 +77,7 @@
 	private short vlan;
 	private static final short NO_VLAN = 0;
 	
-	private ArpCache arpCache;
+	//private ArpCache arpCache;
 
 	private SetMultimap<InetAddress, ArpRequest> arpRequests;
 	
@@ -165,7 +165,7 @@
 		this.configService = context.getServiceImpl(IConfigInfoService.class);
 		this.restApi = context.getServiceImpl(IRestApiService.class);
 		
-		arpCache = new ArpCache();
+		//arpCache = new ArpCache();
 
 		arpRequests = Multimaps.synchronizedSetMultimap(
 				HashMultimap.<InetAddress, ArpRequest>create());
@@ -207,10 +207,7 @@
 
 		//Have to synchronize externally on the Multimap while using an iterator,
 		//even though it's a synchronizedMultimap
-		synchronized (arpRequests) {
-			//log.debug("Current have {} outstanding requests", 
-					//arpRequests.size());
-			
+		synchronized (arpRequests) {			
 			Iterator<Map.Entry<InetAddress, ArpRequest>> it 
 				= arpRequests.entries().iterator();
 			
@@ -222,14 +219,15 @@
 					log.debug("Cleaning expired ARP request for {}", 
 							entry.getKey().getHostAddress());
 		
-					//if he ARP Request is expired and then delete the device
+					// If the ARP request is expired and then delete the device
+					// TODO check whether this is OK from this thread
 					IDeviceObject targetDevice = 
 							deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(entry.getKey()));
 					
-					if(targetDevice!=null)
-					{deviceStorage.removeDevice(targetDevice);
-					 log.debug("RemoveDevice: {} due to no have not recieve the ARP reply", targetDevice.toString());
-					}				
+					if (targetDevice != null) {
+						deviceStorage.removeDevice(targetDevice);
+						log.debug("RemoveDevice: {} due to no have not recieve the ARP reply", targetDevice.toString());
+					}
 					
 					it.remove();
 					
@@ -263,7 +261,7 @@
 	@Override
 	public boolean isCallbackOrderingPrereq(OFType type, String name) {
 		if (type == OFType.PACKET_IN) {
-			return "devicemanager".equals(name);
+			return "devicemanager".equals(name) || "onosdevicemanager".equals(name);
 		}
 		else {
 			return false;
@@ -272,7 +270,7 @@
 
 	@Override
 	public boolean isCallbackOrderingPostreq(OFType type, String name) {
-		return false;
+		return type == OFType.PACKET_IN && "onosforwarding".equals(name);
 	}
 
 	@Override
@@ -287,17 +285,11 @@
 		if (eth.getEtherType() == Ethernet.TYPE_ARP){
 			ARP arp = (ARP) eth.getPayload();	
 			if (arp.getOpCode() == ARP.OP_REQUEST) {
-				log.debug("receive ARP request");
-				//TODO check what the DeviceManager does about propagating
-				//or swallowing ARPs. We want to go after DeviceManager in the
-				//chain but we really need it to CONTINUE ARP packets so we can
-				//get them.
 				handleArpRequest(sw, pi, arp, eth);
 			}
 			else if (arp.getOpCode() == ARP.OP_REPLY) {
-					log.debug("receive ARP reply");
-					handleArpReply(sw, pi, arp);
-					sendToOtherNodesReply(eth, pi);
+				handleArpReply(sw, pi, arp);
+				sendToOtherNodesReply(eth, pi);
 			}
 			
 			// Stop ARP packets here
@@ -337,20 +329,30 @@
 		}
 		
 		//MACAddress macAddress = arpCache.lookup(target);
-				
-		IDeviceObject targetDevice = 
-				deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(target));
-		log.debug("targetDevice: {}", targetDevice);
 
 		arpRequests.put(target, new ArpRequest(
 				new HostArpRequester(arp, sw.getId(), pi.getInPort()), false));
 
-		if (targetDevice != null) {
-			// Even the device in our database is not null, we do not reply to the request directly, but to check whether the device is still valid
+		IDeviceObject targetDevice = 
+				deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(target));
+		
+		if (targetDevice == null) {
+			if (log.isTraceEnabled()) {
+				log.trace("No device info found for {} - broadcasting",
+						target.getHostAddress());
+			}
+			
+			// We don't know the device so broadcast the request out
+			sendToOtherNodes(eth, sw.getId(), pi);
+		}
+		else {
+			// Even if the device exists in our database, we do not reply to
+			// the request directly, but check whether the device is still valid
 			MACAddress macAddress = MACAddress.valueOf(targetDevice.getMACAddress());
 
 			if (log.isTraceEnabled()) {
-				log.trace("The target Device Record in DB is: {} => {} from ARP request host at {}/{}", new Object [] {
+				log.trace("The target Device Record in DB is: {} => {} from ARP request host at {}/{}", 
+						new Object [] {
 						inetAddressToString(arp.getTargetProtocolAddress()),
 						macAddress.toString(),
 						HexString.toHexString(sw.getId()), pi.getInPort()});
@@ -359,41 +361,38 @@
 			// sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
 
 			log.trace("Checking the device info from DB is still valid or not");
-			Iterable<IPortObject> outPorts=targetDevice.getAttachedPorts();	
+			Iterable<IPortObject> outPorts = targetDevice.getAttachedPorts();	
 
-			if(!outPorts.iterator().hasNext()){
-				log.debug("outPort : null");
-				sendToOtherNodes(eth, pi);
-			}else{
-
+			if (!outPorts.iterator().hasNext()){
+				if (log.isTraceEnabled()) {
+					log.trace("Device {} exists but is not connected to any ports" + 
+							" - broadcasting", macAddress);
+				}
+				
+				sendToOtherNodes(eth, sw.getId(), pi);
+			} 
+			else {
 				for (IPortObject portObject : outPorts) {
-					long outSwitch=0;
-					short outPort=0;   
-
+					long outSwitch = 0;
+					short outPort = 0;
 
 					if (!portObject.getLinkedPorts().iterator().hasNext()) {
-						outPort=portObject.getNumber();					
-						log.debug("outPort:{} ", outPort);
-					}   
-
-					Iterable<ISwitchObject>  outSwitches= targetDevice.getSwitch(); 
-
-					for (ISwitchObject outswitch : outSwitches) {
-
-						outSwitch= HexString.toLong(outswitch.getDPID());
-						log.debug("outSwitch.DPID:{}; outPort: {}", outswitch.getDPID(), outPort );
-						sendToOtherNodes( eth, pi, outSwitch, outPort);
+						outPort = portObject.getNumber();					
 					}
+
+					ISwitchObject outSwitchObject = portObject.getSwitch();
+					outSwitch = HexString.toLong(outSwitchObject.getDPID());
+
+					if (log.isTraceEnabled()) {
+						log.trace("Probing device {} on port {}/{}", 
+								new Object[] {macAddress, 
+								HexString.toHexString(outSwitch), outPort});
+					}
+					
+					sendToOtherNodes(eth, pi, outSwitch, outPort);
 				}
 			}
-
-		}else {
-			log.debug("The Device info in DB is {} for IP {}", targetDevice, inetAddressToString(arp.getTargetProtocolAddress()));
-
-			// We don't know the device so broadcast the request out
-			sendToOtherNodes(eth, pi);
 		}
- 
 	}
 	
 	private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp){
@@ -516,7 +515,7 @@
 		}
 	}
 	
-	private void sendToOtherNodes(Ethernet eth, OFPacketIn pi) {
+	private void sendToOtherNodes(Ethernet eth, long inSwitchId, OFPacketIn pi) {
 		ARP arp = (ARP) eth.getPayload();
 		
 		if (log.isTraceEnabled()) {
@@ -532,24 +531,25 @@
 			return;
 		}
 		
-		datagrid.sendArpRequest(ArpMessage.newRequest(targetAddress, eth.serialize()));
+		datagrid.sendArpRequest(ArpMessage.newRequest(targetAddress, eth.serialize(),
+				-1L, (short)-1, inSwitchId, pi.getInPort()));
 	}
+	
 	//hazelcast to other ONOS instances to send the ARP packet out on outPort of outSwitch
 	private void sendToOtherNodes(Ethernet eth, OFPacketIn pi, long outSwitch, short outPort) {
 		ARP arp = (ARP) eth.getPayload();
 		
 		if (log.isTraceEnabled()) {
-				log.trace("Sending ARP request for {} to other ONOS instances with outSwitch {} ",
-				inetAddressToString(arp.getTargetProtocolAddress()), String.valueOf(outSwitch));
-			
+			log.trace("Sending ARP request for {} to other ONOS instances with outSwitch {} ",
+					inetAddressToString(arp.getTargetProtocolAddress()), String.valueOf(outSwitch));
 		}
 		
 		InetAddress targetAddress;
 		try {
-				targetAddress = InetAddress.getByAddress(arp.getTargetProtocolAddress());
+			targetAddress = InetAddress.getByAddress(arp.getTargetProtocolAddress());
 		} catch (UnknownHostException e) {
-				log.error("Unknown host", e);
-				return;
+			log.error("Unknown host", e);
+			return;
 		}
 		
 		datagrid.sendArpRequest(ArpMessage.newRequest(targetAddress, eth.serialize(), outSwitch, outPort)); 
@@ -557,25 +557,26 @@
 		
 		
 	}
+	
 	private void sendToOtherNodesReply(Ethernet eth, OFPacketIn pi) {
 		ARP arp = (ARP) eth.getPayload();
 		
 		if (log.isTraceEnabled()) {
-				log.trace("Sending ARP reply for {} to other ONOS instances",
-				inetAddressToString(arp.getSenderProtocolAddress()));
+			log.trace("Sending ARP reply for {} to other ONOS instances",
+					inetAddressToString(arp.getSenderProtocolAddress()));
 		}
 		
 		InetAddress targetAddress;		
 		MACAddress mac = new MACAddress(arp.getSenderHardwareAddress());
 		
 		try {
-				targetAddress = InetAddress.getByAddress(arp.getSenderProtocolAddress());
+			targetAddress = InetAddress.getByAddress(arp.getSenderProtocolAddress());
 		} catch (UnknownHostException e) {
-				log.error("Unknown host", e);
-				return;
+			log.error("Unknown host", e);
+			return;
 		}
 		
-		datagrid.sendArpRequest(ArpMessage.newReply(targetAddress,mac));
+		datagrid.sendArpRequest(ArpMessage.newReply(targetAddress, mac));
 		//datagrid.sendArpReply(ArpMessage.newRequest(targetAddress, eth.serialize()));
 	
 	}
@@ -628,7 +629,8 @@
 		}
 	}
 	
-	private void broadcastArpRequestOutMyEdge(byte[] arpRequest) {
+	private void broadcastArpRequestOutMyEdge(byte[] arpRequest,
+			long inSwitch, short inPort) {
 		List<SwitchPort> switchPorts = new ArrayList<SwitchPort>();
 		
 		for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
@@ -648,9 +650,17 @@
 			
 			for (IPortObject portObject : ports) {
 				if (!portObject.getLinkedPorts().iterator().hasNext()) {
+					short portNumber = portObject.getNumber();
+					
+					if (sw.getId() == inSwitch && portNumber == inPort) {
+						// This is the port that the ARP message came in,
+						// so don't broadcast out this port
+						continue;
+					}
+					
 					switchPorts.add(new SwitchPort(new Dpid(sw.getId()), 
-							new Port(portObject.getNumber())));
-					actions.add(new OFActionOutput(portObject.getNumber()));
+							new Port(portNumber)));
+					actions.add(new OFActionOutput(portNumber));
 				}
 			}
 			
@@ -669,7 +679,9 @@
 			}
 		}
 		
-		log.debug("Broadcast ARP request to: {}", switchPorts);
+		if (log.isTraceEnabled()) {
+			log.trace("Broadcast ARP request to: {}", switchPorts);
+		}
 	}
 	
 	private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
@@ -784,7 +796,8 @@
 
 	@Override
 	public MACAddress getMacAddress(InetAddress ipAddress) {
-		return arpCache.lookup(ipAddress);
+		//return arpCache.lookup(ipAddress);
+		return null;
 	}
 
 	@Override
@@ -800,7 +813,8 @@
 	
 	@Override
 	public List<String> getMappings() {
-		return arpCache.getMappings();
+		//return arpCache.getMappings();
+		return new ArrayList<String>();
 	}
 
 	/*
@@ -814,7 +828,8 @@
 		switch (arpMessage.getType()){
 		case REQUEST:
 			if(arpMessage.getOutSwitch() == -1 || arpMessage.getOutPort() == -1){	
-				broadcastArpRequestOutMyEdge(arpMessage.getPacket());					
+				broadcastArpRequestOutMyEdge(arpMessage.getPacket(),
+						arpMessage.getInSwitch(), arpMessage.getInPort());					
 			}else{					
 				sendArpRequestOutPort(arpMessage.getPacket(),arpMessage.getOutSwitch(),arpMessage.getOutPort());
 				log.debug("OutSwitch in ARP request message is: {}; OutPort in ARP request message is: {}",arpMessage.getOutSwitch(),arpMessage.getOutPort());
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/ShortestPath.java b/src/main/java/net/onrc/onos/ofcontroller/topology/ShortestPath.java
index a4a2be3..d9e1314 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/ShortestPath.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/ShortestPath.java
@@ -69,8 +69,11 @@
 	//
 	// Test whether we are computing a path from/to the same DPID.
 	// If "yes", then just add a single flow entry in the return result.
+	// However, if the "in" and "out" ports are same, return null.
 	//
 	if (dpid_src.equals(dpid_dest)) {
+	    if (src.port().value() == dest.port().value())
+		return null;		// "In" and "Out" ports are same
 	    FlowEntry flowEntry = new FlowEntry();
 	    flowEntry.setDpid(src.dpid());
 	    flowEntry.setInPort(src.port());
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
index 6b2ab99..570e94f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/TopologyManager.java
@@ -10,12 +10,13 @@
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
-
+import net.floodlightcontroller.restserver.IRestApiService;
 import net.onrc.onos.datagrid.IDatagridService;
 import net.onrc.onos.graph.DBOperation;
 import net.onrc.onos.graph.GraphDBManager;
 import net.onrc.onos.graph.GraphDBOperation;
 import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
+import net.onrc.onos.ofcontroller.topology.web.OnosTopologyWebRoutable;
 import net.onrc.onos.ofcontroller.util.DataPath;
 import net.onrc.onos.ofcontroller.util.FlowEntry;
 import net.onrc.onos.ofcontroller.util.FlowPath;
@@ -40,6 +41,7 @@
     protected static final String GraphDBStore = "graph_db_store";
 
     protected DBOperation dbHandler;
+    protected IRestApiService restApi;
 
 
     /**
@@ -154,6 +156,7 @@
     public void init(FloodlightModuleContext context)
 	throws FloodlightModuleException {
 	floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+	restApi = context.getServiceImpl(IRestApiService.class);
 	Map<String, String> configMap = context.getConfigParams(this);
 	String conf = configMap.get(DBConfigFile);
         String dbStore = configMap.get(GraphDBStore);
@@ -167,6 +170,7 @@
      */
     @Override
     public void startUp(FloodlightModuleContext context) {
+    	restApi.addRestletRoutable(new OnosTopologyWebRoutable());
 
     }
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/topology/web/OnosTopologyWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/topology/web/OnosTopologyWebRoutable.java
new file mode 100644
index 0000000..90eed9a
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/topology/web/OnosTopologyWebRoutable.java
@@ -0,0 +1,29 @@
+package net.onrc.onos.ofcontroller.topology.web;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+import net.onrc.onos.graph.web.TopoDevicesResource;
+import net.onrc.onos.ofcontroller.core.web.TopoLinksResource;
+import net.onrc.onos.ofcontroller.core.web.TopoSwitchesResource;
+
+public class OnosTopologyWebRoutable implements RestletRoutable {
+
+	@Override
+	public Restlet getRestlet(Context context) {
+        Router router = new Router(context);
+        router.attach("/route/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", RouteResource.class);
+        router.attach("/switches/{filter}/json", TopoSwitchesResource.class);
+        router.attach("/links/json", TopoLinksResource.class);
+        router.attach("/devices/json", TopoDevicesResource.class);
+		return router;
+	}
+
+	@Override
+	public String basePath() {
+        return "/wm/onos/topology";
+	}
+
+}
diff --git a/src/main/java/net/onrc/onos/registry/controller/StandaloneRegistry.java b/src/main/java/net/onrc/onos/registry/controller/StandaloneRegistry.java
index b6d980a..82af20c 100644
--- a/src/main/java/net/onrc/onos/registry/controller/StandaloneRegistry.java
+++ b/src/main/java/net/onrc/onos/registry/controller/StandaloneRegistry.java
@@ -11,6 +11,7 @@
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.restserver.IRestApiService;
+import net.onrc.onos.registry.controller.web.RegistryWebRoutable;
 
 import org.openflow.util.HexString;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java b/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java
index 50ee137..b03aea2 100644
--- a/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java
+++ b/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java
@@ -15,6 +15,7 @@
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.restserver.IRestApiService;
+import net.onrc.onos.registry.controller.web.RegistryWebRoutable;
 
 import org.openflow.util.HexString;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/registry/controller/ControllerRegistryResource.java b/src/main/java/net/onrc/onos/registry/controller/web/ControllerRegistryResource.java
similarity index 83%
rename from src/main/java/net/onrc/onos/registry/controller/ControllerRegistryResource.java
rename to src/main/java/net/onrc/onos/registry/controller/web/ControllerRegistryResource.java
index 8660688..676bcb3 100644
--- a/src/main/java/net/onrc/onos/registry/controller/ControllerRegistryResource.java
+++ b/src/main/java/net/onrc/onos/registry/controller/web/ControllerRegistryResource.java
@@ -1,8 +1,11 @@
-package net.onrc.onos.registry.controller;
+package net.onrc.onos.registry.controller.web;
 
 import java.util.ArrayList;
 import java.util.Collection;
 
+import net.onrc.onos.registry.controller.IControllerRegistryService;
+import net.onrc.onos.registry.controller.RegistryException;
+
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 import org.slf4j.Logger;
diff --git a/src/main/java/net/onrc/onos/registry/controller/RegistryWebRoutable.java b/src/main/java/net/onrc/onos/registry/controller/web/RegistryWebRoutable.java
similarity index 86%
rename from src/main/java/net/onrc/onos/registry/controller/RegistryWebRoutable.java
rename to src/main/java/net/onrc/onos/registry/controller/web/RegistryWebRoutable.java
index 74dede4..77dd72d 100644
--- a/src/main/java/net/onrc/onos/registry/controller/RegistryWebRoutable.java
+++ b/src/main/java/net/onrc/onos/registry/controller/web/RegistryWebRoutable.java
@@ -1,4 +1,4 @@
-package net.onrc.onos.registry.controller;
+package net.onrc.onos.registry.controller.web;
 
 import net.floodlightcontroller.restserver.RestletRoutable;
 
@@ -18,7 +18,7 @@
 
 	@Override
 	public String basePath() {
-		return "/wm/registry";
+		return "/wm/onos/registry";
 	}
 
 }
diff --git a/src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java b/src/main/java/net/onrc/onos/registry/controller/web/SwitchRegistryResource.java
similarity index 79%
rename from src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java
rename to src/main/java/net/onrc/onos/registry/controller/web/SwitchRegistryResource.java
index 599a1af..21b0c09 100644
--- a/src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java
+++ b/src/main/java/net/onrc/onos/registry/controller/web/SwitchRegistryResource.java
@@ -1,9 +1,12 @@
-package net.onrc.onos.registry.controller;
+package net.onrc.onos.registry.controller.web;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import net.onrc.onos.registry.controller.ControllerRegistryEntry;
+import net.onrc.onos.registry.controller.IControllerRegistryService;
+
 import org.restlet.resource.Get;
 import org.restlet.resource.ServerResource;
 
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 a842665..dfd31ab 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
@@ -1,6 +1,5 @@
 net.floodlightcontroller.core.FloodlightProvider
 net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher
-net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl
 net.onrc.onos.ofcontroller.linkdiscovery.internal.LinkDiscoveryManager
 net.floodlightcontroller.topology.TopologyManager
 net.floodlightcontroller.forwarding.Forwarding
@@ -21,3 +20,4 @@
 net.onrc.onos.ofcontroller.forwarding.Forwarding
 net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager
 net.onrc.onos.ofcontroller.core.config.DefaultConfiguration
+net.onrc.onos.ofcontroller.devicemanager.OnosDeviceManager
diff --git a/start-onos.sh b/start-onos.sh
index 1f67368..a9d4d64 100755
--- a/start-onos.sh
+++ b/start-onos.sh
@@ -1,21 +1,21 @@
 #!/bin/bash
 
 # Set paths
-if [ -z "${ONOS_HOME}" ]; then
-        ONOS_HOME=`dirname $0`
-fi
+ONOS_HOME="${ONOS_HOME:-`dirname $0`}"
 
 ## Because the script change dir to $ONOS_HOME, we can set ONOS_LOGBACK and LOGDIR relative to $ONOS_HOME
-#ONOS_LOGBACK="${ONOS_HOME}/logback.`hostname`.xml"
-#LOGDIR=${ONOS_HOME}/onos-logs
-ONOS_LOGBACK="./logback.`hostname`.xml"
-LOGDIR=./onos-logs
+ONOS_LOGBACK=${ONOS_LOGBACK:-${ONOS_HOME}/logback.`hostname`.xml}
+LOGDIR=${ONOS_LOGDIR:-${ONOS_HOME}/onos-logs}
+
 ONOS_LOG="${LOGDIR}/onos.`hostname`.log"
 PCAP_LOG="${LOGDIR}/onos.`hostname`.pcap"
 LOGS="$ONOS_LOG $PCAP_LOG"
 
+ONOS_PROPS=${ONOS_PROPS:-${ONOS_HOME}/conf/onos.properties}
+JMX_PORT=${JMX_PORT:-7189}
+
 # Set JVM options
-JVM_OPTS=""
+JVM_OPTS="${JVM_OPTS:-}"
 ## If you want JaCoCo Code Coverage reports... uncomment line below
 #JVM_OPTS="$JVM_OPTS -javaagent:${ONOS_HOME}/lib/jacocoagent.jar=dumponexit=true,output=file,destfile=${LOGDIR}/jacoco.exec"
 JVM_OPTS="$JVM_OPTS -server -d64"
@@ -31,7 +31,7 @@
 		-XX:+UseThreadPriorities \
 		-XX:ThreadPriorityPolicy=42 \
 		-XX:+UseCompressedOops \
-		-Dcom.sun.management.jmxremote.port=7189 \
+		-Dcom.sun.management.jmxremote.port=$JMX_PORT \
 		-Dcom.sun.management.jmxremote.ssl=false \
 		-Dcom.sun.management.jmxremote.authenticate=false"
 JVM_OPTS="$JVM_OPTS -Dhazelcast.logging.type=slf4j"
@@ -39,9 +39,7 @@
 # Set ONOS core main class
 MAIN_CLASS="net.onrc.onos.ofcontroller.core.Main"
 
-if [ -z "${MVN}" ]; then
-    MVN="mvn -o"
-fi
+MVN=${MVN:-mvn -o}
 
 #<logger name="net.floodlightcontroller.linkdiscovery.internal" level="TRACE"/>
 #<appender-ref ref="STDOUT" />
@@ -101,15 +99,15 @@
 
   # Run ONOS
   echo "Starting ONOS controller ..."
-  echo 
+  echo
 
-  # XXX : MVN has to run at the project top dir 
+  # XXX : MVN has to run at the project top dir
   echo $ONOS_HOME
   cd ${ONOS_HOME}
-  pwd 
-  echo "${MVN} exec:exec -Dexec.executable=\"java\" -Dexec.args=\"${JVM_OPTS} -Dlogback.configurationFile=${ONOS_LOGBACK} -cp %classpath ${MAIN_CLASS} -cf ./conf/onos.properties\""
+  pwd
+  echo "${MVN} exec:exec -Dexec.executable=\"java\" -Dexec.args=\"${JVM_OPTS} -Dlogback.configurationFile=${ONOS_LOGBACK} -cp %classpath ${MAIN_CLASS} -cf ${ONOS_PROPS}\""
 
-  ${MVN} exec:exec -Dexec.executable="java" -Dexec.args="${JVM_OPTS} -Dlogback.configurationFile=${ONOS_LOGBACK} -cp %classpath ${MAIN_CLASS} -cf ./conf/onos.properties" > ${LOGDIR}/onos.`hostname`.stdout 2>${LOGDIR}/onos.`hostname`.stderr &
+  ${MVN} exec:exec -Dexec.executable="java" -Dexec.args="${JVM_OPTS} -Dlogback.configurationFile=${ONOS_LOGBACK} -cp %classpath ${MAIN_CLASS} -cf ${ONOS_PROPS}" > ${LOGDIR}/onos.`hostname`.stdout 2>${LOGDIR}/onos.`hostname`.stderr &
 
   echo "Waiting for ONOS to start..."
   COUNT=0
@@ -160,14 +158,18 @@
 case "$1" in
   start)
     stop
-#    check_db
-    start 
+    check_db
+    start
+    ;;
+  startnokill)
+    check_db
+    start
     ;;
   startifdown)
     n=`jps -l |grep "${MAIN_CLASS}" | wc -l`
     if [ $n == 0 ]; then
       start
-    else 
+    else
       echo "$n instance of onos running"
     fi
     ;;
diff --git a/vm-utils/onos.py b/vm-utils/onos.py
new file mode 100755
index 0000000..8283a66
--- /dev/null
+++ b/vm-utils/onos.py
@@ -0,0 +1,318 @@
+#!/usr/bin/env python
+
+"""
+onos.py: A basic (?) ONOS Controller() subclass for Mininet
+
+We implement the following classes:
+
+ONOSController: a custom Controller() subclass to start ONOS
+OVSSwitchONOS: a custom OVSSwitch() switch that connects to multiple controllers.
+
+We use single Zookeeper and Cassandra instances for now.
+
+As a custom file, exports:
+
+--controller onos
+--switch ovso
+
+Usage:
+
+$ sudo ./onos.py
+
+This will start up a simple 2-host, 2 ONOS network
+
+$ sudo mn --custom onos.py --controller onos,2 --switch ovso
+"""
+
+from mininet.node import Controller, OVSSwitch
+from mininet.net import Mininet
+from mininet.cli import CLI
+from mininet.topo import LinearTopo
+from mininet.log import setLogLevel, info, warn
+from mininet.util import quietRun
+
+# This should be cleaned up to avoid interfering with mn
+from shutil import copyfile
+from os import environ
+from functools import partial
+import time
+from sys import argv
+
+class ONOS( Controller ):
+    "Custom controller class for ONOS"
+
+    # Directories and configuration templates
+    home = environ[ 'HOME' ]
+    onosDir = home + "/ONOS"
+    zookeeperDir = home + "/zookeeper-3.4.5"
+    dirBase = '/tmp'
+    logDir = dirBase + '/onos-%s.logs'
+    # cassDir = dirBase + '/onos-%s.cassandra'
+    configFile = dirBase + '/onos-%s.properties'
+    logbackFile = dirBase + '/onos-%s.logback.xml'
+
+    # Base ONOS modules
+    baseModules = (
+        'net.floodlightcontroller.core.FloodlightProvider',
+        'net.floodlightcontroller.threadpool.ThreadPool',
+        'net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher',
+        'net.floodlightcontroller.ui.web.StaticWebRoutable',
+        'net.onrc.onos.datagrid.HazelcastDatagrid',
+        'net.onrc.onos.ofcontroller.flowmanager.FlowManager',
+        'net.onrc.onos.ofcontroller.flowprogrammer.FlowProgrammer',
+        'net.onrc.onos.ofcontroller.topology.TopologyManager',
+        'net.onrc.onos.registry.controller.ZookeeperRegistry'
+    )
+
+    # Additions for reactive forwarding
+    reactiveModules = (
+            'net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager',
+            'net.onrc.onos.ofcontroller.core.config.DefaultConfiguration',
+            'net.onrc.onos.ofcontroller.forwarding.Forwarding'
+    )
+
+    # Module parameters
+    ofbase = 6633
+    restbase = 8080
+    jmxbase = 7189
+
+    fc = 'net.floodlightcontroller.'
+
+    perNodeConfigBase = {
+        fc + 'core.FloodlightProvider.openflowport': ofbase,
+        fc + 'restserver.RestApiServer.port': restbase,
+        fc + 'core.FloodlightProvider.controllerid': 0
+    }
+
+    staticConfig = {
+        'net.onrc.onos.ofcontroller.floodlightlistener.NetworkGraphPublisher.dbconf':
+            '/tmp/cassandra.titan',
+        'net.onrc.onos.datagrid.HazelcastDatagrid.datagridConfig':
+            onosDir + '/conf/hazelcast.xml',
+        'net.floodlightcontroller.core.FloodlightProvider.workerthreads': 16,
+        'net.floodlightcontroller.forwarding.Forwarding.idletimeout': 5,
+        'net.floodlightcontroller.forwarding.Forwarding.hardtimeout': 0
+    }
+
+    proctag = 'mn-onos-id'
+
+    # For maven debugging
+    # mvn = 'mvn -o -e -X'
+
+    def __init__( self, name, n=1, reactive=True, runAsRoot=False, **params):
+        """n: number of ONOS instances to run (1)
+           reactive: run in reactive mode (True)
+           runAsRoot: run ONOS as root (False)"""
+        self.check()
+        self.count = n
+        self.reactive = reactive
+        self.runAsRoot = runAsRoot
+        self.ids = range( 0, self.count )
+        Controller.__init__( self, name, **params )
+        # We don't need to run as root, and it can interfere
+        # with starting Zookeeper manually
+        self.user = None
+        if not self.runAsRoot:
+            try:
+                self.user = quietRun( 'who am i' ).split()[ 0 ]
+                self.sendCmd( 'su', self.user )
+                self.waiting = False
+            except:
+                warn( '__init__: failed to drop privileges\n' )
+        # Need to run commands from ONOS dir
+        self.cmd( 'cd', self.onosDir )
+        self.cmd( 'export PATH=$PATH:%s' % self.onosDir )
+        if hasattr( self, 'mvn' ):
+            self.cmd( 'export MVN="%s"' % self.mvn )
+
+    def check( self ):
+        "Check for ONOS prerequisites"
+        if not quietRun( 'which java' ):
+                raise Exception( 'java not found -'
+                                 ' make sure it is installed and in $PATH' )
+        if not quietRun( 'which mvn' ):
+                raise Exception( 'Maven (mvn) not found -'
+                                ' make sure it is installed and in $PATH' )
+
+
+    def waitNetstat( self, pid ):
+        """Wait for pid to show up in netstat
+           We assume that once a process is listening on some
+           port, it is ready to go!"""
+        while True:
+            output = self.cmd( 'sudo netstat -natp | grep %s/' % pid )
+            if output:
+                return output
+            info( '.' )
+            time.sleep( 1 )
+
+    def waitStart( self, procname, pattern ):
+        "Wait for at least one of procname to show up in netstat"
+        info( '* Waiting for %s startup' % procname )
+        result = self.cmd( 'pgrep -f %s' % pattern ).split()[ 0 ]
+        pid = int( result )
+        output = self.waitNetstat( pid )
+        info( '\n* %s process %d is listening\n' % ( procname, pid ) )
+        info( output )
+
+    def startCassandra( self ):
+        "Start Cassandra"
+        self.cmd( 'start-cassandra.sh start' )
+        self.waitStart( 'Cassandra', 'apache-cassandra' )
+        status = self.cmd( 'start-cassandra.sh status' )
+        if 'running' not in status:
+            raise Exception( 'Cassandra startup failed: ' + status )
+
+    def stopCassandra( self ):
+        "Stop Cassandra"
+        self.cmd( 'start-cassandra.sh stop' )
+
+    def startZookeeper( self, initcfg=True ):
+        "Start Zookeeper"
+        # Reinitialize configuration file
+        if initcfg:
+            cfg = self.zookeeperDir + '/conf/zoo.cfg'
+            template = self.zookeeperDir + '/conf/zoo_sample.cfg'
+            copyfile( template, cfg )
+        self.cmd( 'start-zk.sh restart' )
+        self.waitStart( 'Zookeeper', 'zookeeper' )
+        status = self.cmd( 'start-zk.sh status' )
+        if 'Error' in status:
+            raise Exception( 'Zookeeper startup failed: ' + status )
+
+    def stopZookeeper( self ):
+        "Stop Zookeeper"
+        self.cmd( 'start-zk.sh stop' )
+
+    def genProperties( self, id, path='/tmp' ):
+        "Generate ONOS properties file"
+        filename = path + '/onos-%s.properties' % id
+        with open( filename, 'w' ) as f:
+            # Write modules list
+            modules = list( self.baseModules )
+            if self.reactive:
+                modules += list( self.reactiveModules )
+            f.write( 'floodlight.modules = %s\n' %
+                     ',\\\n'.join( modules ) )
+            # Write other parameters
+            for var, val in self.perNodeConfigBase.iteritems():
+                if type( val ) is int:
+                    val += id
+                f.write( '%s = %s\n' % ( var, val ) )
+            for var, val in self.staticConfig.iteritems():
+                f.write( '%s = %s\n' % ( var, val ) )
+        return filename
+
+    def setVars( self, id, propsFile ):
+        """Set and return environment vars
+           id: ONOS instance number
+           propsFile: properties file name"""
+        # ONOS directories and files
+        logdir = self.logDir % id
+        # cassdir = self.cassDir % id
+        logback = self.logbackFile % id
+        jmxport = self.jmxbase + id
+        self.cmd( 'mkdir -p', logdir ) # , cassdir
+        self.cmd( 'export ONOS_LOGDIR="%s"' % logdir )
+        self.cmd( 'export ZOO_LOG_DIR="%s"' % logdir )
+        # self.cmd( 'export CASS_DIR="%s"' % cassdir )
+        self.cmd( 'export ONOS_LOGBACK="%s"' % logback )
+        self.cmd( 'export JMX_PORT=%s' % jmxport )
+        self.cmd( 'export JVM_OPTS="-D%s=%s"' % (
+            self.proctag, id ) )
+        self.cmd( 'export ONOS_PROPS="%s"' % propsFile )
+
+    def startONOS( self, id ):
+        """Start ONOS
+           id: new instance number"""
+        start = time.time()
+        self.stopONOS( id )
+        propsFile = self.genProperties( id )
+        self.setVars( id, propsFile )
+        self.cmdPrint( 'start-onos.sh startnokill' )
+        # start-onos.sh waits for ONOS startup
+        elapsed = time.time() - start
+        info( '* ONOS %s started in %.2f seconds\n' % ( id, elapsed ) )
+
+    def stopONOS( self, id ):
+        """Shut down ONOS
+           id: identifier for instance"""
+        pid = self.cmd( "jps -v | grep %s=%s | awk '{print $1}'" %
+            ( self.proctag, id ) ).strip()
+        if pid:
+            self.cmdPrint( 'kill', pid )
+
+    def start( self, *args ):
+        "Start ONOS instances"
+        info( '* Starting Cassandra\n' )
+        self.startCassandra()
+        info( '* Starting Zookeeper\n' )
+        self.startZookeeper()
+        for id in self.ids:
+            info( '* Starting ONOS %s\n' % id )
+            self.startONOS( id )
+
+    def stop( self, *args ):
+        "Stop ONOS instances"
+        for id in self.ids:
+            info( '* Stopping ONOS %s\n' % id )
+            self.stopONOS( id )
+        info( '* Stopping Zookeeper\n' )
+        self.stopZookeeper()
+        info( '* Stopping Cassandra\n' )
+        self.stopCassandra()
+
+    def clist( self ):
+        "Return list of controller specifiers (proto:ip:port)"
+        return [ 'tcp:127.0.0.1:%s' % ( self.ofbase + id )
+            for id in range( 0, self.count ) ]
+
+
+class OVSSwitchONOS( OVSSwitch ):
+    "OVS switch which connects to multiple controllers"
+    def start( self, controllers ):
+        OVSSwitch.start( self, controllers )
+        assert len( controllers ) == 1
+        c0 = controllers[ 0 ]
+        assert type( c0 ) == ONOS
+        clist = ','.join( c0.clist() )
+        self.cmd( 'ovs-vsctl set-controller', self, clist)
+        # Reconnect quickly to controllers (1s vs. 15s max_backoff)
+        for uuid in self.controllerUUIDs():
+            if uuid.count( '-' ) != 4:
+                # Doesn't look like a UUID
+                continue
+            uuid = uuid.strip()
+            self.cmd( 'ovs-vsctl set Controller', uuid,
+                      'max_backoff=1000' )
+
+
+def waitConnected( switches ):
+    "Wait until all switches connect to controllers"
+    start = time.time()
+    info( '* Waiting for switches to connect...\n' )
+    for s in switches:
+        info( s )
+        while not s.connected():
+            info( '.' )
+            time.sleep( 1 )
+        info( ' ' )
+    elapsed = time.time() - start
+    info( '\n* Connected in %.2f seconds\n' % elapsed )
+
+
+controllers = { 'onos': ONOS }
+switches = { 'ovso': OVSSwitchONOS }
+
+
+if __name__ == '__main__':
+    # Simple test for ONOS() controller class
+    setLogLevel( 'info' )
+    size = 2 if len( argv ) != 2 else int( argv[ 1 ] )
+    net = Mininet( topo=LinearTopo( size ),
+                   controller=partial( ONOS, n=2 ),
+                   switch=OVSSwitchONOS )
+    net.start()
+    waitConnected( net.switches )
+    CLI( net )
+    net.stop()
diff --git a/web/add_flow.py b/web/add_flow.py
index 9690024..6ff250a 100755
--- a/web/add_flow.py
+++ b/web/add_flow.py
@@ -14,7 +14,7 @@
 from flask import Flask, json, Response, render_template, make_response, request
 
 #
-# curl http://127.0.0.1:8080/wm/topology/route/00:00:00:00:00:00:0a:01/1/00:00:00:00:00:00:0a:04/1/json
+# curl http://127.0.0.1:8080/wm/onos/topology/route/00:00:00:00:00:00:0a:01/1/00:00:00:00:00:00:0a:04/1/json
 #
 
 ## Global Var ##
@@ -37,14 +37,14 @@
   if DEBUG:
     print '%s' % (txt)
 
-# @app.route("/wm/topology/route/<srcdpid>/<srcport>/<destdpid>/<destport>/json")
+# @app.route("/wm/onos/topology/route/<srcdpid>/<srcport>/<destdpid>/<destport>/json")
 #
 # Sample output:
 # {'dstPort': {'port': {'value': 0}, 'dpid': {'value': '00:00:00:00:00:00:00:02'}}, 'srcPort': {'port': {'value': 0}, 'dpid': {'value': '00:00:00:00:00:00:00:01'}}, 'flowEntries': [{'outPort': {'value': 1}, 'flowEntryErrorState': None, 'flowEntryMatch': None, 'flowEntryActions': None, 'inPort': {'value': 0}, 'flowEntryId': None, 'flowEntryUserState': 'FE_USER_UNKNOWN', 'dpid': {'value': '00:00:00:00:00:00:00:01'}, 'flowEntrySwitchState': 'FE_SWITCH_UNKNOWN'}, {'outPort': {'value': 0}, 'flowEntryErrorState': None, 'flowEntryMatch': None, 'flowEntryActions': None, 'inPort': {'value': 9}, 'flowEntryId': None, 'flowEntryUserState': 'FE_USER_UNKNOWN', 'dpid': {'value': '00:00:00:00:00:00:00:02'}, 'flowEntrySwitchState': 'FE_SWITCH_UNKNOWN'}]}
 #
 def shortest_path(v1, p1, v2, p2):
   try:
-    command = "curl -s http://%s:%s/wm/topology/route/%s/%s/%s/%s/json" % (ControllerIP, ControllerPort, v1, p1, v2, p2)
+    command = "curl -s http://%s:%s/wm/onos/topology/route/%s/%s/%s/%s/json" % (ControllerIP, ControllerPort, v1, p1, v2, p2)
     debug("shortest_path %s" % command)
     parsedResult = []
 
@@ -82,7 +82,7 @@
   flow_path_json = json.dumps(flow_path)
 
   try:
-    command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/flow/add/json" % (flow_path_json, ControllerIP, ControllerPort)
+    command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/onos/flows/add/json" % (flow_path_json, ControllerIP, ControllerPort)
     debug("add_flow_path %s" % command)
     result = os.popen(command).read()
     debug("result %s" % result)
@@ -96,7 +96,7 @@
   flow_path_json = json.dumps(flow_path)
 
   try:
-    command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/flow/add-shortest-path/json" % (flow_path_json, ControllerIP, ControllerPort)
+    command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/onos/flows/add/json" % (flow_path_json, ControllerIP, ControllerPort)
     debug("add_shortest_path_flow %s" % command)
     result = os.popen(command).read()
     debug("result %s" % result)
@@ -107,7 +107,7 @@
     exit(1)
 
 def delete_flow_path(flow_id):
-  command = "curl -s \"http://%s:%s/wm/flow/delete/%s/json\"" % (ControllerIP, ControllerPort, flow_id)
+  command = "curl -s \"http://%s:%s/wm/onos/flows/delete/%s/json\"" % (ControllerIP, ControllerPort, flow_id)
   debug("delete_flow_path %s" % command)
   result = os.popen(command).read()
   debug("result %s" % result)
diff --git a/web/clear_core.py b/web/clear_core.py
index ea3e964..36eadd6 100755
--- a/web/clear_core.py
+++ b/web/clear_core.py
@@ -23,7 +23,7 @@
 
   try:
     sw_list = json.dumps(core_switches)
-    command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/core/clearflowtable/json" % (sw_list, controllers[0], onos_rest_port)
+    command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/onos/internal/clearflowtable/json" % (sw_list, controllers[0], onos_rest_port)
 
     print command
     result = os.popen(command).read()
diff --git a/web/delete_flow.py b/web/delete_flow.py
index fff9319..d38e915 100755
--- a/web/delete_flow.py
+++ b/web/delete_flow.py
@@ -14,7 +14,7 @@
 
 #
 # TODO: remove this! We don't use JSON argument here!
-# curl http://127.0.0.1:8080/wm/flow/delete/{"value":"0xf"}/json'
+# curl http://127.0.0.1:8080/wm/onos/flows/delete/{"value":"0xf"}/json'
 #
 
 ## Global Var ##
@@ -34,9 +34,9 @@
   if DEBUG:
     print '%s' % (txt)
 
-# @app.route("/wm/flow/delete/<flow-id>/json")
+# @app.route("/wm/onos/flows/delete/<flow-id>/json")
 def delete_flow_path(flow_id):
-  command = "curl -s \"http://%s:%s/wm/flow/delete/%s/json\"" % (ControllerIP, ControllerPort, flow_id)
+  command = "curl -s \"http://%s:%s/wm/onos/flows/delete/%s/json\"" % (ControllerIP, ControllerPort, flow_id)
   debug("delete_flow_path %s" % command)
   result = os.popen(command).read()
   debug("result %s" % result)
diff --git a/web/css/bootstrap.css b/web/floodlight/css/bootstrap.css
similarity index 100%
rename from web/css/bootstrap.css
rename to web/floodlight/css/bootstrap.css
diff --git a/web/css/styles.css b/web/floodlight/css/styles.css
similarity index 100%
rename from web/css/styles.css
rename to web/floodlight/css/styles.css
diff --git a/web/img/floodlight.png b/web/floodlight/img/floodlight.png
similarity index 100%
rename from web/img/floodlight.png
rename to web/floodlight/img/floodlight.png
Binary files differ
diff --git a/web/img/glyphicons-halflings-white.png b/web/floodlight/img/glyphicons-halflings-white.png
similarity index 100%
rename from web/img/glyphicons-halflings-white.png
rename to web/floodlight/img/glyphicons-halflings-white.png
Binary files differ
diff --git a/web/img/glyphicons-halflings.png b/web/floodlight/img/glyphicons-halflings.png
similarity index 100%
rename from web/img/glyphicons-halflings.png
rename to web/floodlight/img/glyphicons-halflings.png
Binary files differ
diff --git a/web/img/logo.jpg b/web/floodlight/img/logo.jpg
similarity index 100%
rename from web/img/logo.jpg
rename to web/floodlight/img/logo.jpg
Binary files differ
diff --git a/web/img/openflow-logo-40px.png b/web/floodlight/img/openflow-logo-40px.png
similarity index 100%
rename from web/img/openflow-logo-40px.png
rename to web/floodlight/img/openflow-logo-40px.png
Binary files differ
diff --git a/web/img/server.png b/web/floodlight/img/server.png
similarity index 100%
rename from web/img/server.png
rename to web/floodlight/img/server.png
Binary files differ
diff --git a/web/img/switch.png b/web/floodlight/img/switch.png
similarity index 100%
rename from web/img/switch.png
rename to web/floodlight/img/switch.png
Binary files differ
diff --git a/web/index.html b/web/floodlight/index.html
similarity index 100%
rename from web/index.html
rename to web/floodlight/index.html
diff --git a/web/js/controller-status.js b/web/floodlight/js/controller-status.js
similarity index 100%
rename from web/js/controller-status.js
rename to web/floodlight/js/controller-status.js
diff --git a/web/js/jquery-1.7.2.min.js b/web/floodlight/js/jquery-1.7.2.min.js
similarity index 100%
rename from web/js/jquery-1.7.2.min.js
rename to web/floodlight/js/jquery-1.7.2.min.js
diff --git a/web/js/main.js b/web/floodlight/js/main.js
similarity index 100%
rename from web/js/main.js
rename to web/floodlight/js/main.js
diff --git a/web/js/models/flowmodel.js b/web/floodlight/js/models/flowmodel.js
similarity index 100%
rename from web/js/models/flowmodel.js
rename to web/floodlight/js/models/flowmodel.js
diff --git a/web/js/models/hostmodel.js b/web/floodlight/js/models/hostmodel.js
similarity index 97%
rename from web/js/models/hostmodel.js
rename to web/floodlight/js/models/hostmodel.js
index 8de3dd6..1caff6c 100644
--- a/web/js/models/hostmodel.js
+++ b/web/floodlight/js/models/hostmodel.js
@@ -35,7 +35,7 @@
         var self = this;
         //console.log("fetching host list")
         $.ajax({
-            url:hackBase + "/wm/device/",
+            url:hackBase + "/wm/floodlight/device/",
             dataType:"json",
             success:function (data) {
                 //console.log("fetched  host list: " + data.length);
diff --git a/web/js/models/portmodel.js b/web/floodlight/js/models/portmodel.js
similarity index 100%
rename from web/js/models/portmodel.js
rename to web/floodlight/js/models/portmodel.js
diff --git a/web/js/models/statusmodel.js b/web/floodlight/js/models/statusmodel.js
similarity index 89%
rename from web/js/models/statusmodel.js
rename to web/floodlight/js/models/statusmodel.js
index b7cdebd..5cbb526 100644
--- a/web/js/models/statusmodel.js
+++ b/web/floodlight/js/models/statusmodel.js
@@ -30,7 +30,7 @@
         var self = this;
         console.log("fetching controller status");
         $.ajax({
-            url:hackBase + "/wm/core/health/json",
+            url:hackBase + "/wm/floodlight/core/health/json",
             dataType:"json",
             success:function (data) {
                 console.log("fetched controller status: health");
@@ -39,7 +39,7 @@
             }
         });
         $.ajax({
-            url:hackBase + "/wm/core/system/uptime/json",
+            url:hackBase + "/wm/floodlight/core/system/uptime/json",
             dataType:"json",
             success:function (data) {
                 console.log("fetched controller status: uptime");
@@ -48,7 +48,7 @@
             }
         });
         $.ajax({
-            url:hackBase + "/wm/core/memory/json",
+            url:hackBase + "/wm/floodlight/core/memory/json",
             dataType:"json",
             success:function (data) {
                 console.log("fetched controller status: memory");
@@ -57,7 +57,7 @@
             }
         });
         $.ajax({
-            url:hackBase + "/wm/core/module/loaded/json",
+            url:hackBase + "/wm/floodlight/core/module/loaded/json",
             dataType:"json",
             success:function (data) {
                 console.log("fetched controller status: modules loaded");
diff --git a/web/js/models/switchmodel.js b/web/floodlight/js/models/switchmodel.js
similarity index 95%
rename from web/js/models/switchmodel.js
rename to web/floodlight/js/models/switchmodel.js
index 4104dd0..700a1cf 100644
--- a/web/js/models/switchmodel.js
+++ b/web/floodlight/js/models/switchmodel.js
@@ -16,7 +16,7 @@
 
 window.Switch = Backbone.Model.extend({
 
-    urlRoot:"/wm/core/switch/",
+    urlRoot:"/wm/floodlight/core/switch/",
     
     defaults: {
         datapathDescription: '',
@@ -34,7 +34,7 @@
 
         //console.log("fetching switch " + this.id + " desc")
         $.ajax({
-            url:hackBase + "/wm/core/switch/" + self.id + '/desc/json',
+            url:hackBase + "/wm/floodlight/core/switch/" + self.id + '/desc/json',
             dataType:"json",
             success:function (data) {
                 //console.log("fetched  switch " + self.id + " desc");
@@ -45,7 +45,7 @@
 
         //console.log("fetching switch " + this.id + " aggregate")
         $.ajax({
-            url:hackBase + "/wm/core/switch/" + self.id + '/aggregate/json',
+            url:hackBase + "/wm/floodlight/core/switch/" + self.id + '/aggregate/json',
             dataType:"json",
             success:function (data) {
                 //console.log("fetched  switch " + self.id + " aggregate");
@@ -69,7 +69,7 @@
         //console.log("fetching switch " + this.id + " ports")
         //console.log("fetching switch " + this.id + " features")
         $.when($.ajax({
-            url:hackBase + "/wm/core/switch/" + self.id + '/port/json',
+            url:hackBase + "/wm/floodlight/core/switch/" + self.id + '/port/json',
             dataType:"json",
             success:function (data) {
                 //console.log("fetched  switch " + self.id + " ports");
@@ -106,7 +106,7 @@
             }
         }),
         $.ajax({
-            url:hackBase + "/wm/core/switch/" + self.id + '/features/json',
+            url:hackBase + "/wm/floodlight/core/switch/" + self.id + '/features/json',
             dataType:"json",
             success:function (data) {
                 //console.log("fetched  switch " + self.id + " features");
@@ -163,7 +163,7 @@
         var self = this;
         //console.log("fetching switch " + this.id + " flows")
         $.ajax({
-            url:hackBase + "/wm/core/switch/" + self.id + '/flow/json',
+            url:hackBase + "/wm/floodlight/core/switch/" + self.id + '/flow/json',
             dataType:"json",
             success:function (data) {
                 //console.log("fetched  switch " + self.id + " flows");
@@ -269,7 +269,7 @@
         var self = this;
         //console.log("fetching switch list")
         $.ajax({
-            url:hackBase + "/wm/core/controller/switches/json",
+            url:hackBase + "/wm/floodlight/core/controller/switches/json",
             dataType:"json",
             success:function (data) {
                 //console.log("fetched  switch list: " + data.length);
diff --git a/web/js/models/topologymodel.js b/web/floodlight/js/models/topologymodel.js
similarity index 97%
rename from web/js/models/topologymodel.js
rename to web/floodlight/js/models/topologymodel.js
index c5d8f9b..bcac141 100644
--- a/web/js/models/topologymodel.js
+++ b/web/floodlight/js/models/topologymodel.js
@@ -16,7 +16,7 @@
 
 window.Topology = Backbone.Model.extend({
 
-    url:"/wm/topology/links/json",
+    url:"/wm/onos/linkdiscovery/links/json",
     
     defaults:{
         nodes: [],
diff --git a/web/js/onos-topology-route.js b/web/floodlight/js/onos-topology-route.js
similarity index 100%
rename from web/js/onos-topology-route.js
rename to web/floodlight/js/onos-topology-route.js
diff --git a/web/js/onos-topology.js b/web/floodlight/js/onos-topology.js
similarity index 100%
rename from web/js/onos-topology.js
rename to web/floodlight/js/onos-topology.js
diff --git a/web/js/utils.js b/web/floodlight/js/utils.js
similarity index 100%
rename from web/js/utils.js
rename to web/floodlight/js/utils.js
diff --git a/web/js/views/flow.js b/web/floodlight/js/views/flow.js
similarity index 100%
rename from web/js/views/flow.js
rename to web/floodlight/js/views/flow.js
diff --git a/web/js/views/header.js b/web/floodlight/js/views/header.js
similarity index 100%
rename from web/js/views/header.js
rename to web/floodlight/js/views/header.js
diff --git a/web/js/views/home.js b/web/floodlight/js/views/home.js
similarity index 100%
rename from web/js/views/home.js
rename to web/floodlight/js/views/home.js
diff --git a/web/js/views/host.js b/web/floodlight/js/views/host.js
similarity index 100%
rename from web/js/views/host.js
rename to web/floodlight/js/views/host.js
diff --git a/web/js/views/port.js b/web/floodlight/js/views/port.js
similarity index 100%
rename from web/js/views/port.js
rename to web/floodlight/js/views/port.js
diff --git a/web/js/views/status.js b/web/floodlight/js/views/status.js
similarity index 100%
rename from web/js/views/status.js
rename to web/floodlight/js/views/status.js
diff --git a/web/js/views/switch.js b/web/floodlight/js/views/switch.js
similarity index 100%
rename from web/js/views/switch.js
rename to web/floodlight/js/views/switch.js
diff --git a/web/js/views/topology.js b/web/floodlight/js/views/topology.js
similarity index 100%
rename from web/js/views/topology.js
rename to web/floodlight/js/views/topology.js
diff --git a/web/lib/backbone-min.js b/web/floodlight/lib/backbone-min.js
similarity index 100%
rename from web/lib/backbone-min.js
rename to web/floodlight/lib/backbone-min.js
diff --git a/web/lib/bootstrap-alert.js b/web/floodlight/lib/bootstrap-alert.js
similarity index 100%
rename from web/lib/bootstrap-alert.js
rename to web/floodlight/lib/bootstrap-alert.js
diff --git a/web/lib/bootstrap-dropdown.js b/web/floodlight/lib/bootstrap-dropdown.js
similarity index 100%
rename from web/lib/bootstrap-dropdown.js
rename to web/floodlight/lib/bootstrap-dropdown.js
diff --git a/web/lib/d3.v2.min.js b/web/floodlight/lib/d3.v2.min.js
similarity index 100%
rename from web/lib/d3.v2.min.js
rename to web/floodlight/lib/d3.v2.min.js
diff --git a/web/lib/jquery.min.js b/web/floodlight/lib/jquery.min.js
similarity index 100%
rename from web/lib/jquery.min.js
rename to web/floodlight/lib/jquery.min.js
diff --git a/web/lib/underscore-min.js b/web/floodlight/lib/underscore-min.js
similarity index 100%
rename from web/lib/underscore-min.js
rename to web/floodlight/lib/underscore-min.js
diff --git a/web/tpl/flow-list-item.html b/web/floodlight/tpl/flow-list-item.html
similarity index 100%
rename from web/tpl/flow-list-item.html
rename to web/floodlight/tpl/flow-list-item.html
diff --git a/web/tpl/flow-list.html b/web/floodlight/tpl/flow-list.html
similarity index 100%
rename from web/tpl/flow-list.html
rename to web/floodlight/tpl/flow-list.html
diff --git a/web/tpl/header.html b/web/floodlight/tpl/header.html
similarity index 100%
rename from web/tpl/header.html
rename to web/floodlight/tpl/header.html
diff --git a/web/tpl/home.html b/web/floodlight/tpl/home.html
similarity index 100%
rename from web/tpl/home.html
rename to web/floodlight/tpl/home.html
diff --git a/web/tpl/host-list-item.html b/web/floodlight/tpl/host-list-item.html
similarity index 100%
rename from web/tpl/host-list-item.html
rename to web/floodlight/tpl/host-list-item.html
diff --git a/web/tpl/host-list.html b/web/floodlight/tpl/host-list.html
similarity index 100%
rename from web/tpl/host-list.html
rename to web/floodlight/tpl/host-list.html
diff --git a/web/tpl/host.html b/web/floodlight/tpl/host.html
similarity index 100%
rename from web/tpl/host.html
rename to web/floodlight/tpl/host.html
diff --git a/web/tpl/port-list-item.html b/web/floodlight/tpl/port-list-item.html
similarity index 100%
rename from web/tpl/port-list-item.html
rename to web/floodlight/tpl/port-list-item.html
diff --git a/web/tpl/port-list.html b/web/floodlight/tpl/port-list.html
similarity index 100%
rename from web/tpl/port-list.html
rename to web/floodlight/tpl/port-list.html
diff --git a/web/tpl/status.html b/web/floodlight/tpl/status.html
similarity index 100%
rename from web/tpl/status.html
rename to web/floodlight/tpl/status.html
diff --git a/web/tpl/switch-list-item.html b/web/floodlight/tpl/switch-list-item.html
similarity index 100%
rename from web/tpl/switch-list-item.html
rename to web/floodlight/tpl/switch-list-item.html
diff --git a/web/tpl/switch-list.html b/web/floodlight/tpl/switch-list.html
similarity index 100%
rename from web/tpl/switch-list.html
rename to web/floodlight/tpl/switch-list.html
diff --git a/web/tpl/switch.html b/web/floodlight/tpl/switch.html
similarity index 100%
rename from web/tpl/switch.html
rename to web/floodlight/tpl/switch.html
diff --git a/web/tpl/topology.html b/web/floodlight/tpl/topology.html
similarity index 100%
rename from web/tpl/topology.html
rename to web/floodlight/tpl/topology.html
diff --git a/web/tpl/vlan-list-item.html b/web/floodlight/tpl/vlan-list-item.html
similarity index 100%
rename from web/tpl/vlan-list-item.html
rename to web/floodlight/tpl/vlan-list-item.html
diff --git a/web/tpl/vlan.html b/web/floodlight/tpl/vlan.html
similarity index 100%
rename from web/tpl/vlan.html
rename to web/floodlight/tpl/vlan.html
diff --git a/web/flowsync.py b/web/flowsync.py
index 51399d5..ef1d9bd 100755
--- a/web/flowsync.py
+++ b/web/flowsync.py
@@ -29,12 +29,12 @@
   if DEBUG:
     print '%s' % (txt)
 
-# @app.route("/wm/fprog/synchronizer/sync/<dpid>/json")
+# @app.route("/wm/onos/flowprogrammer/synchronizer/sync/<dpid>/json")
 # Sample output:
 #  "true"
 def synchronize(dpid):
   try:
-    command = "curl -s \"http://%s:%s/wm/fprog/synchronizer/sync/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    command = "curl -s \"http://%s:%s/wm/onos/flowprogrammer/synchronizer/sync/%s/json\"" % (ControllerIP, ControllerPort, dpid)
     debug("synchronize %s" % command)
      
     result = os.popen(command).read()
@@ -48,12 +48,12 @@
   
   print "Synchronization of switch %s has successfully began" % (dpid)
 
-# @app.route("/wm/fprog/synchronizer/interrupt/<dpid>/json")
+# @app.route("/wm/onos/flowprogrammer/synchronizer/interrupt/<dpid>/json")
 # Sample output:
 #  "true"
 def interrupt(dpid):
   try:
-    command = "curl -s \"http://%s:%s/wm/fprog/synchronizer/interrupt/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    command = "curl -s \"http://%s:%s/wm/onos/flowprogrammer/synchronizer/interrupt/%s/json\"" % (ControllerIP, ControllerPort, dpid)
     debug("interrupt %s" % command)
      
     result = os.popen(command).read()
diff --git a/web/get_datagrid.py b/web/get_datagrid.py
index 2d26846..43ab04f 100755
--- a/web/get_datagrid.py
+++ b/web/get_datagrid.py
@@ -29,7 +29,7 @@
   if DEBUG:
     print '%s' % (txt)
 
-# @app.route("/wm/datagrid/get/map/<map-name>/json ")
+# @app.route("/wm/onos/datagrid/get/map/<map-name>/json ")
 # Sample output:
 
 def print_datagrid_map(parsedResult):
@@ -37,7 +37,7 @@
 
 def get_datagrid_map(map_name):
   try:
-    command = "curl -s \"http://%s:%s/wm/datagrid/get/map/%s/json\"" % (ControllerIP, ControllerPort, map_name)
+    command = "curl -s \"http://%s:%s/wm/onos/datagrid/get/map/%s/json\"" % (ControllerIP, ControllerPort, map_name)
     debug("get_datagrid_map %s" % command)
 
     result = os.popen(command).read()
diff --git a/web/get_flow.py b/web/get_flow.py
index 94b9a61..382238f 100755
--- a/web/get_flow.py
+++ b/web/get_flow.py
@@ -29,7 +29,7 @@
   if DEBUG:
     print '%s' % (txt)
 
-# @app.route("/wm/flow/get/<flow-id>/json")
+# @app.route("/wm/onos/flows/get/<flow-id>/json")
 # Sample output:
 # {"flowId":{"value":"0x5"},"installerId":{"value":"FOOBAR"},"dataPath":{"srcPort":{"dpid":{"value":"00:00:00:00:00:00:00:01"},"port":{"value":0}},"dstPort":{"dpid":{"value":"00:00:00:00:00:00:00:02"},"port":{"value":0}},"flowEntries":[{"flowEntryId":"0x1389","flowEntryMatch":null,"flowEntryActions":null,"dpid":{"value":"00:00:00:00:00:00:00:01"},"inPort":{"value":0},"outPort":{"value":1},"flowEntryUserState":"FE_USER_DELETE","flowEntrySwitchState":"FE_SWITCH_NOT_UPDATED","flowEntryErrorState":null},{"flowEntryId":"0x138a","flowEntryMatch":null,"flowEntryActions":null,"dpid":{"value":"00:00:00:00:00:00:00:02"},"inPort":{"value":9},"outPort":{"value":0},"flowEntryUserState":"FE_USER_DELETE","flowEntrySwitchState":"FE_SWITCH_NOT_UPDATED","flowEntryErrorState":null}]}}
 
@@ -236,7 +236,7 @@
 
 def get_flow_path(flow_id):
   try:
-    command = "curl -s \"http://%s:%s/wm/flow/get/%s/json\"" % (ControllerIP, ControllerPort, flow_id)
+    command = "curl -s \"http://%s:%s/wm/onos/flows/get/%s/json\"" % (ControllerIP, ControllerPort, flow_id)
     debug("get_flow_path %s" % command)
 
     result = os.popen(command).read()
@@ -256,7 +256,7 @@
 
 def get_all_flow_paths():
   try:
-    command = "curl -s \"http://%s:%s/wm/flow/getall/json\"" % (ControllerIP, ControllerPort)
+    command = "curl -s \"http://%s:%s/wm/onos/flows/getall/json\"" % (ControllerIP, ControllerPort)
     debug("get_all_flow_paths %s" % command)
 
     result = os.popen(command).read()
diff --git a/web/onos-topology-route.html b/web/onos-topology-route.html
index 6c167c7..cbda5e9 100644
--- a/web/onos-topology-route.html
+++ b/web/onos-topology-route.html
@@ -42,7 +42,7 @@
     </marker>
   </defs>
 <script type="text/javascript">
-gui("http://onosnat.onlab.us:8080/wm/topology/toporoute/00:00:00:0d:00:d1/2/00:00:00:0d:00:d3/3/json");
+gui("http://onosnat.onlab.us:8080/wm/floodlight/topology/toporoute/00:00:00:0d:00:d1/2/00:00:00:0d:00:d3/3/json");
 </script>
 </svg>
 </body>
diff --git a/web/ons-demo/js/model.js b/web/ons-demo/js/model.js
index df4a751..bb1aaea 100644
--- a/web/ons-demo/js/model.js
+++ b/web/ons-demo/js/model.js
@@ -61,12 +61,12 @@
 }
 
 var urls = {
-	links: '/wm/core/topology/links/json',
-	switches: '/wm/core/topology/switches/all/json',
-	flows: '/wm/flow/getsummary/0/0/json?proxy',
-	activeControllers: '/wm/registry/controllers/json',
+	links: '/wm/onos/topology/links/json',
+	switches: '/wm/onos/topology/switches/all/json',
+	flows: '/wm/onos/flows/getsummary/0/0/json?proxy',
+	activeControllers: '/wm/onos/registry/controllers/json',
 	controllers: 'data/controllers.json',
-	mapping: '/wm/registry/switches/json',
+	mapping: '/wm/onos/registry/switches/json',
 	configuration: 'data/configuration.json'
 }
 
@@ -81,12 +81,12 @@
 }
 
 var proxyURLs = {
-	links: '/wm/core/topology/links/json?proxy',
-	switches: '/wm/core/topology/switches/all/json?proxy',
-	flows: '/wm/flow/getsummary/0/0/json?proxy',
-	activeControllers: '/wm/registry/controllers/json?proxy',
+	links: '/wm/onos/topology/links/json?proxy',
+	switches: '/wm/onos/topology/switches/all/json?proxy',
+	flows: '/wm/onos/flows/getsummary/0/0/json?proxy',
+	activeControllers: '/wm/onos/registry/controllers/json?proxy',
 	controllers: 'data/controllers.json',
-	mapping: '/wm/registry/switches/json?proxy',
+	mapping: '/wm/onos/registry/switches/json?proxy',
 	configuration: 'data/configuration.json'
 }
 
diff --git a/web/pusher.py b/web/pusher.py
index 2a3528b..dbbe7f9 100755
--- a/web/pusher.py
+++ b/web/pusher.py
@@ -29,12 +29,12 @@
   if DEBUG:
     print '%s' % (txt)
 
-# @app.route("/wm/fprog/pusher/setrate/<dpid>/<rate>/json")
+# @app.route("/wm/onos/flowprogrammer/pusher/setrate/<dpid>/<rate>/json")
 # Sample output:
 #  "true"
 def set_rate(dpid,rate):
   try:
-    command = "curl -s \"http://%s:%s/wm/fprog/pusher/setrate/%s/%s/json\"" % (ControllerIP, ControllerPort, dpid, rate)
+    command = "curl -s \"http://%s:%s/wm/onos/flowprogrammer/pusher/setrate/%s/%s/json\"" % (ControllerIP, ControllerPort, dpid, rate)
     debug("set_rate %s" % command)
      
     result = os.popen(command).read()
@@ -48,12 +48,12 @@
   
   print "Sending rate to %s is successfully set to %s" % (dpid, rate)
 
-# @app.route("/wm/fprog/pusher/suspend/<dpid>/json")
+# @app.route("/wm/onos/flowprogrammer/pusher/suspend/<dpid>/json")
 # Sample output:
 #  "true"
 def suspend(dpid):
   try:
-    command = "curl -s \"http://%s:%s/wm/fprog/pusher/suspend/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    command = "curl -s \"http://%s:%s/wm/onos/flowprogrammer/pusher/suspend/%s/json\"" % (ControllerIP, ControllerPort, dpid)
     debug("suspend %s" % command)
      
     result = os.popen(command).read()
@@ -67,12 +67,12 @@
   
   print "DPID %s is successfully suspended" % dpid
 
-# @app.route("/wm/fprog/pusher/resume/<dpid>/json")
+# @app.route("/wm/onos/flowprogrammer/pusher/resume/<dpid>/json")
 # Sample output:
 #  "true"
 def resume(dpid):
   try:
-    command = "curl -s \"http://%s:%s/wm/fprog/pusher/resume/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    command = "curl -s \"http://%s:%s/wm/onos/flowprogrammer/pusher/resume/%s/json\"" % (ControllerIP, ControllerPort, dpid)
     debug("resume %s" % command)
      
     result = os.popen(command).read()
@@ -86,12 +86,12 @@
   
   print "DPID %s is successfully resumed" % dpid
 
-# @app.route("/wm/fprog/pusher/barrier/<dpid>/json")
+# @app.route("/wm/onos/flowprogrammer/pusher/barrier/<dpid>/json")
 # Sample output:
 #  "{"version":1,"type":"BARRIER_REPLY","length":8,"xid":4,"lengthU":8}"
 def barrier(dpid):
   try:
-    command = "curl -s \"http://%s:%s/wm/fprog/pusher/barrier/%s/json\"" % (ControllerIP, ControllerPort, dpid)
+    command = "curl -s \"http://%s:%s/wm/onos/flowprogrammer/pusher/barrier/%s/json\"" % (ControllerIP, ControllerPort, dpid)
     debug("barrier %s" % command)
      
     result = os.popen(command).read()
diff --git a/web/rest-test.sh b/web/rest-test.sh
index 2551f12..c6c870b 100755
--- a/web/rest-test.sh
+++ b/web/rest-test.sh
@@ -2,7 +2,7 @@
 rm -f rest.json
 touch rest.json
 
-urls="http://localhost:8080/wm/core/topology/switches/all/json http://localhost:8080/wm/core/topology/links/json http://localhost:8080/wm/registry/controllers/json http://localhost:8080/wm/registry/switches/json"
+urls="http://localhost:8080/wm/onos/topology/switches/all/json http://localhost:8080/wm/onos/linkdiscovery/links/json http://localhost:8080/wm/onos/registry/controllers/json http://localhost:8080/wm/onos/registry/switches/json"
 
 for url in $urls; do
   echo "---REST CALL---" >> rest.json
diff --git a/web/restapi.py b/web/restapi.py
index a3bd51c..fd99ac6 100755
--- a/web/restapi.py
+++ b/web/restapi.py
@@ -54,21 +54,21 @@
   return response
 
 ## REST API ##
-#@app.route("/wm/topology/links/json")
+#@app.route("/wm/onos/linkdiscovery/links/json")
 #def links():
 #    global links_
 #    js = json.dumps(links_)
 #    resp = Response(js, status=200, mimetype='application/json')
 #    return resp
 
-#@app.route("/wm/core/controller/switches/json")
+#@app.route("/wm/floodlight/core/controller/switches/json")
 #def switches():
 #    global switches_
 #    js = json.dumps(switches_)
 #    resp = Response(js, status=200, mimetype='application/json')
 #    return resp
 
-@app.route("/wm/device/")
+@app.route("/wm/floodlight/device/")
 def devices():
   ret = []
   js = json.dumps(ret)
@@ -76,7 +76,7 @@
   return resp
 
 ## return fake stat for now
-@app.route("/wm/core/switch/<switchId>/<statType>/json")
+@app.route("/wm/floodlight/core/switch/<switchId>/<statType>/json")
 def switch_stat(switchId, statType):
     if statType == "desc":
         desc=[{"length":1056,"serialNumber":"None","manufacturerDescription":"Nicira Networks, Inc.","hardwareDescription":"Open vSwitch","softwareDescription":"1.4.0+build0","datapathDescription":"None"}]
@@ -93,7 +93,7 @@
     resp = Response(js, status=200, mimetype='application/json')
     return resp
 
-@app.route("/wm/core/controller/switches/json")
+@app.route("/wm/floodlight/core/controller/switches/json")
 def query_switch():
   try:
     command = "curl -s http://%s:%s/graphs/%s/vertices" % (RestIP, RestPort, DBName)
@@ -116,7 +116,7 @@
   resp = Response(js, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/topology/links/json")
+@app.route("/wm/onos/linkdiscovery/links/json")
 def query_links():
   try:
     command = "curl -s http://%s:%s/graphs/%s/edges" % (RestIP, RestPort, DBName)
diff --git a/web/restapi2.py b/web/restapi2.py
index c9952ac..050d8a4 100755
--- a/web/restapi2.py
+++ b/web/restapi2.py
@@ -57,7 +57,7 @@
 ONOS_GUI3_HOST="http://gui3.onlab.us:8080"
 ONOS_LOCAL_HOST="http://localhost:8080" ;# for Amazon EC2
 
-@app.route("/wm/core/topology/switches/all/json")
+@app.route("/wm/onos/topology/switches/all/json")
 def switches():
   if request.args.get('proxy') == None:
     host = ONOS_LOCAL_HOST
@@ -65,7 +65,7 @@
     host = ONOS_GUI3_HOST
 
   try:
-    command = "curl -s %s/wm/core/topology/switches/all/json" % (host)
+    command = "curl -s %s/wm/onos/topology/switches/all/json" % (host)
     print command
     result = os.popen(command).read()
   except:
@@ -75,7 +75,7 @@
   resp = Response(result, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/core/topology/links/json")
+@app.route("/wm/onos/topology/links/json")
 def links():
   if request.args.get('proxy') == None:
     host = ONOS_LOCAL_HOST
@@ -83,7 +83,7 @@
     host = ONOS_GUI3_HOST
 
   try:
-    command = "curl -s %s/wm/core/topology/links/json" % (host)
+    command = "curl -s %s/wm/onos/topology/links/json" % (host)
     print command
     result = os.popen(command).read()
   except:
@@ -93,7 +93,7 @@
   resp = Response(result, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/flow/getall/json")
+@app.route("/wm/onos/flows/getall/json")
 def flows():
   if request.args.get('proxy') == None:
     host = ONOS_LOCAL_HOST
@@ -101,7 +101,7 @@
     host = ONOS_GUI3_HOST
 
   try:
-    command = "curl -s %s/wm/flow/getall/json" % (host)
+    command = "curl -s %s/wm/onos/flows/getall/json" % (host)
     print command
     result = os.popen(command).read()
   except:
@@ -111,7 +111,7 @@
   resp = Response(result, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/registry/controllers/json")
+@app.route("/wm/onos/registry/controllers/json")
 def registry_controllers():
   if request.args.get('proxy') == None:
     host = ONOS_LOCAL_HOST
@@ -119,7 +119,7 @@
     host = ONOS_GUI3_HOST
 
   try:
-    command = "curl -s %s/wm/registry/controllers/json" % (host)
+    command = "curl -s %s/wm/onos/registry/controllers/json" % (host)
     print command
     result = os.popen(command).read()
   except:
@@ -129,7 +129,7 @@
   resp = Response(result, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/registry/switches/json")
+@app.route("/wm/onos/registry/switches/json")
 def registry_switches():
   if request.args.get('proxy') == None:
     host = ONOS_LOCAL_HOST
@@ -137,7 +137,7 @@
     host = ONOS_GUI3_HOST
 
   try:
-    command = "curl -s %s/wm/registry/switches/json" % (host)
+    command = "curl -s %s/wm/onos/registry/switches/json" % (host)
     print command
     result = os.popen(command).read()
   except:
@@ -151,21 +151,21 @@
 
 
 ## REST API ##
-#@app.route("/wm/topology/links/json")
+#@app.route("/wm/onos/linkdiscovery/links/json")
 #def links():
 #    global links_
 #    js = json.dumps(links_)
 #    resp = Response(js, status=200, mimetype='application/json')
 #    return resp
 
-#@app.route("/wm/core/controller/switches/json")
+#@app.route("/wm/floodlight/core/controller/switches/json")
 #def switches():
 #    global switches_
 #    js = json.dumps(switches_)
 #    resp = Response(js, status=200, mimetype='application/json')
 #    return resp
 
-@app.route("/wm/device/")
+@app.route("/wm/floodlight/device/")
 def devices():
   try:
     command = "curl -s http://%s:%s/graphs/%s/vertices?key=type\&value=device" % (RestIP, RestPort, DBName)
@@ -218,7 +218,7 @@
 #{"entityClass":"DefaultEntityClass","mac":["7c:d1:c3:e0:8c:a3"],"ipv4":["192.168.2.102","10.1.10.35"],"vlan":[],"attachmentPoint":[{"port":13,"switchDPID":"00:01:00:12:e2:78:32:44","errorStatus":null}],"lastSeen":1357333593496}
 
 ## return fake stat for now
-@app.route("/wm/core/switch/<switchId>/<statType>/json")
+@app.route("/wm/floodlight/core/switch/<switchId>/<statType>/json")
 def switch_stat(switchId, statType):
     if statType == "desc":
         desc=[{"length":1056,"serialNumber":"None","manufacturerDescription":"Nicira Networks, Inc.","hardwareDescription":"Open vSwitch","softwareDescription":"1.4.0+build0","datapathDescription":"None"}]
@@ -235,7 +235,7 @@
     resp = Response(js, status=200, mimetype='application/json')
     return resp
 
-@app.route("/wm/core/controller/switches/json")
+@app.route("/wm/floodlight/core/controller/switches/json")
 def query_switch():
   try:
     command = "curl -s http://%s:%s/graphs/%s/vertices?key=type\&value=switch" % (RestIP, RestPort, DBName)
@@ -258,7 +258,7 @@
   resp = Response(js, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/topology/links/json")
+@app.route("/wm/onos/linkdiscovery/links/json")
 def query_links():
   try:
     command = "curl -s http://%s:%s/graphs/%s/vertices?key=type\&value=port" % (RestIP, RestPort, DBName)
diff --git a/web/restapi3.py b/web/restapi3.py
index 001faa6..f3bb3eb 100755
--- a/web/restapi3.py
+++ b/web/restapi3.py
@@ -137,7 +137,7 @@
 
   return response
 
-@app.route("/wm/device/")
+@app.route("/wm/floodlight/device/")
 def devices():
   try:
     command = "curl -s http://%s:%s/graphs/%s/vertices\?key=type\&value=device" % (RestIP, RestPort, DBName)
@@ -182,7 +182,7 @@
 
 
 ## return fake stat for now
-@app.route("/wm/core/switch/<switchId>/<statType>/json")
+@app.route("/wm/floodlight/core/switch/<switchId>/<statType>/json")
 def switch_stat(switchId, statType):
     if statType == "desc":
         desc=[{"length":1056,"serialNumber":"None","manufacturerDescription":"Nicira Networks, Inc.","hardwareDescription":"Open vSwitch","softwareDescription":"1.4.0+build0","datapathDescription":"None"}]
@@ -199,7 +199,7 @@
     resp = Response(js, status=200, mimetype='application/json')
     return resp
 
-@app.route("/wm/core/controller/switches/json")
+@app.route("/wm/floodlight/core/controller/switches/json")
 def query_switch():
   try:
     command = "curl -s \'http://%s:%s/graphs/%s/vertices?key=type&value=switch\'" % (RestIP, RestPort, DBName)
@@ -226,7 +226,7 @@
   resp = Response(js, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/topology/links/json")
+@app.route("/wm/onos/linkdiscovery/links/json")
 def query_links():
   try:
     command = 'curl -s http://%s:%s/graphs/%s/vertices?key=type\&value=port' % (RestIP, RestPort, DBName)
diff --git a/web/shortest_path.py b/web/shortest_path.py
index 0f23bf4..805224b 100755
--- a/web/shortest_path.py
+++ b/web/shortest_path.py
@@ -13,7 +13,7 @@
 from flask import Flask, json, Response, render_template, make_response, request
 
 #
-# curl http://127.0.0.1:8080/wm/topology/route/00:00:00:00:00:00:0a:01/1/00:00:00:00:00:00:0a:04/1/json
+# curl http://127.0.0.1:8080/wm/onos/topology/route/00:00:00:00:00:00:0a:01/1/00:00:00:00:00:00:0a:04/1/json
 #
 
 ## Global Var ##
@@ -33,14 +33,14 @@
   if DEBUG:
     print '%s' % (txt)
 
-# @app.route("/wm/topology/route/<srcdpid>/<srcport>/<destdpid>/<destport>/json")
+# @app.route("/wm/onos/topology/route/<srcdpid>/<srcport>/<destdpid>/<destport>/json")
 #
 # Sample output:
 # {'dstPort': {'port': {'value': 0}, 'dpid': {'value': '00:00:00:00:00:00:00:02'}}, 'srcPort': {'port': {'value': 0}, 'dpid': {'value': '00:00:00:00:00:00:00:01'}}, 'flowEntries': [{'outPort': {'value': 1}, 'flowEntryErrorState': None, 'flowEntryMatch': None, 'flowEntryActions': None, 'inPort': {'value': 0}, 'flowEntryId': None, 'flowEntryUserState': 'FE_USER_UNKNOWN', 'dpid': {'value': '00:00:00:00:00:00:00:01'}, 'flowEntrySwitchState': 'FE_SWITCH_UNKNOWN'}, {'outPort': {'value': 0}, 'flowEntryErrorState': None, 'flowEntryMatch': None, 'flowEntryActions': None, 'inPort': {'value': 9}, 'flowEntryId': None, 'flowEntryUserState': 'FE_USER_UNKNOWN', 'dpid': {'value': '00:00:00:00:00:00:00:02'}, 'flowEntrySwitchState': 'FE_SWITCH_UNKNOWN'}]}
 #
 def shortest_path(v1, p1, v2, p2):
   try:
-    command = "curl -s http://%s:%s/wm/topology/route/%s/%s/%s/%s/json" % (ControllerIP, ControllerPort, v1, p1, v2, p2)
+    command = "curl -s http://%s:%s/wm/onos/topology/route/%s/%s/%s/%s/json" % (ControllerIP, ControllerPort, v1, p1, v2, p2)
     debug("shortest_path %s" % command)
 
     result = os.popen(command).read()
diff --git a/web/topology_rest.py b/web/topology_rest.py
index b3a415e..38dba5d 100755
--- a/web/topology_rest.py
+++ b/web/topology_rest.py
@@ -273,69 +273,69 @@
   return "http://" + host + ":8080"
 
 ## Switch ##
-@app.route("/wm/core/topology/switches/all/json")
+@app.route("/wm/onos/topology/switches/all/json")
 def switches():
   if request.args.get('proxy') == None:
     host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  url ="%s/wm/core/topology/switches/all/json" % (host)
+  url ="%s/wm/onos/topology/switches/all/json" % (host)
   (code, result) = get_json(url)
 
   resp = Response(result, status=code, mimetype='application/json')
   return resp
 
 ## Link ##
-@app.route("/wm/core/topology/links/json")
+@app.route("/wm/onos/topology/links/json")
 def links():
   if request.args.get('proxy') == None:
     host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  url ="%s/wm/core/topology/links/json" % (host)
+  url ="%s/wm/onos/topology/links/json" % (host)
   (code, result) = get_json(url)
 
   resp = Response(result, status=code, mimetype='application/json')
   return resp
 
 ## FlowSummary ##
-@app.route("/wm/flow/getsummary/<start>/<range>/json")
+@app.route("/wm/onos/flows/getsummary/<start>/<range>/json")
 def flows(start, range):
   if request.args.get('proxy') == None:
     host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  url ="%s/wm/flow/getsummary/%s/%s/json" % (host, start, range)
+  url ="%s/wm/onos/flows/getsummary/%s/%s/json" % (host, start, range)
   (code, result) = get_json(url)
 
   resp = Response(result, status=code, mimetype='application/json')
   return resp
 
-@app.route("/wm/registry/controllers/json")
+@app.route("/wm/onos/registry/controllers/json")
 def registry_controllers():
   if request.args.get('proxy') == None:
     host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  url= "%s/wm/registry/controllers/json" % (host)
+  url= "%s/wm/onos/registry/controllers/json" % (host)
   (code, result) = get_json(url)
 
   resp = Response(result, status=code, mimetype='application/json')
   return resp
 
 
-@app.route("/wm/registry/switches/json")
+@app.route("/wm/onos/registry/switches/json")
 def registry_switches():
   if request.args.get('proxy') == None:
     host = pick_host()
   else:
     host = ONOS_GUI3_HOST
 
-  url="%s/wm/registry/switches/json" % (host)
+  url="%s/wm/onos/registry/switches/json" % (host)
   (code, result) = get_json(url)
 
   resp = Response(result, status=code, mimetype='application/json')
@@ -354,7 +354,7 @@
 @app.route('/topology', methods=['GET'])
 def topology_for_gui():
   try:
-    command = "curl -s \'http://%s:%s/wm/core/topology/switches/all/json\'" % (RestIP, RestPort)
+    command = "curl -s \'http://%s:%s/wm/onos/topology/switches/all/json\'" % (RestIP, RestPort)
     result = os.popen(command).read()
     parsedResult = json.loads(result)
   except:
@@ -382,7 +382,7 @@
       switches.append(sw)
 
   try:
-    command = "curl -s \'http://%s:%s/wm/registry/switches/json\'" % (RestIP, RestPort)
+    command = "curl -s \'http://%s:%s/wm/onos/registry/switches/json\'" % (RestIP, RestPort)
     result = os.popen(command).read()
     parsedResult = json.loads(result)
   except:
@@ -404,7 +404,7 @@
 #    v2 = "00:00:00:00:00:0b:0d:03"
 #    v2 = "00:00:00:00:00:0d:00:d3"
 #    p2=1
-#    command = "curl -s http://%s:%s/wm/topology/route/%s/%s/%s/%s/json" % (RestIP, RestPort, v1, p1, v2, p2)
+#    command = "curl -s http://%s:%s/wm/onos/topology/route/%s/%s/%s/%s/json" % (RestIP, RestPort, v1, p1, v2, p2)
 #    result = os.popen(command).read()
 #    parsedResult = json.loads(result)
 #  except:
@@ -421,7 +421,7 @@
   #      path.append( (sdpid, ddpid))
 
   try:
-    command = "curl -s \'http://%s:%s/wm/core/topology/links/json\'" % (RestIP, RestPort)
+    command = "curl -s \'http://%s:%s/wm/onos/topology/links/json\'" % (RestIP, RestPort)
     result = os.popen(command).read()
     parsedResult = json.loads(result)
   except:
@@ -457,12 +457,12 @@
   resp = Response(js, status=200, mimetype='application/json')
   return resp
 
-#@app.route("/wm/topology/toporoute/00:00:00:00:00:a1/2/00:00:00:00:00:c1/3/json")
-#@app.route("/wm/topology/toporoute/<srcdpid>/<srcport>/<destdpid>/<destport>/json")
-@app.route("/wm/topology/toporoute/<v1>/<p1>/<v2>/<p2>/json")
+#@app.route("/wm/floodlight/topology/toporoute/00:00:00:00:00:a1/2/00:00:00:00:00:c1/3/json")
+#@app.route("/wm/floodlight/topology/toporoute/<srcdpid>/<srcport>/<destdpid>/<destport>/json")
+@app.route("/wm/floodlight/topology/toporoute/<v1>/<p1>/<v2>/<p2>/json")
 def shortest_path(v1, p1, v2, p2):
   try:
-    command = "curl -s \'http://%s:%s/wm/core/topology/switches/all/json\'" % (RestIP, RestPort)
+    command = "curl -s \'http://%s:%s/wm/onos/topology/switches/all/json\'" % (RestIP, RestPort)
     result = os.popen(command).read()
     parsedResult = json.loads(result)
   except:
@@ -494,7 +494,7 @@
       switches.append(sw)
 
   try:
-    command = "curl -s http://%s:%s/wm/topology/route/%s/%s/%s/%s/json" % (RestIP, RestPort, v1, p1, v2, p2)
+    command = "curl -s http://%s:%s/wm/onos/topology/route/%s/%s/%s/%s/json" % (RestIP, RestPort, v1, p1, v2, p2)
     result = os.popen(command).read()
     parsedResult = json.loads(result)
   except:
@@ -510,7 +510,7 @@
       path.append( (sdpid, ddpid))
 
   try:
-    command = "curl -s \'http://%s:%s/wm/core/topology/links/json\'" % (RestIP, RestPort)
+    command = "curl -s \'http://%s:%s/wm/onos/topology/links/json\'" % (RestIP, RestPort)
     result = os.popen(command).read()
     parsedResult = json.loads(result)
   except:
@@ -545,11 +545,11 @@
   resp = Response(js, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/core/controller/switches/json")
+@app.route("/wm/floodlight/core/controller/switches/json")
 def query_switch():
   try:
-    command = "curl -s \'http://%s:%s/wm/core/topology/switches/all/json\'" % (RestIP, RestPort)
-#    http://localhost:8080/wm/core/topology/switches/active/json
+    command = "curl -s \'http://%s:%s/wm/onos/topology/switches/all/json\'" % (RestIP, RestPort)
+#    http://localhost:8080/wm/onos/topology/switches/active/json
     print command
     result = os.popen(command).read()
     parsedResult = json.loads(result)
@@ -577,7 +577,7 @@
   resp = Response(js, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/device/")
+@app.route("/wm/floodlight/device/")
 def devices():
   try:
     command = "curl -s http://%s:%s/graphs/%s/vertices\?key=type\&value=device" % (RestIP, RestPort, DBName)
@@ -621,7 +621,7 @@
 #{"entityClass":"DefaultEntityClass","mac":["7c:d1:c3:e0:8c:a3"],"ipv4":["192.168.2.102","10.1.10.35"],"vlan":[],"attachmentPoint":[{"port":13,"switchDPID":"00:01:00:12:e2:78:32:44","errorStatus":null}],"lastSeen":1357333593496}
 
 ## return fake stat for now
-@app.route("/wm/core/switch/<switchId>/<statType>/json")
+@app.route("/wm/floodlight/core/switch/<switchId>/<statType>/json")
 def switch_stat(switchId, statType):
     if statType == "desc":
         desc=[{"length":1056,"serialNumber":"None","manufacturerDescription":"Nicira Networks, Inc.","hardwareDescription":"Open vSwitch","softwareDescription":"1.4.0+build0","datapathDescription":"None"}]
@@ -639,7 +639,7 @@
     return resp
 
 
-@app.route("/wm/topology/links/json")
+@app.route("/wm/onos/linkdiscovery/links/json")
 def query_links():
   try:
     command = 'curl -s http://%s:%s/graphs/%s/vertices?key=type\&value=port' % (RestIP, RestPort, DBName)
@@ -955,7 +955,7 @@
 @app.route("/gui/addflow/<src_dpid>/<src_port>/<dst_dpid>/<dst_port>/<srcMAC>/<dstMAC>")
 def add_flow(src_dpid, src_port, dst_dpid, dst_port, srcMAC, dstMAC):
   host = pick_host()
-  url ="%s/wm/flow/getsummary/%s/%s/json" % (host, 0, 0)
+  url ="%s/wm/onos/flows/getsummary/%s/%s/json" % (host, 0, 0)
   (code, result) = get_json(url)
   parsedResult = json.loads(result)
   if len(parsedResult) > 0:
@@ -990,7 +990,7 @@
 @app.route("/gui/iperf/start/<flow_id>/<duration>/<samples>")
 def iperf_start(flow_id,duration,samples):
   try:
-    command = "curl -s \'http://%s:%s/wm/flow/get/%s/json\'" % (RestIP, RestPort, flow_id)
+    command = "curl -s \'http://%s:%s/wm/onos/flows/get/%s/json\'" % (RestIP, RestPort, flow_id)
     print command
     result = os.popen(command).read()
     if len(result) == 0:
@@ -1055,7 +1055,7 @@
 @app.route("/gui/iperf/rate/<flow_id>")
 def iperf_rate(flow_id):
   try:
-    command = "curl -s \'http://%s:%s/wm/flow/get/%s/json\'" % (RestIP, RestPort, flow_id)
+    command = "curl -s \'http://%s:%s/wm/onos/flows/get/%s/json\'" % (RestIP, RestPort, flow_id)
     print command
     result = os.popen(command).read()
     if len(result) == 0: