Merge remote-tracking branch 'upstream/master'
diff --git a/build.xml b/build.xml
index 1c473ce..657a80d 100644
--- a/build.xml
+++ b/build.xml
@@ -26,7 +26,7 @@
     generated code.
 -->
 
-<project default="dist" name="Floodlight">
+<project default="jar" name="Floodlight">
     <property name="target" location="target"/>
     <property name="build" location="${target}/bin"/>
     <property name="build-test" location="${target}/bin-test"/>
@@ -66,9 +66,9 @@
         <include name="concurrentlinkedhashmap-lru-1.3.jar"/>
         <include name="jython-2.5.2.jar"/>
         <include name="libthrift-0.7.0.jar"/>
-	<include name="curator-client-1.3.4-SNAPSHOT.jar"/>
-	<include name="curator-framework-1.3.4-SNAPSHOT.jar"/>
-	<include name="curator-recipes-1.3.4-SNAPSHOT.jar"/>
+	<include name="curator-client-1.3.5-SNAPSHOT.jar"/>
+	<include name="curator-framework-1.3.5-SNAPSHOT.jar"/>
+	<include name="curator-recipes-1.3.5-SNAPSHOT.jar"/>
 	<include name="zookeeper-3.4.5.jar"/>
     </patternset>
 
diff --git a/cleanup-cassandra.sh b/cleanup-cassandra.sh
deleted file mode 100755
index 2844c1a..0000000
--- a/cleanup-cassandra.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#! /bin/bash
-DIR=~/ONOS
-~/titan-0.2.0/bin/gremlin.sh -e $DIR/cleanup-onos-db 
diff --git a/cluster-mgmt/README.txt b/cluster-mgmt/README.txt
new file mode 100644
index 0000000..974e3d2
--- /dev/null
+++ b/cluster-mgmt/README.txt
@@ -0,0 +1,22 @@
+########
+Cluster Management Tools
+#######
+
+ssh : contains necessary files in .ssh (don't change file permission)
+bash_profile: Can be used as $HOME/.bash_profile file. The following four lines needs to be changed as necessary
+
+export RCP_USER=ubuntu
+export RCMD_CMD=ssh
+export RCMD_CMD_ARGS="-i $HOME/.ssh/onlabkey.pem"
+export RCMD_USER=ubuntu
+export RCP_CMD="scp -i $HOME/.ssh/onlabkey.pem -o StrictHostKeyChecking=no"
+export FANOUT=64
+export CLUSTER="$HOME/cluster-mgmt/cluster.txt"
+
+### Set the proper value ##
+export ONOS_CLUSTER_BASENAME="onosdevx"
+export ONOS_CLUSTER_NR_NODES=8
+
+bin/start.sh : shutdown all service and restart
+bin/stop.sh : shutdown all service
+bin/status.sh : show status of the services 
diff --git a/cluster-mgmt/bash_profile b/cluster-mgmt/bash_profile
new file mode 100644
index 0000000..e9f2a39
--- /dev/null
+++ b/cluster-mgmt/bash_profile
@@ -0,0 +1,25 @@
+# .bash_profile
+
+# Get the aliases and functions
+if [ -f ~/.bashrc ]; then
+	. ~/.bashrc
+fi
+
+# User specific environment and startup programs
+
+PATH=$PATH:$HOME/bin
+
+export PATH
+
+### Cluster-IT setting##
+export RCP_USER=ubuntu
+export RCMD_CMD=ssh
+export RCMD_CMD_ARGS="-i $HOME/.ssh/onlabkey.pem"
+export RCMD_USER=ubuntu
+export RCP_CMD="scp -i $HOME/.ssh/onlabkey.pem -o StrictHostKeyChecking=no"
+export FANOUT=64
+export CLUSTER="$HOME/cluster-mgmt/cluster.txt"
+
+#### Set the proper value ####
+#export ONOS_CLUSTER_BASENAME="onosdevx"
+#export ONOS_CLUSTER_NR_NODES=8
diff --git a/cluster-mgmt/bin/start.sh b/cluster-mgmt/bin/start.sh
new file mode 100755
index 0000000..bd65df7
--- /dev/null
+++ b/cluster-mgmt/bin/start.sh
@@ -0,0 +1,13 @@
+#! /bin/bash
+. $HOME/cluster-mgmt/func.sh
+
+onos stop
+cassandra cleandb
+cassandra stop
+zk stop
+
+zk start
+cassandra start
+cassandra cleandb
+onos start
+dsh -g $basename 'cd ONOS; ./ctrl-local.sh'
diff --git a/cluster-mgmt/bin/status.sh b/cluster-mgmt/bin/status.sh
new file mode 100755
index 0000000..880bf10
--- /dev/null
+++ b/cluster-mgmt/bin/status.sh
@@ -0,0 +1,9 @@
+#! /bin/bash
+. $HOME/cluster-mgmt/func.sh
+
+basename="onosdevb"
+nr_nodes=4
+
+onos status
+cassandra status
+zk status
diff --git a/cluster-mgmt/bin/stop.sh b/cluster-mgmt/bin/stop.sh
new file mode 100755
index 0000000..a8f64ca
--- /dev/null
+++ b/cluster-mgmt/bin/stop.sh
@@ -0,0 +1,10 @@
+#! /bin/bash
+. $HOME/cluster-mgmt/func.sh
+
+basename="onosdevc"
+nr_nodes=4
+
+onos stop
+cassandra cleandb
+cassandra stop
+zk stop
diff --git a/cluster-mgmt/common/hosts b/cluster-mgmt/common/hosts
new file mode 100644
index 0000000..220b30f
--- /dev/null
+++ b/cluster-mgmt/common/hosts
@@ -0,0 +1,11 @@
+127.0.0.1 localhost
+
+# The following lines are desirable for IPv6 capable hosts
+::1 ip6-localhost ip6-loopback
+fe00::0 ip6-localnet
+ff00::0 ip6-mcastprefix
+ff02::1 ip6-allnodes
+ff02::2 ip6-allrouters
+ff02::3 ip6-allhosts
+
+## For ONOS Development
diff --git a/cluster-mgmt/common/known_hosts b/cluster-mgmt/common/known_hosts
new file mode 100644
index 0000000..bc8d892
--- /dev/null
+++ b/cluster-mgmt/common/known_hosts
@@ -0,0 +1,2 @@
+|1|vpuCVwBaUAW338i8XkTyuZpPn3o=|OEtDpg0rUr4I6MJrPU3UgO6xIjY= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
+|1|oQEfymNRsrXOo9uHu/jCST0f0I0=|UqxLCIvwPdgIlZWmusieRLCzRxE= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvCFIZTznMUPbS/r6b0Gw9jcnOBbH21wcBKETjXg9U5bMwHz2ocnEK8PPL1EK8uUTjZ3Kbilx4Jeio8HXEWtUkyOF/KyW1nXd0mxrWqqGQjFlpPj017Wfo0KIISgCWB9L8RJJ3aJ0selZwvmdHmg7uS306UGsJf1co2qubLGMAsdjPhYpvKXSJHoThupHBCuoqqOw80Tt5b3qJ6RwFjt/QiCgom9KoQn2DMQhS0iB9h5NHpejDX9/qLgFFiF3PdXaBCTE+vFLvoXwecp/x3pP2c8zA6FhCzYbZxLYMdMHqSmJRSKALWU3Qg9ekdXUBfzrLs4lPQ6UGFcku9WBAtN7oQ==
diff --git a/cluster-mgmt/common/onos.properties b/cluster-mgmt/common/onos.properties
new file mode 100644
index 0000000..1828db7
--- /dev/null
+++ b/cluster-mgmt/common/onos.properties
@@ -0,0 +1,18 @@
+floodlight.modules = net.floodlightcontroller.storage.memory.MemoryStorageSource,\
+net.floodlightcontroller.core.FloodlightProvider,\
+net.floodlightcontroller.threadpool.ThreadPool,\
+net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
+net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
+net.floodlightcontroller.firewall.Firewall,\
+net.floodlightcontroller.jython.JythonDebugInterface,\
+net.floodlightcontroller.counter.CounterStore,\
+net.floodlightcontroller.perfmon.PktInProcessingTime,\
+net.floodlightcontroller.ui.web.StaticWebRoutable,\
+net.floodlightcontroller.onoslistener.OnosPublisher, \
+net.onrc.onos.registry.controller.ZookeeperRegistry
+net.floodlightcontroller.restserver.RestApiServer.port = 8080
+net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633
+net.floodlightcontroller.jython.JythonDebugInterface.port = 6655
+net.floodlightcontroller.forwarding.Forwarding.idletimeout = 5
+net.floodlightcontroller.forwarding.Forwarding.hardtimeout = 0
+net.floodlightcontroller.onoslistener.OnosPublisher.dbconf = /tmp/cassandra.titan
diff --git a/cluster-mgmt/common/zoo.cfg b/cluster-mgmt/common/zoo.cfg
new file mode 100644
index 0000000..c4e1eb3
--- /dev/null
+++ b/cluster-mgmt/common/zoo.cfg
@@ -0,0 +1,45 @@
+# The number of milliseconds of each tick
+tickTime=2000
+# The number of ticks that the initial 
+# synchronization phase can take
+initLimit=10
+# The number of ticks that can pass between 
+# sending a request and getting an acknowledgement
+syncLimit=5
+# the directory where the snapshot is stored.
+# do not use /tmp for storage, /tmp here is just 
+# example sakes.
+dataDir=/var/lib/zookeeper
+# the port at which the clients will connect
+clientPort=2181
+#
+# specify all servers in the Zookeeper ensemble
+
+#server.1=onosgui1:2888:3888
+#server.2=onosgui2:2888:3888
+#server.3=onosgui3:2888:3888
+#server.4=onosgui4:2888:3888
+#server.5=onosgui5:2888:3888
+#server.6=onosgui6:2888:3888
+#server.7=onosgui7:2888:3888
+#server.8=onosgui8:2888:3888
+#
+#
+# Be sure to read the maintenance section of the 
+# administrator guide before turning on autopurge.
+#
+#
+# Be sure to read the maintenance section of the 
+# administrator guide before turning on autopurge.
+#
+# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
+#
+# The number of snapshots to retain in dataDir
+#autopurge.snapRetainCount=3
+# Purge task interval in hours
+# Set to "0" to disable auto purge feature
+#autopurge.purgeInterval=1
+server.1=test1:2888:3888
+server.2=test2:2888:3888
+server.3=test3:2888:3888
+server.4=test4:2888:3888
diff --git a/cluster-mgmt/cp-config.sh b/cluster-mgmt/cp-config.sh
new file mode 100755
index 0000000..5c74462
--- /dev/null
+++ b/cluster-mgmt/cp-config.sh
@@ -0,0 +1,69 @@
+#! /bin/bash
+USERNAME=ubuntu
+CASSANDRA_DIR='/home/ubuntu/apache-cassandra-1.1.4'
+ZK_DIR='/home/ubuntu/zookeeper-3.4.5'
+ZK_LIB='/var/lib/zookeeper'
+CASSANDRA_LIB='/var/lib/cassandra'
+
+SSH_COPY="authorized_keys  id_rsa  id_rsa.pub  known_hosts  onlab-gui.pem  onlabkey.pem"
+
+if [ $# == 2 ]; then
+  NR_NODES=$1
+  basename=$2
+else
+  echo "$0 nr_nodes basename"
+  exit
+fi
+
+if [ ! -f ./cluster.txt ]; then
+  echo "Cannot find cluster.txt"
+  exit
+fi
+
+export CLUSTER="./cluster.txt"
+dsh -g $basename 'uname -a'
+
+echo "Stopping Services"
+#dsh -g $basename 'cd ONOS; ./start-onos.sh stop'
+#dsh -g $basename 'cd ONOS; ./stop-cassandra stop'
+#dsh -g $basename '$ZK_DIR/bin/zkServer.sh stop'
+
+# authorized_keys  cassandra.yaml  hosts  id_rsa  id_rsa.pub  known_hosts  onlab-gui.pem  onlabkey.pem  onos.properties  zoo.cfg
+## SSH Setting
+dsh -g $basename 'mkdir -m 700 .ssh' 
+for n in $SSH_COPY; do
+ pcp -g $basename  common/$n '.ssh'
+ if [ $n != "id_rsa.pub" ] ; then
+   dsh -g $basename "chmod 600 .ssh/$n"
+ fi
+done
+
+dsh -g $basename "sudo rm -rf $CASSANDRA_LIB/commitlog/*"
+dsh -g $basename "sudo rm -rf $CASSANDRA_LIB/saved_caches/*"
+dsh -g $basename "sudo rm -rf $CASSANDRA_LIB/data/*"
+dsh -g $basename "sudo chown -R $username:$username $CASSANDRA_LIB"
+
+dsh -g $basename "sudo rm -rf $ZK_LIB/version-2*"
+dsh -g $basename "sudo rm -rf $ZK_LIB/myid"
+
+pcp -g $basename common/cassandra.yaml $CASSANDRA_DIR/conf
+pcp -g $basename common/zoo.cfg        $ZK_DIR/conf
+pcp -g $basename common/hosts          '~'
+
+for n in `seq 1 $NR_NODES`; do
+  pcp -w ${basename}${n} ${basename}${n}/hostname '~'
+  pcp -w ${basename}${n} ${basename}${n}/myid $ZK_DIR/conf
+done
+
+dsh -g $basename 'sudo cp ~/hostname /etc' 
+dsh -g $basename 'sudo cp ~/hosts /etc' 
+dsh -g $basename "cd $ZK_LIB; sudo ln -s $ZK_DIR/conf/myid"
+
+dsh -g $basename 'sudo hostname `cat /etc/hostname`'
+
+for n in `seq 2 $NR_NODES`; do
+  pcp -w ${basename}${n} ${basename}${n}/onsdemo_edge.py 'ONOS/test-network/mininet'
+  pcp -w ${basename}${n} ${basename}${n}/tunnel_onos_edge.sh 'ONOS/test-network/mininet'
+done
+pcp -w ${basename}1 ${basename}1/tunnel_onos_core.sh 'ONOS/test-network/mininet'
+pcp -w ${basename}1 ${basename}1/onsdemo_core.py 'ONOS/test-network/mininet'
diff --git a/cluster-mgmt/cp-mininet.sh b/cluster-mgmt/cp-mininet.sh
new file mode 100755
index 0000000..c3d69fe
--- /dev/null
+++ b/cluster-mgmt/cp-mininet.sh
@@ -0,0 +1,29 @@
+#! /bin/bash
+USERNAME=ubuntu
+CASSANDRA_DIR='/home/ubuntu/apache-cassandra-1.1.4'
+ZK_DIR='/home/ubuntu/zookeeper-3.4.5'
+ZK_LIB='/var/lib/zookeeper'
+CASSANDRA_LIB='/var/lib/cassandra'
+
+if [ $# == 2 ]; then
+  NR_NODES=$1
+  basename=$2
+else
+  echo "$0 nr_nodes basename"
+  exit
+fi
+
+if [ ! -f ./cluster.txt ]; then
+  echo "Cannot find cluster.txt"
+  exit
+fi
+
+export CLUSTER="./cluster.txt"
+dsh -g $basename 'uname -a'
+
+for n in `seq 1 $NR_NODES`; do
+  pcp -w ${basename}${n} ${basename}${n}/onsdemo.py 'ONOS/test-network/mininet'
+  pcp -w ${basename}${n} ${basename}${n}/tunnel_onsdemo.sh 'ONOS/test-network/mininet'
+done
+dsh -g $basename 'chmod 755 ONOS/test-network/mininet/tunnel_onsdemo.sh'
+dsh -g $basename 'chmod 755 ONOS/test-network/mininet/onsdemo.py'
diff --git a/cluster-mgmt/func.sh b/cluster-mgmt/func.sh
new file mode 100755
index 0000000..e7d976d
--- /dev/null
+++ b/cluster-mgmt/func.sh
@@ -0,0 +1,109 @@
+USERNAME=ubuntu
+CASSANDRA_DIR='/home/ubuntu/apache-cassandra-1.1.4'
+ZK_DIR='/home/ubuntu/zookeeper-3.4.5'
+ONOS_DIR='/home/ubuntu/ONOS'
+ZK_LIB='/var/lib/zookeeper'
+CASSANDRA_LIB='/var/lib/cassandra'
+
+if [ x$CLUSTER == "x" ]; then
+  echo "CLUSTER is not set. Exitting."
+  exit
+fi
+if [ x$ONOS_CLUSTER_BASENAME == "x" ]; then
+  echo "ONOS_CLUSTER_BASENAME is not set. Exitting"
+  exit
+fi
+if [ x$ONOS_CLUSTER_NR_NODES == "x" ]; then
+  echo "ONOS_CLUSTER_NR_NODES is not set. Exitting"
+  exit
+fi
+
+export basename=$ONOS_CLUSTER_BASENAME
+export nr_nodes=$ONOS_CLUSTER_NR_NODES
+
+checkcluster () {
+  dsh -g $basename 'uname -a'
+}
+
+zk () {
+  case "$1" in
+    start)
+      echo "Starting ZK.."
+      dsh -g $basename "$ZK_DIR/bin/zkServer.sh start"
+      while [ 1 ]; do
+        nup=`dsh -g $basename "$ZK_DIR/bin/zkServer.sh status" | grep "Mode" | egrep "leader|follower" | wc -l`
+        if [ $nup == $nr_nodes ]; then
+          echo "everybody's up: $nup up of of $nr_nodes"
+          echo "ZK started"
+          break;
+        fi
+        echo "waiting for everybody's up: $nup up of of $nr_nodes"
+        sleep 1
+      done
+      ;;
+    stop)
+      echo "Stopping ZK.."
+      dsh -g $basename "$ZK_DIR/bin/zkServer.sh stop"
+      ;;
+    status)
+      echo "Checking ZK Status"
+      dsh -g $basename "$ZK_DIR/bin/zkServer.sh status"
+      ;;
+  esac
+}
+
+cassandra () {
+  case "$1" in
+    start)
+      echo "Starting Cassandra.."
+      echo "  start cassandra at the seed node"
+      dsh -w ${basename}1 "cd $ONOS_DIR; ./start-cassandra.sh start"
+      sleep 1
+      echo "  start cassandra in rest nodes"
+      dsh -g ${basename} -x ${basename}1 "cd $ONOS_DIR; ./start-cassandra.sh start"
+      while [ 1 ]; do
+        echo $$
+        dsh -w ${basename}1 "cd $ONOS_DIR; ./start-cassandra.sh status" > .cassandra_check.$$
+        cat .cassandra_check.$$
+        nup=`cat .cassandra_check.$$ | grep Normal |grep Up| wc -l`
+        if [ $nup == $nr_nodes ]; then
+          echo "everybody's up: $nup up of of $nr_nodes"
+          echo "Cassandra started"
+          break;
+        fi
+        echo "waiting for everybody's up: $nup up of of $nr_nodes"
+        sleep 1
+      done
+      ;;
+    stop)
+      echo "Stopping Cassandra.."
+      dsh -g ${basename} "cd $ONOS_DIR; ./start-cassandra.sh stop"
+      ;;
+    cleandb)
+      echo "Removing all data in db"
+      dsh -w ${basename}1 "cd $ONOS_DIR; ./scripts/cleanup-cassandra.sh"
+      ;;
+    status)
+      echo "Checking Cassandra Status"
+      dsh -w ${basename}1 "cd $ONOS_DIR; ./start-cassandra.sh status"
+      ;;
+  esac
+}
+
+onos () {
+  case "$1" in
+    start)
+      echo "Starting ONOS"
+      dsh -g ${basename} "cd $ONOS_DIR; ./start-onos.sh start"
+      dsh -w ${basename}1 "cd $ONOS_DIR; ./start-rest.sh start"
+      ;;
+    stop)
+      echo "Stop ONOS"
+      dsh -g ${basename} "cd $ONOS_DIR; ./start-onos.sh stop"
+      ;;
+    status)
+      echo "Checking ONOS Status"
+      dsh -g ${basename} "cd $ONOS_DIR; ./start-onos.sh status"
+      ;;
+  esac
+}
diff --git a/cluster-mgmt/make-config.sh b/cluster-mgmt/make-config.sh
new file mode 100755
index 0000000..b97a818
--- /dev/null
+++ b/cluster-mgmt/make-config.sh
@@ -0,0 +1,56 @@
+#! /bin/bash
+USERNAME=ubuntu
+if [ $# == 3 ]; then
+  NR_NODES=$1
+  basename=$2
+  hosts_file=$3
+else
+  echo "$0 nr_hodes basename hostfile"
+  exit
+fi
+
+for n in `seq 1 $NR_NODES`; do
+  rm -rf ${basename}${n}
+  mkdir ${basename}${n}
+  echo "${basename}${n}" > ${basename}${n}/hostname
+  echo $n > ${basename}${n}/myid
+done
+
+## ZK config ##
+cp template/zoo.cfg common/
+for n in `seq 1 $NR_NODES`; do
+ echo "server.${n}=${basename}${n}:2888:3888"
+done >> common/zoo.cfg
+
+## Cassandra config ##
+cat template/cassandra.yaml |\
+  sed "s/__SEED__/${basename}1/g" > common/cassandra.yaml
+
+## /etc/hosts ##
+cat template/hosts $hosts_file >  common/hosts
+
+## .ssh/known_hosts ##
+ssh-keyscan -H -t rsa github.com > common/known_hosts
+ssh-keyscan -H -t rsa onosnat >> common/known_hosts
+for n in `seq 1 $NR_NODES`; do
+  ssh-keyscan -H -t rsa ${basename}${n}
+done >> common/known_hosts
+
+echo "GROUP: $basename" > cluster.txt
+cat $hosts_file | awk '{print $2}' >> cluster.txt
+
+
+## Creating shell script to login each node ##
+for n in `seq 1 $NR_NODES`; do
+  cat << EOF > bin/${basename}${n}
+#!/bin/sh
+ssh $USERNAME@${basename}${n}
+EOF
+  chmod 755 bin/${basename}${n}
+done
+
+echo "======================================"
+echo "Do not forget to do the following"
+echo "paste $hosts_file to /etc/hosts"
+echo "paste cluster.txt to your CLUSTER file"
+echo "======================================"
diff --git a/cluster-mgmt/make-mininet.sh b/cluster-mgmt/make-mininet.sh
new file mode 100755
index 0000000..e314114
--- /dev/null
+++ b/cluster-mgmt/make-mininet.sh
@@ -0,0 +1,31 @@
+#! /bin/bash
+if [ $# == 3 ]; then
+  NR_NODES=$1
+  basename=$2
+  hosts_file=$3
+else
+  echo "$0 nr_hodes basename hostfile"
+  exit
+fi
+
+for n in `seq 2 $NR_NODES`; do
+  if [ $n == 2 ]; then
+    nrsw=50
+  else
+    nrsw=25
+  fi
+  cat template/onsdemo_edge_template.py | sed "s/__NWID__/$n/g" | sed "s/__NRSW__/${nrsw}/g" > ${basename}${n}/onsdemo.py
+done
+cp template/onsdemo_core.py ${basename}1/onsdemo.py
+
+cat hosts  | awk '{printf("%s=%s\n",$2,$1)}' > .tmp
+for n in `seq 2 $NR_NODES`; do
+  cat template/tunnel_onsdemo_edge_template.sh | awk '{if(NR==2){system("cat .tmp")}else{print $0}}' |\
+  sed "s/__NWID__/$n/g" |\
+  sed "s/__TUNNEL__/TUNNEL\=\(\"1 $n ${basename}1\"\)/g" > ${basename}${n}/tunnel_onsdemo.sh
+  chmod 755 ${basename}${n}/tunnel_onsdemo.sh
+done
+
+cat template/tunnel_onsdemo_core_template.sh | awk '{if(NR==2){system("cat .tmp")}else{print $0}}' |\
+  sed "s/__basename__/$basename/g" > ${basename}1/tunnel_onsdemo.sh 
+  chmod 755 ${basename}1/tunnel_onsdemo.sh
diff --git a/cluster-mgmt/ssh/authorized_keys b/cluster-mgmt/ssh/authorized_keys
new file mode 100644
index 0000000..f723bc2
--- /dev/null
+++ b/cluster-mgmt/ssh/authorized_keys
@@ -0,0 +1,2 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCTlBTIOKm30b7TsCgIT+xjq42q0zwG+EohOGkCtNr1eGkS9OZDYwkNAkPtpzYtZJ914oRL29JiXFm+OsAfwVKsY2yZlV+tcnTx4Djfhgs6/wURMhw3sOovWu2iAoPAhQYvvvq8maD8ZvybYTzq4yHNP27G7rv4s+GCtv3bXOgzsKd8Zkg0+tGZYuCks5mNimlfWGBlA5jI9MEkd0nWTqSTRj8IkfhJo26HralR+X/KwHGryfxjG9rsyqoZGnVC/xV4KOOtZlVRzTVxCDFPj86lO4dzf7Tt+dst/t/9u/V2d7YxnuhaM+Sarve+6f/tZoekWzpNRGGT9h7FzT7Osg+l onlab-gui
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEHmYMw6DugE6FCoLR5fdTO7iQfouHmLm60yxSjXu/wnBGmM7SGc1AAgmtr6JaEPYj8H6g7AL8+wFrbj7TXOoMD4HWoEzC/PuTZ5JgyCeTK/rmYdBlbAqBbLeD1d9q35O+GnWOsLIsSQHcKvKZveLLPTBtzJ6em9NfgiPKibbsAFD716w++cxXKHabzHw7KB9XaewoYdznrosWwU3TXR4C2rzMAimh6XuBLZ0xFTNF4nFhy+H0AWUEN8dY8NHwAMGlAWK4g7phZ2cQhgU4GeutfGlEKlKT3iT7j8rkW1JKsx/AOVfcnozuHCm76jYD5qXcizHeS4BYinXRepGY7mfn onlabkey
diff --git a/cluster-mgmt/ssh/id_rsa.pub b/cluster-mgmt/ssh/id_rsa.pub
new file mode 100644
index 0000000..bcb2d75
--- /dev/null
+++ b/cluster-mgmt/ssh/id_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC3QgAX4yEcOHaKFgeq/tD2lbGg5VbNvRka1atUSd5q8hhtw5rB8um5Q5Z6+AfL83+Xlez2KonH6JLjhhs8wBHaJCVbzvDnycMEEHg12o+MvlKgKTkkSqP9W+Jejk4YGIr6QOQ/yzZRhRGoNGMaqI6KU7NjtgZyZs8h66GTyoBeXi9TZwGYdxeF5rVqZD80nlb+xlc+PUC4TQ/o2RnGej7S0J/+ES+/X6LiNgHyZPdFK2Pr4BilLwS8c5EyAHHQuW8hIcPhNwXgrx97f5L8yuNKAmW9WSYLk0r4DhnFUZrvIGqh3isxtnJDDf3UZ2U+PtGZ75ZNfk546obsuyc/IwHH ubuntu@onos9vpc
diff --git a/cluster-mgmt/start-mininet.sh b/cluster-mgmt/start-mininet.sh
new file mode 100755
index 0000000..46a0239
--- /dev/null
+++ b/cluster-mgmt/start-mininet.sh
@@ -0,0 +1,21 @@
+#! /bin/bash
+USERNAME=ubuntu
+CASSANDRA_DIR='/home/ubuntu/apache-cassandra-1.1.4'
+ZK_DIR='/home/ubuntu/zookeeper-3.4.5'
+ZK_LIB='/var/lib/zookeeper'
+CASSANDRA_LIB='/var/lib/cassandra'
+
+if [ $# == 1 ]; then
+  basename=$1
+else
+  echo "$0 basename"
+  exit
+fi
+
+export CLUSTER="./cluster.txt"
+dsh -g $basename 'uname -a'
+
+#dsh -g ${basename} 'cd ONOS/test-network/mininet; ./tunnel_onsdemo.sh start'
+#dsh -g ${basename} 'cd ONOS/test-network/mininet; ./tunnel_onsdemo.sh start'
+dsh -g ${basename} 'cd ONOS/test-network/mininet; sudo mn -c'
+dsh -g ${basename} 'cd ONOS/test-network/mininet; sudo ./onsdemo.py -n'
diff --git a/cluster-mgmt/template/cassandra.yaml b/cluster-mgmt/template/cassandra.yaml
new file mode 100644
index 0000000..ab79cdc
--- /dev/null
+++ b/cluster-mgmt/template/cassandra.yaml
@@ -0,0 +1,568 @@
+# Cassandra storage config YAML 
+
+# NOTE:
+#   See http://wiki.apache.org/cassandra/StorageConfiguration for
+#   full explanations of configuration directives
+# /NOTE
+
+# The name of the cluster. This is mainly used to prevent machines in
+# one logical cluster from joining another.
+cluster_name: 'ONOS Test Cluster'
+
+# You should always specify InitialToken when setting up a production
+# cluster for the first time, and often when adding capacity later.
+# The principle is that each node should be given an equal slice of
+# the token ring; see http://wiki.apache.org/cassandra/Operations
+# for more details.
+#
+# If blank, Cassandra will request a token bisecting the range of
+# the heaviest-loaded existing node.  If there is no load information
+# available, such as is the case with a new cluster, it will pick
+# a random token, which will lead to hot spots.
+initial_token:
+
+# See http://wiki.apache.org/cassandra/HintedHandoff
+hinted_handoff_enabled: true
+# this defines the maximum amount of time a dead host will have hints
+# generated.  After it has been dead this long, hints will be dropped.
+max_hint_window_in_ms: 3600000 # one hour
+# Sleep this long after delivering each hint
+hinted_handoff_throttle_delay_in_ms: 1
+
+# The following setting populates the page cache on memtable flush and compaction
+# WARNING: Enable this setting only when the whole node's data fits in memory.
+# Defaults to: false
+# populate_io_cache_on_flush: false
+
+# authentication backend, implementing IAuthenticator; used to identify users
+authenticator: org.apache.cassandra.auth.AllowAllAuthenticator
+
+# authorization backend, implementing IAuthority; used to limit access/provide permissions
+authority: org.apache.cassandra.auth.AllowAllAuthority
+
+# The partitioner is responsible for distributing rows (by key) across
+# nodes in the cluster.  Any IPartitioner may be used, including your
+# own as long as it is on the classpath.  Out of the box, Cassandra
+# provides org.apache.cassandra.dht.RandomPartitioner
+# org.apache.cassandra.dht.ByteOrderedPartitioner,
+# org.apache.cassandra.dht.OrderPreservingPartitioner (deprecated),
+# and org.apache.cassandra.dht.CollatingOrderPreservingPartitioner
+# (deprecated).
+# 
+# - RandomPartitioner distributes rows across the cluster evenly by md5.
+#   When in doubt, this is the best option.
+# - ByteOrderedPartitioner orders rows lexically by key bytes.  BOP allows
+#   scanning rows in key order, but the ordering can generate hot spots
+#   for sequential insertion workloads.
+# - OrderPreservingPartitioner is an obsolete form of BOP, that stores
+# - keys in a less-efficient format and only works with keys that are
+#   UTF8-encoded Strings.
+# - CollatingOPP colates according to EN,US rules rather than lexical byte
+#   ordering.  Use this as an example if you need custom collation.
+#
+# See http://wiki.apache.org/cassandra/Operations for more on
+# partitioners and token selection.
+partitioner: org.apache.cassandra.dht.RandomPartitioner
+
+# directories where Cassandra should store data on disk.
+data_file_directories:
+    - /var/lib/cassandra/data
+
+# commit log
+commitlog_directory: /var/lib/cassandra/commitlog
+
+# Maximum size of the key cache in memory.
+#
+# Each key cache hit saves 1 seek and each row cache hit saves 2 seeks at the
+# minimum, sometimes more. The key cache is fairly tiny for the amount of
+# time it saves, so it's worthwhile to use it at large numbers.
+# The row cache saves even more time, but must store the whole values of
+# its rows, so it is extremely space-intensive. It's best to only use the
+# row cache if you have hot rows or static rows.
+#
+# NOTE: if you reduce the size, you may not get you hottest keys loaded on startup.
+#
+# Default value is empty to make it "auto" (min(5% of Heap (in MB), 100MB)). Set to 0 to disable key cache.
+key_cache_size_in_mb:
+
+# Duration in seconds after which Cassandra should
+# safe the keys cache. Caches are saved to saved_caches_directory as
+# specified in this configuration file.
+#
+# Saved caches greatly improve cold-start speeds, and is relatively cheap in
+# terms of I/O for the key cache. Row cache saving is much more expensive and
+# has limited use.
+#
+# Default is 14400 or 4 hours.
+key_cache_save_period: 14400
+
+# Number of keys from the key cache to save
+# Disabled by default, meaning all keys are going to be saved
+# key_cache_keys_to_save: 100
+
+# Maximum size of the row cache in memory.
+# NOTE: if you reduce the size, you may not get you hottest keys loaded on startup.
+#
+# Default value is 0, to disable row caching.
+row_cache_size_in_mb: 0
+
+# Duration in seconds after which Cassandra should
+# safe the row cache. Caches are saved to saved_caches_directory as specified
+# in this configuration file.
+#
+# Saved caches greatly improve cold-start speeds, and is relatively cheap in
+# terms of I/O for the key cache. Row cache saving is much more expensive and
+# has limited use.
+#
+# Default is 0 to disable saving the row cache.
+row_cache_save_period: 0
+
+# Number of keys from the row cache to save
+# Disabled by default, meaning all keys are going to be saved
+# row_cache_keys_to_save: 100
+
+# The provider for the row cache to use.
+#
+# Supported values are: ConcurrentLinkedHashCacheProvider, SerializingCacheProvider
+#
+# SerializingCacheProvider serialises the contents of the row and stores
+# it in native memory, i.e., off the JVM Heap. Serialized rows take
+# significantly less memory than "live" rows in the JVM, so you can cache
+# more rows in a given memory footprint.  And storing the cache off-heap
+# means you can use smaller heap sizes, reducing the impact of GC pauses.
+#
+# It is also valid to specify the fully-qualified class name to a class
+# that implements org.apache.cassandra.cache.IRowCacheProvider.
+#
+# Defaults to SerializingCacheProvider
+row_cache_provider: SerializingCacheProvider
+
+# saved caches
+saved_caches_directory: /var/lib/cassandra/saved_caches
+
+# commitlog_sync may be either "periodic" or "batch." 
+# When in batch mode, Cassandra won't ack writes until the commit log
+# has been fsynced to disk.  It will wait up to
+# commitlog_sync_batch_window_in_ms milliseconds for other writes, before
+# performing the sync.
+#
+# commitlog_sync: batch
+# commitlog_sync_batch_window_in_ms: 50
+#
+# the other option is "periodic" where writes may be acked immediately
+# and the CommitLog is simply synced every commitlog_sync_period_in_ms
+# milliseconds.
+commitlog_sync: periodic
+commitlog_sync_period_in_ms: 10000
+
+# The size of the individual commitlog file segments.  A commitlog
+# segment may be archived, deleted, or recycled once all the data
+# in it (potentally from each columnfamily in the system) has been 
+# flushed to sstables.  
+#
+# The default size is 32, which is almost always fine, but if you are
+# archiving commitlog segments (see commitlog_archiving.properties),
+# then you probably want a finer granularity of archiving; 8 or 16 MB
+# is reasonable.
+commitlog_segment_size_in_mb: 32
+
+# any class that implements the SeedProvider interface and has a
+# constructor that takes a Map<String, String> of parameters will do.
+seed_provider:
+    # Addresses of hosts that are deemed contact points. 
+    # Cassandra nodes use this list of hosts to find each other and learn
+    # the topology of the ring.  You must change this if you are running
+    # multiple nodes!
+    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
+      parameters:
+          # seeds is actually a comma-delimited list of addresses.
+          # Ex: "<ip1>,<ip2>,<ip3>"
+#          - seeds: "10.0.1.243"
+          - seeds: "__SEED__"
+
+# emergency pressure valve: each time heap usage after a full (CMS)
+# garbage collection is above this fraction of the max, Cassandra will
+# flush the largest memtables.  
+#
+# Set to 1.0 to disable.  Setting this lower than
+# CMSInitiatingOccupancyFraction is not likely to be useful.
+#
+# RELYING ON THIS AS YOUR PRIMARY TUNING MECHANISM WILL WORK POORLY:
+# it is most effective under light to moderate load, or read-heavy
+# workloads; under truly massive write load, it will often be too
+# little, too late.
+flush_largest_memtables_at: 0.75
+
+# emergency pressure valve #2: the first time heap usage after a full
+# (CMS) garbage collection is above this fraction of the max,
+# Cassandra will reduce cache maximum _capacity_ to the given fraction
+# of the current _size_.  Should usually be set substantially above
+# flush_largest_memtables_at, since that will have less long-term
+# impact on the system.  
+# 
+# Set to 1.0 to disable.  Setting this lower than
+# CMSInitiatingOccupancyFraction is not likely to be useful.
+reduce_cache_sizes_at: 0.85
+reduce_cache_capacity_to: 0.6
+
+# For workloads with more data than can fit in memory, Cassandra's
+# bottleneck will be reads that need to fetch data from
+# disk. "concurrent_reads" should be set to (16 * number_of_drives) in
+# order to allow the operations to enqueue low enough in the stack
+# that the OS and drives can reorder them.
+#
+# On the other hand, since writes are almost never IO bound, the ideal
+# number of "concurrent_writes" is dependent on the number of cores in
+# your system; (8 * number_of_cores) is a good rule of thumb.
+concurrent_reads: 16
+concurrent_writes: 16
+
+# Total memory to use for memtables.  Cassandra will flush the largest
+# memtable when this much memory is used.
+# If omitted, Cassandra will set it to 1/3 of the heap.
+# memtable_total_space_in_mb: 2048
+
+# Total space to use for commitlogs.  Since commitlog segments are
+# mmapped, and hence use up address space, the default size is 32
+# on 32-bit JVMs, and 1024 on 64-bit JVMs.
+#
+# If space gets above this value (it will round up to the next nearest
+# segment multiple), Cassandra will flush every dirty CF in the oldest
+# segment and remove it.  So a small total commitlog space will tend
+# to cause more flush activity on less-active columnfamilies.
+# commitlog_total_space_in_mb: 4096
+
+# This sets the amount of memtable flush writer threads.  These will
+# be blocked by disk io, and each one will hold a memtable in memory
+# while blocked. If you have a large heap and many data directories,
+# you can increase this value for better flush performance.
+# By default this will be set to the amount of data directories defined.
+#memtable_flush_writers: 1
+
+# the number of full memtables to allow pending flush, that is,
+# waiting for a writer thread.  At a minimum, this should be set to
+# the maximum number of secondary indexes created on a single CF.
+memtable_flush_queue_size: 4
+
+# Whether to, when doing sequential writing, fsync() at intervals in
+# order to force the operating system to flush the dirty
+# buffers. Enable this to avoid sudden dirty buffer flushing from
+# impacting read latencies. Almost always a good idea on SSD:s; not
+# necessarily on platters.
+trickle_fsync: false
+trickle_fsync_interval_in_kb: 10240
+
+# TCP port, for commands and data
+storage_port: 7000
+
+# SSL port, for encrypted communication.  Unused unless enabled in
+# encryption_options
+ssl_storage_port: 7001
+
+# Address to bind to and tell other Cassandra nodes to connect to. You
+# _must_ change this if you want multiple nodes to be able to
+# communicate!
+# 
+# Leaving it blank leaves it up to InetAddress.getLocalHost(). This
+# will always do the Right Thing *if* the node is properly configured
+# (hostname, name resolution, etc), and the Right Thing is to use the
+# address associated with the hostname (it might not be).
+#
+# Setting this to 0.0.0.0 is always wrong.
+listen_address:
+
+# Address to broadcast to other Cassandra nodes
+# Leaving this blank will set it to the same value as listen_address
+# broadcast_address: 1.2.3.4
+
+# The address to bind the Thrift RPC service to -- clients connect
+# here. Unlike ListenAddress above, you *can* specify 0.0.0.0 here if
+# you want Thrift to listen on all interfaces.
+# 
+# Leaving this blank has the same effect it does for ListenAddress,
+# (i.e. it will be based on the configured hostname of the node).
+rpc_address: 0.0.0.0
+# port for Thrift to listen for clients on
+rpc_port: 9160
+
+# enable or disable keepalive on rpc connections
+rpc_keepalive: true
+
+# Cassandra provides three options for the RPC Server:
+#
+# sync  -> One connection per thread in the rpc pool (see below).
+#          For a very large number of clients, memory will be your limiting
+#          factor; on a 64 bit JVM, 128KB is the minimum stack size per thread.
+#          Connection pooling is very, very strongly recommended.
+#
+# async -> Nonblocking server implementation with one thread to serve 
+#          rpc connections.  This is not recommended for high throughput use
+#          cases. Async has been tested to be about 50% slower than sync
+#          or hsha and is deprecated: it will be removed in the next major release.
+#
+# hsha  -> Stands for "half synchronous, half asynchronous." The rpc thread pool 
+#          (see below) is used to manage requests, but the threads are multiplexed
+#          across the different clients.
+#
+# The default is sync because on Windows hsha is about 30% slower.  On Linux,
+# sync/hsha performance is about the same, with hsha of course using less memory.
+rpc_server_type: sync
+
+# Uncomment rpc_min|max|thread to set request pool size.
+# You would primarily set max for the sync server to safeguard against
+# misbehaved clients; if you do hit the max, Cassandra will block until one
+# disconnects before accepting more.  The defaults for sync are min of 16 and max
+# unlimited.
+# 
+# For the Hsha server, the min and max both default to quadruple the number of
+# CPU cores.
+#
+# This configuration is ignored by the async server.
+#
+# rpc_min_threads: 16
+# rpc_max_threads: 2048
+
+# uncomment to set socket buffer sizes on rpc connections
+# rpc_send_buff_size_in_bytes:
+# rpc_recv_buff_size_in_bytes:
+
+# Frame size for thrift (maximum field length).
+# 0 disables TFramedTransport in favor of TSocket. This option
+# is deprecated; we strongly recommend using Framed mode.
+thrift_framed_transport_size_in_mb: 15
+
+# The max length of a thrift message, including all fields and
+# internal thrift overhead.
+thrift_max_message_length_in_mb: 16
+
+# Set to true to have Cassandra create a hard link to each sstable
+# flushed or streamed locally in a backups/ subdirectory of the
+# Keyspace data.  Removing these links is the operator's
+# responsibility.
+incremental_backups: false
+
+# Whether or not to take a snapshot before each compaction.  Be
+# careful using this option, since Cassandra won't clean up the
+# snapshots for you.  Mostly useful if you're paranoid when there
+# is a data format change.
+snapshot_before_compaction: false
+
+# Whether or not a snapshot is taken of the data before keyspace truncation
+# or dropping of column families. The STRONGLY advised default of true 
+# should be used to provide data safety. If you set this flag to false, you will
+# lose data on truncation or drop.
+auto_snapshot: true
+
+# Add column indexes to a row after its contents reach this size.
+# Increase if your column values are large, or if you have a very large
+# number of columns.  The competing causes are, Cassandra has to
+# deserialize this much of the row to read a single column, so you want
+# it to be small - at least if you do many partial-row reads - but all
+# the index data is read for each access, so you don't want to generate
+# that wastefully either.
+column_index_size_in_kb: 64
+
+# Size limit for rows being compacted in memory.  Larger rows will spill
+# over to disk and use a slower two-pass compaction process.  A message
+# will be logged specifying the row key.
+in_memory_compaction_limit_in_mb: 64
+
+# Number of simultaneous compactions to allow, NOT including
+# validation "compactions" for anti-entropy repair.  Simultaneous
+# compactions can help preserve read performance in a mixed read/write
+# workload, by mitigating the tendency of small sstables to accumulate
+# during a single long running compactions. The default is usually
+# fine and if you experience problems with compaction running too
+# slowly or too fast, you should look at
+# compaction_throughput_mb_per_sec first.
+#
+# This setting has no effect on LeveledCompactionStrategy.
+#
+# concurrent_compactors defaults to the number of cores.
+# Uncomment to make compaction mono-threaded, the pre-0.8 default.
+#concurrent_compactors: 1
+
+# Multi-threaded compaction. When enabled, each compaction will use
+# up to one thread per core, plus one thread per sstable being merged.
+# This is usually only useful for SSD-based hardware: otherwise, 
+# your concern is usually to get compaction to do LESS i/o (see:
+# compaction_throughput_mb_per_sec), not more.
+multithreaded_compaction: false
+
+# Throttles compaction to the given total throughput across the entire
+# system. The faster you insert data, the faster you need to compact in
+# order to keep the sstable count down, but in general, setting this to
+# 16 to 32 times the rate you are inserting data is more than sufficient.
+# Setting this to 0 disables throttling. Note that this account for all types
+# of compaction, including validation compaction.
+compaction_throughput_mb_per_sec: 16
+
+# Track cached row keys during compaction, and re-cache their new
+# positions in the compacted sstable.  Disable if you use really large
+# key caches.
+compaction_preheat_key_cache: true
+
+# Throttles all outbound streaming file transfers on this node to the
+# given total throughput in Mbps. This is necessary because Cassandra does
+# mostly sequential IO when streaming data during bootstrap or repair, which
+# can lead to saturating the network connection and degrading rpc performance.
+# When unset, the default is 400 Mbps or 50 MB/s.
+# stream_throughput_outbound_megabits_per_sec: 400
+
+# Time to wait for a reply from other nodes before failing the command 
+rpc_timeout_in_ms: 10000
+
+# Enable socket timeout for streaming operation.
+# When a timeout occurs during streaming, streaming is retried from the start
+# of the current file. This *can* involve re-streaming an important amount of
+# data, so you should avoid setting the value too low.
+# Default value is 0, which never timeout streams.
+# streaming_socket_timeout_in_ms: 0
+
+# phi value that must be reached for a host to be marked down.
+# most users should never need to adjust this.
+# phi_convict_threshold: 8
+
+# endpoint_snitch -- Set this to a class that implements
+# IEndpointSnitch.  The snitch has two functions:
+# - it teaches Cassandra enough about your network topology to route
+#   requests efficiently
+# - it allows Cassandra to spread replicas around your cluster to avoid
+#   correlated failures. It does this by grouping machines into
+#   "datacenters" and "racks."  Cassandra will do its best not to have
+#   more than one replica on the same "rack" (which may not actually
+#   be a physical location)
+#
+# IF YOU CHANGE THE SNITCH AFTER DATA IS INSERTED INTO THE CLUSTER,
+# YOU MUST RUN A FULL REPAIR, SINCE THE SNITCH AFFECTS WHERE REPLICAS
+# ARE PLACED.
+#
+# Out of the box, Cassandra provides
+#  - SimpleSnitch:
+#    Treats Strategy order as proximity. This improves cache locality
+#    when disabling read repair, which can further improve throughput.
+#    Only appropriate for single-datacenter deployments.
+#  - PropertyFileSnitch:
+#    Proximity is determined by rack and data center, which are
+#    explicitly configured in cassandra-topology.properties.
+#  - GossipingPropertyFileSnitch
+#    The rack and datacenter for the local node are defined in
+#    cassandra-rackdc.properties and propagated to other nodes via gossip.  If
+#    cassandra-topology.properties exists, it is used as a fallback, allowing
+#    migration from the PropertyFileSnitch.
+#  - RackInferringSnitch:
+#    Proximity is determined by rack and data center, which are
+#    assumed to correspond to the 3rd and 2nd octet of each node's
+#    IP address, respectively.  Unless this happens to match your
+#    deployment conventions (as it did Facebook's), this is best used
+#    as an example of writing a custom Snitch class.
+#  - Ec2Snitch:
+#    Appropriate for EC2 deployments in a single Region.  Loads Region
+#    and Availability Zone information from the EC2 API. The Region is
+#    treated as the Datacenter, and the Availability Zone as the rack.
+#    Only private IPs are used, so this will not work across multiple
+#    Regions.
+#  - Ec2MultiRegionSnitch:
+#    Uses public IPs as broadcast_address to allow cross-region
+#    connectivity.  (Thus, you should set seed addresses to the public
+#    IP as well.) You will need to open the storage_port or
+#    ssl_storage_port on the public IP firewall.  (For intra-Region
+#    traffic, Cassandra will switch to the private IP after
+#    establishing a connection.)
+#
+# You can use a custom Snitch by setting this to the full class name
+# of the snitch, which will be assumed to be on your classpath.
+endpoint_snitch: SimpleSnitch
+
+# controls how often to perform the more expensive part of host score
+# calculation
+dynamic_snitch_update_interval_in_ms: 100 
+# controls how often to reset all host scores, allowing a bad host to
+# possibly recover
+dynamic_snitch_reset_interval_in_ms: 600000
+# if set greater than zero and read_repair_chance is < 1.0, this will allow
+# 'pinning' of replicas to hosts in order to increase cache capacity.
+# The badness threshold will control how much worse the pinned host has to be
+# before the dynamic snitch will prefer other replicas over it.  This is
+# expressed as a double which represents a percentage.  Thus, a value of
+# 0.2 means Cassandra would continue to prefer the static snitch values
+# until the pinned host was 20% worse than the fastest.
+dynamic_snitch_badness_threshold: 0.1
+
+# request_scheduler -- Set this to a class that implements
+# RequestScheduler, which will schedule incoming client requests
+# according to the specific policy. This is useful for multi-tenancy
+# with a single Cassandra cluster.
+# NOTE: This is specifically for requests from the client and does
+# not affect inter node communication.
+# org.apache.cassandra.scheduler.NoScheduler - No scheduling takes place
+# org.apache.cassandra.scheduler.RoundRobinScheduler - Round robin of
+# client requests to a node with a separate queue for each
+# request_scheduler_id. The scheduler is further customized by
+# request_scheduler_options as described below.
+request_scheduler: org.apache.cassandra.scheduler.NoScheduler
+
+# Scheduler Options vary based on the type of scheduler
+# NoScheduler - Has no options
+# RoundRobin
+#  - throttle_limit -- The throttle_limit is the number of in-flight
+#                      requests per client.  Requests beyond 
+#                      that limit are queued up until
+#                      running requests can complete.
+#                      The value of 80 here is twice the number of
+#                      concurrent_reads + concurrent_writes.
+#  - default_weight -- default_weight is optional and allows for
+#                      overriding the default which is 1.
+#  - weights -- Weights are optional and will default to 1 or the
+#               overridden default_weight. The weight translates into how
+#               many requests are handled during each turn of the
+#               RoundRobin, based on the scheduler id.
+#
+# request_scheduler_options:
+#    throttle_limit: 80
+#    default_weight: 5
+#    weights:
+#      Keyspace1: 1
+#      Keyspace2: 5
+
+# request_scheduler_id -- An identifer based on which to perform
+# the request scheduling. Currently the only valid option is keyspace.
+# request_scheduler_id: keyspace
+
+# index_interval controls the sampling of entries from the primrary
+# row index in terms of space versus time.  The larger the interval,
+# the smaller and less effective the sampling will be.  In technicial
+# terms, the interval coresponds to the number of index entries that
+# are skipped between taking each sample.  All the sampled entries
+# must fit in memory.  Generally, a value between 128 and 512 here
+# coupled with a large key cache size on CFs results in the best trade
+# offs.  This value is not often changed, however if you have many
+# very small rows (many to an OS page), then increasing this will
+# often lower memory usage without a impact on performance.
+index_interval: 128
+
+# Enable or disable inter-node encryption
+# Default settings are TLS v1, RSA 1024-bit keys (it is imperative that
+# users generate their own keys) TLS_RSA_WITH_AES_128_CBC_SHA as the cipher
+# suite for authentication, key exchange and encryption of the actual data transfers.
+# NOTE: No custom encryption options are enabled at the moment
+# The available internode options are : all, none, dc, rack
+#
+# If set to dc cassandra will encrypt the traffic between the DCs
+# If set to rack cassandra will encrypt the traffic between the racks
+#
+# The passwords used in these options must match the passwords used when generating
+# the keystore and truststore.  For instructions on generating these files, see:
+# http://download.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#CreateKeystore
+#
+encryption_options:
+    internode_encryption: none
+    keystore: conf/.keystore
+    keystore_password: cassandra
+    truststore: conf/.truststore
+    truststore_password: cassandra
+    # More advanced defaults below:
+    # protocol: TLS
+    # algorithm: SunX509
+    # store_type: JKS
+    # cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA]
diff --git a/cluster-mgmt/template/hosts b/cluster-mgmt/template/hosts
new file mode 100644
index 0000000..220b30f
--- /dev/null
+++ b/cluster-mgmt/template/hosts
@@ -0,0 +1,11 @@
+127.0.0.1 localhost
+
+# The following lines are desirable for IPv6 capable hosts
+::1 ip6-localhost ip6-loopback
+fe00::0 ip6-localnet
+ff00::0 ip6-mcastprefix
+ff02::1 ip6-allnodes
+ff02::2 ip6-allrouters
+ff02::3 ip6-allhosts
+
+## For ONOS Development
diff --git a/cluster-mgmt/template/onsdemo_core.py b/cluster-mgmt/template/onsdemo_core.py
new file mode 100755
index 0000000..e62ae77
--- /dev/null
+++ b/cluster-mgmt/template/onsdemo_core.py
@@ -0,0 +1,191 @@
+#!/usr/bin/python
+
+"""
+Start up a Simple topology
+"""
+from mininet.net import Mininet
+from mininet.node import Controller, RemoteController
+from mininet.log import setLogLevel, info, error, warn, debug
+from mininet.cli import CLI
+from mininet.topo import Topo
+from mininet.util import quietRun
+from mininet.moduledeps import pathCheck
+from mininet.link import Link, TCLink
+
+from sys import exit
+import os.path
+from subprocess import Popen, STDOUT, PIPE
+
+import sys
+
+
+#import argparse
+
+class MyController( Controller ):
+    def __init__( self, name, ip='127.0.0.1', port=6633, **kwargs):
+        """Init.
+           name: name to give controller
+           ip: the IP address where the remote controller is
+           listening
+           port: the port where the remote controller is listening"""
+        Controller.__init__( self, name, ip=ip, port=port, **kwargs )
+
+    def start( self ):
+        "Overridden to do nothing."
+        return
+
+    def stop( self ):
+        "Overridden to do nothing."
+        return
+
+    def checkListening( self ):
+        "Warn if remote controller is not accessible"
+        listening = self.cmd( "echo A | telnet -e A %s %d" %
+                              ( self.ip, self.port ) )
+        if 'Unable' in listening:
+            warn( "Unable to contact the remote controller"
+                  " at %s:%d\n" % ( self.ip, self.port ) )
+
+class SDNTopo( Topo ):
+    "SDN Topology"
+
+    def __init__( self, *args, **kwargs ):
+        Topo.__init__( self, *args, **kwargs )
+        sw1 = self.addSwitch('sw1', dpid='00:00:00:16:97:08:9a:46')
+        sw2 = self.addSwitch('sw2', dpid='00:00:00:00:ba:5e:ba:11')
+        sw3 = self.addSwitch('sw3', dpid='00:00:00:08:a2:08:f9:01')
+        sw4 = self.addSwitch('sw4', dpid='00:00:00:00:00:00:ba:12')
+        sw5 = self.addSwitch('sw5', dpid='00:00:00:00:ba:5e:ba:13')
+        sw6 = self.addSwitch('sw6', dpid='00:00:20:4e:7f:51:8a:35')
+
+        host1 = self.addHost( 'host1' )
+        host2 = self.addHost( 'host2' )
+        host3 = self.addHost( 'host3' )
+        host4 = self.addHost( 'host4' )
+        host5 = self.addHost( 'host5' )
+        host6 = self.addHost( 'host6' )
+
+        root1 = self.addHost( 'root1', inNamespace=False )
+        root2 = self.addHost( 'root2', inNamespace=False )
+        root3 = self.addHost( 'root3', inNamespace=False )
+        root4 = self.addHost( 'root4', inNamespace=False )
+        root5 = self.addHost( 'root5', inNamespace=False )
+        root6 = self.addHost( 'root6', inNamespace=False )
+
+
+        self.addLink( host1, sw1 )
+        self.addLink( host2, sw2 )
+        self.addLink( host3, sw3 )
+        self.addLink( host4, sw4 )
+        self.addLink( host5, sw5 )
+        self.addLink( host6, sw6 )
+
+
+        self.addLink( sw1, sw2 )
+        self.addLink( sw1, sw6 )
+        self.addLink( sw2, sw3 )
+        self.addLink( sw3, sw4 )
+        self.addLink( sw3, sw6 )
+        self.addLink( sw4, sw5 )
+        self.addLink( sw5, sw6 )
+
+        self.addLink( root1, host1 )
+        self.addLink( root2, host2 )
+        self.addLink( root3, host3 )
+        self.addLink( root4, host4 )
+        self.addLink( root5, host5 )
+        self.addLink( root6, host6 )
+
+def startsshd( host ):
+    "Start sshd on host"
+    info( '*** Starting sshd\n' )
+    name, intf, ip = host.name, host.defaultIntf(), host.IP()
+    banner = '/tmp/%s.banner' % name
+    host.cmd( 'echo "Welcome to %s at %s" >  %s' % ( name, ip, banner ) )
+    host.cmd( '/usr/sbin/sshd -o "Banner %s"' % banner, '-o "UseDNS no"' )
+    info( '***', host.name, 'is running sshd on', intf, 'at', ip, '\n' )
+
+def startsshds ( hosts ):
+    for h in hosts:
+        startsshd( h )
+
+def stopsshd( ):
+    "Stop *all* sshd processes with a custom banner"
+    info( '*** Shutting down stale sshd/Banner processes ',
+          quietRun( "pkill -9 -f Banner" ), '\n' )
+
+def sdnnet(opt):
+#    os.system('/home/ubuntu/openflow/controller/controller ptcp: &')
+#    os.system('/home/ubuntu/openflow/controller/controller ptcp:7000 &')
+
+    topo = SDNTopo()
+    info( '*** Creating network\n' )
+#    net = Mininet( topo=topo, controller=RemoteController )
+    net = Mininet( topo=topo, controller=MyController, link=TCLink)
+#    dc = DebugController('c3', ip='127.0.0.1', port=7000)
+#    net.addController(dc)
+#    net.addController(controller=RemoteController)
+
+    host1, host2, host3, host4, host5, host6 = net.get( 'host1', 'host2', 'host3', 'host4', 'host5', 'host6')
+
+    ## Adding 2nd, 3rd and 4th interface to host1 connected to sw1 (for another BGP peering)
+    sw1 = net.get('sw1')
+    sw2 = net.get('sw2')
+    sw3 = net.get('sw3')
+    sw4 = net.get('sw4')
+    sw5 = net.get('sw5')
+    sw6 = net.get('sw6')
+
+    net.start()
+
+    sw2.attach('tap01_2')
+    sw3.attach('tap01_3')
+    sw4.attach('tap01_4')
+    sw4.attach('tap01_5')
+    sw5.attach('tap01_6')
+    sw6.attach('tap01_7')
+    sw1.attach('tap01_8')
+
+    host1.defaultIntf().setIP('192.168.100.141/16') 
+    host2.defaultIntf().setIP('192.168.100.142/16')
+    host3.defaultIntf().setIP('192.168.100.143/16')
+    host4.defaultIntf().setIP('192.168.100.144/16')
+    host5.defaultIntf().setIP('192.168.100.145/16')
+    host6.defaultIntf().setIP('192.168.100.146/16')
+
+    root1, root2, root3, root4, root5, root6  = net.get( 'root1', 'root2', 'root3', 'root4', 'root5', 'root6' )
+    host1.intf('host1-eth1').setIP('1.1.1.1/24')
+    root1.intf('root1-eth0').setIP('1.1.1.2/24')
+
+    host2.intf('host2-eth1') .setIP('1.1.2.1/24')
+    root2.intf('root2-eth0').setIP('1.1.2.2/24')
+
+    host3.intf('host3-eth1') .setIP('1.1.3.1/24')
+    root3.intf('root3-eth0').setIP('1.1.3.2/24')
+
+    host4.intf('host4-eth1') .setIP('1.1.4.1/24')
+    root4.intf('root4-eth0').setIP('1.1.4.2/24')
+
+    host5.intf('host5-eth1') .setIP('1.1.5.1/24')
+    root5.intf('root5-eth0').setIP('1.1.5.2/24')
+
+    host6.intf('host6-eth1') .setIP('1.1.6.1/24')
+    root6.intf('root6-eth0').setIP('1.1.6.2/24')
+
+    hosts = [ host1, host2, host3, host4, host5, host6 ]
+    stopsshd ()
+    startsshds ( hosts )
+
+    if opt=="cli":
+        CLI(net)
+        stopsshd()
+        net.stop()
+
+if __name__ == '__main__':
+    setLogLevel( 'info' )
+    if len(sys.argv) == 1:
+      sdnnet("cli")
+    elif len(sys.argv) == 2 and sys.argv[1] == "-n":
+      sdnnet("nocli")
+    else:
+      print "%s [-n]" % sys.argv[0]
diff --git a/cluster-mgmt/template/onsdemo_edge_template.py b/cluster-mgmt/template/onsdemo_edge_template.py
new file mode 100755
index 0000000..a1ac11c
--- /dev/null
+++ b/cluster-mgmt/template/onsdemo_edge_template.py
@@ -0,0 +1,155 @@
+#!/usr/bin/python
+NWID=__NWID__
+NR_NODES=__NRSW__
+Controllers=[{"ip":"127.0.0.1", "port":6633}]
+
+"""
+Start up a Simple topology
+"""
+from mininet.net import Mininet
+from mininet.node import Controller, RemoteController
+from mininet.log import setLogLevel, info, error, warn, debug
+from mininet.cli import CLI
+from mininet.topo import Topo
+from mininet.util import quietRun
+from mininet.moduledeps import pathCheck
+from mininet.link import Link, TCLink
+
+from sys import exit
+import os.path
+from subprocess import Popen, STDOUT, PIPE
+
+import sys
+
+#import argparse
+
+class MyController( Controller ):
+    def __init__( self, name, ip='127.0.0.1', port=6633, **kwargs):
+        """Init.
+           name: name to give controller
+           ip: the IP address where the remote controller is
+           listening
+           port: the port where the remote controller is listening"""
+        Controller.__init__( self, name, ip=ip, port=port, **kwargs )
+
+    def start( self ):
+        "Overridden to do nothing."
+        return
+
+    def stop( self ):
+        "Overridden to do nothing."
+        return
+
+    def checkListening( self ):
+        "Warn if remote controller is not accessible"
+        listening = self.cmd( "echo A | telnet -e A %s %d" %
+                              ( self.ip, self.port ) )
+        if 'Unable' in listening:
+            warn( "Unable to contact the remote controller"
+                  " at %s:%d\n" % ( self.ip, self.port ) )
+
+class SDNTopo( Topo ):
+    "SDN Topology"
+
+    def __init__( self, *args, **kwargs ):
+        Topo.__init__( self, *args, **kwargs )
+
+        switch = []
+        host = []
+        root = []
+
+        for i in range (NR_NODES):
+            name_suffix = '%02d' % NWID + "." + '%02d' % (int(i)+1)
+            dpid_suffix = '%02x' % NWID + '%02x' % (int(i)+1)
+            dpid = '0000' + '0000' + '0000' + dpid_suffix
+            sw = self.addSwitch('sw'+name_suffix, dpid=dpid)
+            switch.append(sw)
+
+        for i in range (NR_NODES):
+            host.append(self.addHost( 'host%d' % (int(i)+1) ))
+            root.append(self.addHost( 'root%d' % (int(i)+1), inNamespace=False ))
+
+        for i in range (NR_NODES):
+            self.addLink(host[i], switch[i])
+
+        for i in range (1, NR_NODES):
+            self.addLink(switch[0], switch[i])
+
+        for i in range (NR_NODES):
+            self.addLink(root[i], host[i])
+
+def startsshd( host ):
+    "Start sshd on host"
+    info( '*** Starting sshd\n' )
+    name, intf, ip = host.name, host.defaultIntf(), host.IP()
+    banner = '/tmp/%s.banner' % name
+    host.cmd( 'echo "Welcome to %s at %s" >  %s' % ( name, ip, banner ) )
+    host.cmd( '/usr/sbin/sshd -o "Banner %s"' % banner, '-o "UseDNS no"' )
+    info( '***', host.name, 'is running sshd on', intf, 'at', ip, '\n' )
+
+def startsshds ( hosts ):
+    for h in hosts:
+        startsshd( h )
+
+def stopsshd( ):
+    "Stop *all* sshd processes with a custom banner"
+    info( '*** Shutting down stale sshd/Banner processes ',
+          quietRun( "pkill -9 -f Banner" ), '\n' )
+
+def sdnnet(opt):
+    topo = SDNTopo()
+    info( '*** Creating network\n' )
+    net = Mininet( topo=topo, controller=MyController, link=TCLink)
+    #net = Mininet( topo=topo, link=TCLink, build=False)
+    #controllers=[]
+    #for c in Controllers:
+    #  rc = RemoteController('c%d' % Controllers.index(c), ip=c['ip'],port=c['port'])
+    #  print "controller ip %s port %s" % (c['ip'], c['port'])
+    #  controllers.append(rc)
+
+    #net.controllers=controllers
+    net.build()
+
+    host = []
+    for i in range (NR_NODES):
+      host.append(net.get( 'host%d' % (int(i)+1) ))
+
+    net.start()
+
+    sw=net.get('sw%02x.%02x' % (NWID,1))
+    print "center sw", sw
+    sw.attach('tap%02x_1' % NWID)
+
+    for i in range (NR_NODES):
+        host[i].defaultIntf().setIP('192.168.%d.%d/16' % (NWID,(int(i)+1))) 
+        host[i].defaultIntf().setMAC('00:00:%02x:%02x:%02x:%02x' % (192,168,NWID,(int(i)+1))) 
+
+    for i in range (NR_NODES):
+       for n in range (1,8):
+         for h in range (25):
+           host[i].setARP('192.168.%d.%d' % (n, (int(h)+1)), '00:00:%02x:%02x:%02x:%02x' % (192,168,n,(int(h)+1))) 
+
+    root = []
+    for i in range (NR_NODES):
+        root.append(net.get( 'root%d' % (int(i)+1) ))
+
+    for i in range (NR_NODES):
+        host[i].intf('host%d-eth1' % (int(i)+1)).setIP('1.1.%d.1/24' % (int(i)+1))
+        root[i].intf('root%d-eth0' % (int(i)+1)).setIP('1.1.%d.2/24' % (int(i)+1))
+
+    stopsshd ()
+    startsshds ( host )
+
+    if opt=="cli":
+        CLI(net)
+        stopsshd()
+        net.stop()
+
+if __name__ == '__main__':
+    setLogLevel( 'info' )
+    if len(sys.argv) == 1:
+      sdnnet("cli")
+    elif len(sys.argv) == 2 and sys.argv[1] == "-n":
+      sdnnet("nocli")
+    else:
+      print "%s [-n]" % sys.argv[0]
diff --git a/cluster-mgmt/template/tunnel_onsdemo_core_template.sh b/cluster-mgmt/template/tunnel_onsdemo_core_template.sh
new file mode 100755
index 0000000..d697c6c
--- /dev/null
+++ b/cluster-mgmt/template/tunnel_onsdemo_core_template.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+TUNNEL=( "2 2 __basename__2" "3 3 __basename__3" "4 4 __basename__4" "5 5 __basename__5" "6 6 __basename__6" "7 7 __basename__7" "8 8 __basename__8")
+NW_ID=01
+
+start () {
+  ## Modify ##
+  ulimit -c
+  for (( i = 0; i< ${#TUNNEL[@]}; i ++)); do
+    t=`echo ${TUNNEL[$i]}`
+    ifnr=`echo $t | awk '{print $1}'`
+    tun_tag=`echo $t | awk '{print $2}'`
+    tun_end_=`echo $t | awk '{print $3}'`
+    tun_end=`eval echo '$'$tun_end_`
+    ifconfig tap${NW_ID}_${ifnr}
+    echo "ifconfig tap${NW_ID}_${ifnr}"
+    if [ $? -ne 0 ]; then
+      echo "creating tap${NW_ID}_${ifnr}"
+      sudo tunctl -t tap${NW_ID}_${ifnr} 
+    fi
+    echo "./capsulator -v -d -t eth0 -f ${tun_end} -vb tap${NW_ID}_${ifnr}#${tun_tag}"
+    sudo ifconfig tap${NW_ID}_${ifnr} 0.0.0.0 up > /dev/null 2>&1
+    sudo ./capsulator -v -d -t eth0 -f ${tun_end} -vb tap${NW_ID}_${ifnr}#${tun_tag}  > /dev/null 2>&1 &
+  done
+}
+
+stop () {
+  sudo pkill capsulator
+}
+
+case "$1" in
+  start | restart)
+    stop
+    start
+    ;;
+  stop)
+    stop
+    ;;
+  status)
+    nr=`pgrep capsulator | wc -l`
+    if [ $nr -gt 0 ]; then
+      echo "$nr tunnel(s) is running"
+    else
+      echo "tunnel is not running"
+    fi
+    ;;
+  *)
+    echo "Usage: $0 {start|stop|restart|status}" >&2
+    exit 1
+    ;;
+esac
diff --git a/cluster-mgmt/template/tunnel_onsdemo_edge_template.sh b/cluster-mgmt/template/tunnel_onsdemo_edge_template.sh
new file mode 100755
index 0000000..bbd7274
--- /dev/null
+++ b/cluster-mgmt/template/tunnel_onsdemo_edge_template.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+#TUNNEL=("0 1 VIP_ONOS10" "1 2 VIP_ONOS10") 
+__TUNNEL__
+NW_ID=0__NWID__
+
+start () {
+  ## Modify ##
+  ulimit -c
+  for (( i = 0; i< ${#TUNNEL[@]}; i ++)); do
+    t=`echo ${TUNNEL[$i]}`
+    ifnr=`echo $t | awk '{print $1}'`
+    tun_tag=`echo $t | awk '{print $2}'`
+    tun_end_=`echo $t | awk '{print $3}'`
+    tun_end=`eval echo '$'$tun_end_`
+    ifconfig tap${NW_ID}_${ifnr}
+    echo "ifconfig tap${NW_ID}_${ifnr}"
+    if [ $? -ne 0 ]; then
+      echo "creating tap${NW_ID}_${ifnr}"
+      sudo tunctl -t tap${NW_ID}_${ifnr} 
+    fi
+    echo "./capsulator -v -d -t eth0 -f ${tun_end} -vb tap${NW_ID}_${ifnr}#${tun_tag}"
+    sudo ifconfig tap${NW_ID}_${ifnr} 0.0.0.0 up > /dev/null 2>&1
+    sudo ./capsulator -v -d -t eth0 -f ${tun_end} -vb tap${NW_ID}_${ifnr}#${tun_tag}  > /dev/null 2>&1 &
+  done
+}
+
+stop () {
+  sudo pkill capsulator
+}
+
+case "$1" in
+  start | restart)
+    stop
+    start
+    ;;
+  stop)
+    stop
+    ;;
+  status)
+    nr=`pgrep capsulator | wc -l`
+    if [ $nr -gt 0 ]; then
+      echo "$nr tunnel(s) is running"
+    else
+      echo "tunnel is not running"
+    fi
+    ;;
+  *)
+    echo "Usage: $0 {start|stop|restart|status}" >&2
+    exit 1
+    ;;
+esac
diff --git a/cluster-mgmt/template/zoo.cfg b/cluster-mgmt/template/zoo.cfg
new file mode 100644
index 0000000..e1ab8c3
--- /dev/null
+++ b/cluster-mgmt/template/zoo.cfg
@@ -0,0 +1,41 @@
+# The number of milliseconds of each tick
+tickTime=2000
+# The number of ticks that the initial 
+# synchronization phase can take
+initLimit=10
+# The number of ticks that can pass between 
+# sending a request and getting an acknowledgement
+syncLimit=5
+# the directory where the snapshot is stored.
+# do not use /tmp for storage, /tmp here is just 
+# example sakes.
+dataDir=/var/lib/zookeeper
+# the port at which the clients will connect
+clientPort=2181
+#
+# specify all servers in the Zookeeper ensemble
+
+#server.1=onosgui1:2888:3888
+#server.2=onosgui2:2888:3888
+#server.3=onosgui3:2888:3888
+#server.4=onosgui4:2888:3888
+#server.5=onosgui5:2888:3888
+#server.6=onosgui6:2888:3888
+#server.7=onosgui7:2888:3888
+#server.8=onosgui8:2888:3888
+#
+#
+# Be sure to read the maintenance section of the 
+# administrator guide before turning on autopurge.
+#
+#
+# Be sure to read the maintenance section of the 
+# administrator guide before turning on autopurge.
+#
+# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
+#
+# The number of snapshots to retain in dataDir
+#autopurge.snapRetainCount=3
+# Purge task interval in hours
+# Set to "0" to disable auto purge feature
+#autopurge.purgeInterval=1
diff --git a/scripts/check-cluster-hw.sh b/scripts/check-cluster-hw.sh
new file mode 100755
index 0000000..1243e3a
--- /dev/null
+++ b/scripts/check-cluster-hw.sh
@@ -0,0 +1,30 @@
+#! /bin/bash
+
+# This checks the overall status of Cassandra, onos, zookeeper, and the web server 
+# Checks status on all 8 onos nodes.
+# Built to run only on the hw testbed from ONOS1.
+# 
+
+echo 	""
+echo    "****************************"
+echo 	"***** CASSANDRA STATUS *****"
+echo    "****************************"
+dsh -w onos1 'cd ONOS; ./start-cassandra.sh status'
+
+echo 	""
+echo    "***********************"
+echo 	"***** ONOS STATUS *****"
+echo    "***********************"
+dsh -g onos 'cd ONOS; ./start-onos.sh status; echo "Open ports on 9160: "; netstat -nat | grep 9160 | wc -l'
+
+echo 	""
+echo    "****************************"
+echo 	"***** ZOOKEEPER STATUS *****"
+echo    "****************************"
+dsh -g onos '~/zookeeper-3.4.5/bin/zkServer.sh status'
+
+echo 	""
+echo    "**************************"
+echo 	"***** WEB GUI STATUS *****"
+echo    "**************************"
+~/ONOS/start-rest.sh status
diff --git a/scripts/cleanup-cassandra.sh b/scripts/cleanup-cassandra.sh
new file mode 100755
index 0000000..a88ae6a
--- /dev/null
+++ b/scripts/cleanup-cassandra.sh
@@ -0,0 +1,3 @@
+#! /bin/bash
+DIR=~/ONOS
+~/titan-0.2.0/bin/gremlin.sh -e $DIR/scripts/cleanup-onos-db 
diff --git a/cleanup-onos-db b/scripts/cleanup-onos-db
similarity index 100%
rename from cleanup-onos-db
rename to scripts/cleanup-onos-db
diff --git a/ctrl-local.sh b/scripts/ctrl-local.sh
similarity index 100%
rename from ctrl-local.sh
rename to scripts/ctrl-local.sh
diff --git a/ctrl-none.sh b/scripts/ctrl-none.sh
similarity index 100%
rename from ctrl-none.sh
rename to scripts/ctrl-none.sh
diff --git a/delflow.sh b/scripts/delflow.sh
similarity index 100%
rename from delflow.sh
rename to scripts/delflow.sh
diff --git a/clean-cassandra.sh b/scripts/drop-keyspace.sh
similarity index 100%
rename from clean-cassandra.sh
rename to scripts/drop-keyspace.sh
diff --git a/showdpid.sh b/scripts/showdpid.sh
similarity index 100%
rename from showdpid.sh
rename to scripts/showdpid.sh
diff --git a/showflow.sh b/scripts/showflow.sh
similarity index 100%
rename from showflow.sh
rename to scripts/showflow.sh
diff --git a/ctrl-add-ext-template.sh b/scripts/template/ctrl-add-ext-template.sh
similarity index 100%
rename from ctrl-add-ext-template.sh
rename to scripts/template/ctrl-add-ext-template.sh
diff --git a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
index 2c19f68..e58b19f 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
@@ -62,10 +62,23 @@
 		@Property("number")
 		public Short getNumber();
 		
+		@Property("number")
+		public void setNumber(Short n);
+		
 		@JsonProperty("desc")
 		@Property("desc")
 		public String getDesc();
 		
+		@Property("desc")
+		public void setDesc(String s);
+		
+		@JsonIgnore
+		@Property("port_sate")
+		public Integer getPortState();
+		
+		@Property("port_state")
+		public void setPortState(Integer s);
+		
 		@JsonIgnore
 		@Incidence(label="on",direction = Direction.IN)
 		public ISwitchObject getSwitch();
diff --git a/src/main/java/net/floodlightcontroller/core/INetMapTopologyService.java b/src/main/java/net/floodlightcontroller/core/INetMapTopologyService.java
index b16e4a9..ecf217e 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyService.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyService.java
@@ -19,12 +19,14 @@
 		Iterable<ISwitchObject> getInactiveSwitches();
 		Iterable<IPortObject> getPortsOnSwitch(String dpid);
 		IPortObject getPortOnSwitch(String dpid, short port_num);
+		void close();
 
 	}
 	
 	public interface ITopoLinkService {
 		List<Link> getActiveLinks();
 		List<Link> getLinksOnSwitch(String dpid);
+		void close();
 	}
 	public interface ITopoDeviceService {
 		Iterable<IDeviceObject> getActiveDevices();
@@ -33,7 +35,74 @@
 	}
 	
 	public interface ITopoRouteService extends IFloodlightService {
+	    /**
+	     * Get the shortest path from a source to a destination.
+	     *
+	     * @param src the source in the shortest path computation.
+	     * @param dest the destination in the shortest path computation.
+	     * @return the data path with the computed shortest path if
+	     * found, otherwise null.
+	     */
 	    DataPath getShortestPath(SwitchPort src, SwitchPort dest);
+
+	    /**
+	     * Fetch the Switch and Ports info from the Titan Graph
+	     * and store it locally for fast access during the shortest path
+	     * computation.
+	     *
+	     * After fetching the state, method @ref getTopoShortestPath()
+	     * can be used for fast shortest path computation.
+	     *
+	     * Note: There is certain cost to fetch the state, hence it should
+	     * be used only when there is a large number of shortest path
+	     * computations that need to be done on the same topology.
+	     * Typically, a single call to @ref prepareShortestPathTopo()
+	     * should be followed by a large number of calls to
+	     * method @ref getTopoShortestPath().
+	     * After the last @ref getTopoShortestPath() call,
+	     * method @ref dropShortestPathTopo() should be used to release
+	     * the internal state that is not needed anymore:
+	     *
+	     *       prepareShortestPathTopo();
+	     *       for (int i = 0; i < 10000; i++) {
+	     *           dataPath = getTopoShortestPath(...);
+	     *           ...
+	     *        }
+	     *        dropShortestPathTopo();
+	     */
+	    void prepareShortestPathTopo();
+
+	    /**
+	     * Release the state that was populated by
+	     * method @ref prepareShortestPathTopo().
+	     *
+	     * See the documentation for method @ref prepareShortestPathTopo()
+	     * for additional information and usage.
+	     */
+	    void dropShortestPathTopo();
+
+	    /**
+	     * Get the shortest path from a source to a destination by
+	     * using the pre-populated local topology state prepared
+	     * by method @ref prepareShortestPathTopo().
+	     *
+	     * See the documentation for method @ref prepareShortestPathTopo()
+	     * for additional information and usage.
+	     *
+	     * @param src the source in the shortest path computation.
+	     * @param dest the destination in the shortest path computation.
+	     * @return the data path with the computed shortest path if
+	     * found, otherwise null.
+	     */
+	    DataPath getTopoShortestPath(SwitchPort src, SwitchPort dest);
+
+	    /**
+	     * Test whether a route exists from a source to a destination.
+	     *
+	     * @param src the source node for the test.
+	     * @param dest the destination node for the test.
+	     * @return true if a route exists, otherwise false.
+	     */
 	    Boolean routeExists(SwitchPort src, SwitchPort dest);
 	}
 	
diff --git a/src/main/java/net/floodlightcontroller/core/ISwitchStorage.java b/src/main/java/net/floodlightcontroller/core/ISwitchStorage.java
index 3646e15..1219aac 100644
--- a/src/main/java/net/floodlightcontroller/core/ISwitchStorage.java
+++ b/src/main/java/net/floodlightcontroller/core/ISwitchStorage.java
@@ -50,9 +50,6 @@
 	 */
 	public void deletePort(String dpid, String portName);
 	
-	public Iterable<ISwitchObject> getActiveSwitches();
-	public Iterable<ISwitchObject> getAllSwitches();
-	public Iterable<ISwitchObject> getInactiveSwitches();
 	
 	/*
 	 * Initialize
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 4057bc9..1a9a9c5 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -146,18 +146,8 @@
  */
 public class Controller implements IFloodlightProviderService, 
             IStorageSourceListener {
-   
-	ThreadLocal<SwitchStorageImpl> store = new ThreadLocal<SwitchStorageImpl>() {
-		@Override
-		protected SwitchStorageImpl initialValue() {
-			SwitchStorageImpl swStore = new SwitchStorageImpl();
-			//TODO: Get the file path from global properties
-			swStore.init("/tmp/cassandra.titan");
-			return swStore;
-		}
-	};
-	
-	protected SwitchStorageImpl swStore = store.get();
+   	
+	protected SwitchStorageImpl swStore;;
 	
     protected static Logger log = LoggerFactory.getLogger(Controller.class);
 
@@ -560,7 +550,9 @@
                     removeSwitch(sw);
                 }
                 synchronized(roleChanger) {
-                	registryService.releaseControl(sw.getId());
+                	if (controlRequested) {
+                		registryService.releaseControl(sw.getId());
+                	}
                     connectedSwitches.remove(sw);
                 }
                 sw.setConnected(false);
@@ -767,6 +759,7 @@
          */
         void sendHelloConfiguration() throws IOException {
             // Send initial Features Request
+        	log.debug("Sending FEATURES_REQUEST to {}", sw);
             sw.write(factory.getMessage(OFType.FEATURES_REQUEST), null);
         }
         
@@ -776,6 +769,7 @@
          * @throws IOException
          */
         void sendFeatureReplyConfiguration() throws IOException {
+        	log.debug("Sending CONFIG_REQUEST to {}", sw);
             // Ensure we receive the full packet via PacketIn
             OFSetConfig config = (OFSetConfig) factory
                     .getMessage(OFType.SET_CONFIG);
@@ -795,12 +789,15 @@
                     dfuture);
 
         }
-        
+ 
+      	volatile Boolean controlRequested = Boolean.FALSE;
         protected void checkSwitchReady() {
+  
             if (state.hsState == HandshakeState.FEATURES_REPLY &&
                     state.hasDescription && state.hasGetConfigReply) {
                 
                 state.hsState = HandshakeState.READY;
+                log.debug("Handshake with {} complete", sw);
                 
                 synchronized(roleChanger) {
                     // We need to keep track of all of the switches that are connected
@@ -821,10 +818,12 @@
                     	
                     	//Request control of the switch from the global registry
                     	try {
+                    		controlRequested = Boolean.TRUE;
 							registryService.requestControl(sw.getId(), 
 									new RoleChangeCallback());
 						} catch (RegistryException e) {
 							log.debug("Registry error: {}", e.getMessage());
+							controlRequested = Boolean.FALSE;
 						}
                     	
                     	
@@ -858,6 +857,18 @@
                         state.firstRoleReplyReceived = true;
                     }
                 }
+                if (!controlRequested) {
+                	// yield to allow other thread(s) to release control
+                	try {
+						Thread.sleep(10);
+					} catch (InterruptedException e) {
+						// Ignore interruptions						
+					}
+                	// safer to bounce the switch to reconnect here than proceeding further
+                	log.debug("Closing {} because we weren't able to request control " +
+                			"successfully" + sw);
+                	sw.channel.close();
+                }
             }
         }
                 
@@ -1084,6 +1095,7 @@
                     shouldHandleMessage = handleVendorMessage((OFVendor)m);
                     break;
                 case ERROR:
+                	log.debug("Recieved ERROR message from switch {}: {}", sw, m);
                     // TODO: we need better error handling. Especially for 
                     // request/reply style message (stats, roles) we should have
                     // a unified way to lookup the xid in the error message. 
@@ -1107,6 +1119,7 @@
                         // is not a spurious error
                         shouldLogError = !isBadVendorError;
                         if (isBadVendorError) {
+                        	log.debug("Handling bad vendor error for {}", sw);
                             if (state.firstRoleReplyReceived && (role != null)) {
                                 log.warn("Received ERROR from sw {} that "
                                           +"indicates roles are not supported "
@@ -1114,16 +1127,23 @@
                                           +"role reply earlier", sw);
                             }
                             state.firstRoleReplyReceived = true;
-                            sw.deliverRoleRequestNotSupported(error.getXid());
+                            Role requestedRole = 
+                            		sw.deliverRoleRequestNotSupported(error.getXid());
                             synchronized(roleChanger) {
                                 if (sw.role == null && Controller.this.role==Role.SLAVE) {
+                                	//This will now never happen. The Controller's role
+                                	//is now never SLAVE, always MASTER.
                                     // the switch doesn't understand role request
                                     // messages and the current controller role is
                                     // slave. We need to disconnect the switch. 
                                     // @see RoleChanger for rationale
+                                	log.warn("Closing {} channel because controller's role " +
+                                			"is SLAVE", sw);
                                     sw.getChannel().close();
                                 }
-                                else if (sw.role == null) {
+                                else if (sw.role == null && requestedRole == Role.MASTER) {
+                                	log.debug("Adding switch {} because we got an error" +
+                                			" returned from a MASTER role request", sw);
                                     // Controller's role is master: add to
                                     // active 
                                     // TODO: check if clearing flow table is
@@ -1156,6 +1176,8 @@
                             // to make sure that the switch eventually accepts one
                             // of our requests or disconnect the switch. This feels
                             // cumbersome. 
+                        	log.debug("Closing {} channel because we recieved an " + 
+                        			"error other than BAD_VENDOR", sw);
                             sw.getChannel().close();
                         }
                     }
@@ -1527,6 +1549,8 @@
                 // a "Not removing Switch ... already removed debug message.
                 // TODO: Figure out a way to handle this that avoids the
                 // spurious debug message.
+                log.debug("Closing {} because a new IOFSwitch got added " +
+                		"for this dpid", oldSw);
                 oldSw.getChannel().close();
             }
             finally {
@@ -2183,11 +2207,20 @@
         this.updates = new LinkedBlockingQueue<IUpdate>();
         this.factory = new BasicFactory();
         this.providerMap = new HashMap<String, List<IInfoProvider>>();
+        
         setConfigParams(configParams);
         //this.role = getInitialRole(configParams);
         //Set the controller's role to MASTER so it always tries to do role requests.
         this.role = Role.MASTER;
         this.roleChanger = new RoleChanger();
+        
+		String conf = configParams.get("dbconf");
+		if (conf == null) {
+			conf = "/tmp/cassandra.titan";
+		}
+		this.swStore = new SwitchStorageImpl();
+		this.swStore.init(conf);
+		
         initVendorMessages();
         this.systemStartTime = System.currentTimeMillis();
     }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
index 5ffd9bc..e0ff8c3 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
@@ -787,15 +787,19 @@
      * Otherwise we ignore it.
      * @param xid
      */
-    protected void deliverRoleRequestNotSupported(int xid) {
+    protected Role deliverRoleRequestNotSupported(int xid) {
         synchronized(pendingRoleRequests) {
             PendingRoleRequestEntry head = pendingRoleRequests.poll();
             this.role = null;
             if (head!=null && head.xid == xid) {
                 setAttribute(SWITCH_SUPPORTS_NX_ROLE, false);
+                return head.role;
             }
             else {
+            	log.debug("Closing {} because a role request error didn't match " + 
+            			"head of pendingRoleRequests queue", this);
                 this.channel.close();
+                return null;
             }
         }
     }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
index 6378136..b2de649 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/RoleChanger.java
@@ -275,10 +275,23 @@
                         sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE);
                 if ((supportsNxRole == null) || supportsNxRole) {
                     // Handle cases #1 and #2
+                	log.debug("Sending NxRoleRequest to {}", sw);
                     sw.sendNxRoleRequest(role, cookie);
-                } else {
-                    // Handle case #3
-                    if (role == Role.SLAVE) {
+                } else {         
+                	if (role == Role.MASTER) {
+                		log.debug("Switch {} doesn't support NxRoleRequests, but sending " + 
+                					"{} request anyway", sw, role);
+                		//Send the role request anyway, even though we know the switch
+                		//doesn't support it. The switch will give an error and in our
+                		//error handling code we will add the switch.
+                		//NOTE we *could* just add the switch right away rather than
+                		//going through the overhead of sending a role request - however
+                		//we then have to deal with concurrency issues resulting from
+                		//calling addSwitch outside of a netty handler.
+                		sw.sendNxRoleRequest(role, cookie);
+                	}
+                	// Handle case #3
+                	else if (role == Role.SLAVE) {
                         log.debug("Disconnecting switch {} that doesn't support " +
                         "role request messages from a controller that went to SLAVE mode");
                         // Closing the channel should result in a call to
diff --git a/src/main/java/net/floodlightcontroller/core/internal/SwitchStorageImpl.java b/src/main/java/net/floodlightcontroller/core/internal/SwitchStorageImpl.java
index 7e049b6..a068586 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/SwitchStorageImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/SwitchStorageImpl.java
@@ -1,31 +1,21 @@
 package net.floodlightcontroller.core.internal;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
-import java.util.Set;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
+import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.floodlightcontroller.core.ISwitchStorage;
+import net.onrc.onos.util.GraphDBConnection;
+import net.onrc.onos.util.GraphDBConnection.Transaction;
 
 import org.openflow.protocol.OFPhysicalPort;
 import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
 import org.openflow.protocol.OFPhysicalPort.OFPortState;
-
-import com.thinkaurelius.titan.core.TitanException;
-import com.thinkaurelius.titan.core.TitanFactory;
-import com.thinkaurelius.titan.core.TitanGraph;
-import com.tinkerpop.blueprints.Direction;
-import com.tinkerpop.blueprints.TransactionalGraph;
-import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
-import com.tinkerpop.blueprints.Edge;
-import com.tinkerpop.blueprints.Vertex;
-import com.tinkerpop.frames.FramedGraph;
-import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
-import net.floodlightcontroller.core.ISwitchStorage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class SwitchStorageImpl implements ISwitchStorage {
-	public TitanGraph graph;
+	public GraphDBConnection conn;
 	protected static Logger log = LoggerFactory.getLogger(SwitchStorageImpl.class);
 
 	@Override
@@ -50,26 +40,20 @@
 	}
 
 	private void setStatus(String dpid, SwitchState state) {
-		Vertex sw;
-		try {
-            if ((sw = graph.getVertices("dpid",dpid).iterator().next()) != null) {
-            	sw.setProperty("state",state.toString());
-            	graph.stopTransaction(Conclusion.SUCCESS);
-            	log.info("SwitchStorage:setStatus dpid:{} state: {} done", dpid, state);
-            }
-		} catch (TitanException e) {
-             // TODO: handle exceptions
-			graph.stopTransaction(Conclusion.FAILURE);
+		ISwitchObject sw = conn.utils().searchSwitch(conn, dpid);
+		if (sw != null) {
+			sw.setState(state.toString());
+			conn.endTx(Transaction.COMMIT);
+			log.info("SwitchStorage:setStatus dpid:{} state: {} done", dpid, state);
+		} 	else {
+			conn.endTx(Transaction.ROLLBACK);
 			log.info("SwitchStorage:setStatus dpid:{} state: {} failed", dpid, state);
 		}
-            	
-		
 	}
 
 	@Override
 	public void addPort(String dpid, OFPhysicalPort port) {
 		// TODO Auto-generated method stub
-		Vertex sw;
 		
         boolean portDown = ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0) ||
         		((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0);
@@ -77,30 +61,31 @@
              deletePort(dpid, port.getPortNumber());
              return;
        }
+             
 		try {
-            if ((sw = graph.getVertices("dpid",dpid).iterator().next()) != null) {
+			ISwitchObject sw = conn.utils().searchSwitch(conn, dpid);
+
+            if (sw != null) {
+            	IPortObject p = conn.utils().searchPort(conn, dpid, port.getPortNumber());
             	log.info("SwitchStorage:addPort dpid:{} port:{}", dpid, port.getPortNumber());
-            	// TODO: Check if port exists
-            	if (sw.query().direction(Direction.OUT).labels("on").has("number",port.getPortNumber()).vertices().iterator().hasNext()) {
-            		//TODO: Do nothing for now
+            	if (p != null) {
             		log.error("SwitchStorage:addPort dpid:{} port:{} exists", dpid, port.getPortNumber());
             	} else {
-            		Vertex p = graph.addVertex(null);
-            		p.setProperty("type","port");
-            		p.setProperty("number",port.getPortNumber());
-            		p.setProperty("state", "ACTIVE");
-            		p.setProperty("port_state",port.getState());
-            		p.setProperty("desc",port.getName());
-            		Edge e = graph.addEdge(null, sw, p, "on");
-            		e.setProperty("state","ACTIVE");
-            		e.setProperty("number", port.getPortNumber());
-                     	
-            		graph.stopTransaction(Conclusion.SUCCESS);
+            		p = conn.utils().newPort(conn);
+
+            		p.setType("port");
+            		p.setNumber(port.getPortNumber());
+            		p.setState("ACTIVE");
+            		p.setPortState(port.getState());
+            		p.setDesc(port.getName());
+            		sw.addPort(p);
+            		conn.endTx(Transaction.COMMIT);
+  
             	}
             }
-		} catch (TitanException e) {
+		} catch (Exception e) {
              // TODO: handle exceptions
-			graph.stopTransaction(Conclusion.FAILURE);
+			conn.endTx(Transaction.ROLLBACK);
 			log.error("SwitchStorage:addPort dpid:{} port:{} failed", dpid, port.getPortNumber());
 		}	
 
@@ -130,29 +115,29 @@
 		log.info("SwitchStorage:addSwitch(): dpid {} ", dpid);
 		
         try {
-            if (graph.getVertices("dpid",dpid).iterator().hasNext()) {
+        	ISwitchObject sw = conn.utils().searchSwitch(conn, dpid);
+            if (sw != null) {
                     /*
                      *  Do nothing or throw exception?
                      */
-            		Vertex sw = graph.getVertices("dpid",dpid).iterator().next();
             	
             		log.info("SwitchStorage:addSwitch dpid:{} already exists", dpid);
-            		sw.setProperty("state",SwitchState.ACTIVE.toString());
-            		graph.stopTransaction(Conclusion.SUCCESS);
+            		sw.setState(SwitchState.ACTIVE.toString());
+            		conn.endTx(Transaction.COMMIT);
             } else {
-                    Vertex sw = graph.addVertex(null);
+                    sw = conn.utils().newSwitch(conn);
 
-                    sw.setProperty("type","switch");
-                    sw.setProperty("dpid", dpid);
-                    sw.setProperty("state",SwitchState.ACTIVE.toString());
-                    graph.stopTransaction(Conclusion.SUCCESS);
+                    sw.setType("switch");
+                    sw.setDPID(dpid);
+                    sw.setState(SwitchState.ACTIVE.toString());
+                    conn.endTx(Transaction.COMMIT);
                     log.info("SwitchStorage:addSwitch dpid:{} added", dpid);
             }
-    } catch (TitanException e) {
+    } catch (Exception e) {
             /*
-             * retry till we succeed?
+             * retry?
              */
-    	graph.stopTransaction(Conclusion.FAILURE);
+    	conn.endTx(Transaction.ROLLBACK);
     	log.info("SwitchStorage:addSwitch dpid:{} failed", dpid);
     }
 
@@ -162,17 +147,19 @@
 	@Override
 	public void deleteSwitch(String dpid) {
 		// TODO Setting inactive but we need to eventually remove data
-		Vertex sw;
+
 		try {
-			
-            if ((sw = graph.getVertices("dpid",dpid).iterator().next()) != null) {
-            	graph.removeVertex(sw);
-            	graph.stopTransaction(Conclusion.SUCCESS);
+
+			ISwitchObject sw = conn.utils().searchSwitch(conn, dpid);
+            if (sw  != null) {
+            	conn.utils().removeSwitch(conn, sw);
+ 
+            	conn.endTx(Transaction.COMMIT);
             	log.info("SwitchStorage:DeleteSwitch dpid:{} done", dpid);
             }
-		} catch (TitanException e) {
+		} catch (Exception e) {
              // TODO: handle exceptions
-			graph.stopTransaction(Conclusion.FAILURE);
+			conn.endTx(Transaction.ROLLBACK);			
 			log.error("SwitchStorage:deleteSwitch {} failed", dpid);
 		}
 
@@ -181,21 +168,21 @@
 	@Override
 	public void deletePort(String dpid, short port) {
 		// TODO Auto-generated method stub
-		Vertex sw;
 		try {
-            if ((sw = graph.getVertices("dpid",dpid).iterator().next()) != null) {
-            	// TODO: Check if port exists
-            	log.info("SwitchStorage:deletePort dpid:{} port:{}", dpid, port);
-            	if (sw.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().hasNext()) {
-            		Vertex p = sw.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().next();
+			ISwitchObject sw = conn.utils().searchSwitch(conn, dpid);
+
+            if (sw != null) {
+            	IPortObject p = conn.utils().searchPort(conn, dpid, port);
+                if (p != null) {
             		log.info("SwitchStorage:deletePort dpid:{} port:{} found and deleted", dpid, port);
-            		graph.removeVertex(p);
-            		graph.stopTransaction(Conclusion.SUCCESS);
+            		sw.removePort(p);
+            		conn.utils().removePort(conn, p);
+            		conn.endTx(Transaction.COMMIT);
             	}
             }
-		} catch (TitanException e) {
+		} catch (Exception e) {
              // TODO: handle exceptions
-			graph.stopTransaction(Conclusion.FAILURE);
+			conn.endTx(Transaction.ROLLBACK);
 			log.info("SwitchStorage:deletePort dpid:{} port:{} failed", dpid, port);
 		}	
 	}
@@ -206,74 +193,24 @@
 
 	}
 
-	@Override
-	public Iterable<ISwitchObject> getActiveSwitches() {
-		// TODO Add unit test
-		FramedGraph<TitanGraph> fg = new FramedGraph<TitanGraph>(graph);
-		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);
-			}
-		}
-
-		return activeSwitches;		
-	}
 
 	@Override
 	public void init(String conf) {
 
-        graph = TitanFactory.open(conf);
+		conn = GraphDBConnection.getInstance(conf);
         
-        // FIXME: Creation on Indexes should be done only once
-        Set<String> s = graph.getIndexedKeys(Vertex.class);
-        if (!s.contains("dpid")) {
-           graph.createKeyIndex("dpid", Vertex.class);
-           graph.stopTransaction(Conclusion.SUCCESS);
-        }
-        if (!s.contains("type")) {
-        	graph.createKeyIndex("type", Vertex.class);
-        	graph.stopTransaction(Conclusion.SUCCESS);
-        }
 	}
 
-	@Override
-	public Iterable<ISwitchObject> getAllSwitches() {
-		// TODO Auto-generated method stub
-		FramedGraph<TitanGraph> fg = new FramedGraph<TitanGraph>(graph);
-		Iterable<ISwitchObject> switches =  fg.getVertices("type","switch",ISwitchObject.class);
 
 
-		return switches;
-	}
-
-	@Override
-	public Iterable<ISwitchObject> getInactiveSwitches() {
-		// TODO Auto-generated method stub
-		FramedGraph<TitanGraph> fg = new FramedGraph<TitanGraph>(graph);
-		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);
-			}
-		}
-		return inactiveSwitches;
-	}
-
 	public void finalize() {
 		close();
 	}
 	
 	@Override
 	public void close() {
-		// TODO Auto-generated method stub
-		graph.shutdown();
-		
+		conn.close();		
 	}
 
 	
diff --git a/src/main/java/net/floodlightcontroller/core/internal/TopoSwitchServiceImpl.java b/src/main/java/net/floodlightcontroller/core/internal/TopoSwitchServiceImpl.java
index e8b1bf8..b3c31ec 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/TopoSwitchServiceImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/TopoSwitchServiceImpl.java
@@ -1,39 +1,49 @@
 package net.floodlightcontroller.core.internal;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.floodlightcontroller.core.INetMapTopologyService.ITopoSwitchService;
+import net.onrc.onos.util.GraphDBConnection;
+import net.onrc.onos.util.GraphDBConnection.Transaction;
 
 public class TopoSwitchServiceImpl implements ITopoSwitchService {
 	
-	ThreadLocal<SwitchStorageImpl> store = new ThreadLocal<SwitchStorageImpl>() {
-		@Override
-		protected SwitchStorageImpl initialValue() {
-			SwitchStorageImpl swStore = new SwitchStorageImpl();
-			//TODO: Get the file path from global properties
-			swStore.init("/tmp/cassandra.titan");
-			return swStore;
-		}
-	};
+	private GraphDBConnection conn;
+	protected static Logger log = LoggerFactory.getLogger(TopoSwitchServiceImpl.class);
+
+
+	public void finalize() {
+		close();
+	}
 	
-	SwitchStorageImpl swStore = store.get();
+	@Override
+	public void close() {
+		conn.endTx(Transaction.COMMIT);
+		conn.close();
+	}
 	
 	@Override
 	public Iterable<ISwitchObject> getActiveSwitches() {
 		// TODO Auto-generated method stub
-		return swStore.getActiveSwitches();
+		conn = GraphDBConnection.getInstance("");
+		return conn.utils().getActiveSwitches(conn);
 	}
 
 	@Override
 	public Iterable<ISwitchObject> getAllSwitches() {
-		// TODO Auto-generated method stub		
-		return swStore.getAllSwitches();
+		// TODO Auto-generated method stub
+		conn = GraphDBConnection.getInstance("");
+		return conn.utils().getAllSwitches(conn);
 	}
 
 	@Override
 	public Iterable<ISwitchObject> getInactiveSwitches() {
 		// TODO Auto-generated method stub
-		return swStore.getInactiveSwitches();
+		conn = GraphDBConnection.getInstance("");
+		return conn.utils().getInactiveSwitches(conn);
 	}
 
 	@Override
diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceStorageImpl.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceStorageImpl.java
index 64c12dc..e964b8e 100644
--- a/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceStorageImpl.java
+++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/DeviceStorageImpl.java
@@ -26,7 +26,7 @@
 		conn = GraphDBConnection.getInstance(conf);
 	}	
 
-	public void finalize() {
+	public void finalize() {		
 		close();
 	}
 	
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index d55979e..24a0c58 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -8,15 +8,20 @@
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
+import java.util.Collections;
+import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.INetMapStorage;
 import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
 import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
+import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
@@ -41,6 +46,7 @@
 import net.floodlightcontroller.util.MACAddress;
 import net.floodlightcontroller.util.OFMessageDamper;
 import net.floodlightcontroller.util.Port;
+import net.floodlightcontroller.util.SwitchPort;
 import net.onrc.onos.util.GraphDBConnection;
 import net.onrc.onos.util.GraphDBConnection.Transaction;
 
@@ -61,6 +67,7 @@
 
     protected IRestApiService restApi;
     protected IFloodlightProviderService floodlightProvider;
+    protected FloodlightModuleContext context;
 
     protected OFMessageDamper messageDamper;
 
@@ -75,14 +82,178 @@
     public static final short PRIORITY_DEFAULT = 100;
 
     private static long nextFlowEntryId = 1;
+    private static long measurementFlowId = 100000;
+    private static String measurementFlowIdStr = "0x186a0";	// 100000
+    private long modifiedMeasurementFlowTime = 0;
 
     /** The logger. */
     private static Logger log = LoggerFactory.getLogger(FlowManager.class);
 
     // The periodic task(s)
-    private final ScheduledExecutorService scheduler =
+    private final ScheduledExecutorService measureShortestPathScheduler =
 	Executors.newScheduledThreadPool(1);
-    final Runnable reader = new Runnable() {
+    private final ScheduledExecutorService measureMapReaderScheduler =
+	Executors.newScheduledThreadPool(1);
+    private final ScheduledExecutorService mapReaderScheduler =
+	Executors.newScheduledThreadPool(1);
+
+    private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
+    private ThreadPoolExecutor shortestPathExecutor =
+	new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
+
+    class ShortestPathTask implements Runnable {
+	private int hint;
+	private ITopoRouteService topoRouteService;
+	private ArrayList<DataPath> dpList;
+
+	public ShortestPathTask(int hint,
+				ITopoRouteService topoRouteService,
+				ArrayList<DataPath> dpList) {
+	    this.hint = hint;
+	    this.topoRouteService = topoRouteService;
+	    this.dpList = dpList;
+	}
+
+	@Override
+	public void run() {
+	    /*
+	    String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
+	    log.debug(logMsg);
+	    long startTime = System.nanoTime();
+	    */
+	    for (DataPath dp : this.dpList) {
+		topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
+	    }
+	    /*
+	    long estimatedTime = System.nanoTime() - startTime;
+	    double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
+	    logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
+	    log.debug(logMsg);
+	    */
+	}
+    }
+
+    final Runnable measureShortestPath = new Runnable() {
+	    public void run() {
+		log.debug("Recomputing Shortest Paths from the Network Map Flows...");
+		if (floodlightProvider == null) {
+		    log.debug("FloodlightProvider service not found!");
+		    return;
+		}
+
+		ITopoRouteService topoRouteService =
+		    context.getServiceImpl(ITopoRouteService.class);
+		if (topoRouteService == null) {
+		    log.debug("Topology Route Service not found");
+		    return;
+		}
+
+		int leftoverQueueSize = shortestPathExecutor.getQueue().size();
+		if (leftoverQueueSize > 0) {
+		    String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
+		    log.debug(logMsg);
+		    return;
+		}
+		log.debug("MEASUREMENT: Beginning Shortest Path Computation");
+
+		//
+		// Recompute the Shortest Paths for all Flows
+		//
+		int counter = 0;
+		int hint = 0;
+		ArrayList<DataPath> dpList = new ArrayList<DataPath>();
+		long startTime = System.nanoTime();
+
+		topoRouteService.prepareShortestPathTopo();
+
+		Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
+		for (IFlowPath flowPathObj : allFlowPaths) {
+		    FlowId flowId = new FlowId(flowPathObj.getFlowId());
+
+		    // log.debug("Found Path {}", flowId.toString());
+		    Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
+		    Port srcPort = new Port(flowPathObj.getSrcPort());
+		    Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
+		    Port dstPort = new Port(flowPathObj.getDstPort());
+		    SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
+		    SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
+
+		    /*
+		    DataPath dp = new DataPath();
+		    dp.setSrcPort(srcSwitchPort);
+		    dp.setDstPort(dstSwitchPort);
+		    dpList.add(dp);
+		    if ((dpList.size() % 10) == 0) {
+			shortestPathExecutor.execute(
+				new ShortestPathTask(hint, topoRouteService,
+						     dpList));
+			dpList = new ArrayList<DataPath>();
+			hint++;
+		    }
+		    */
+
+		    DataPath dataPath =
+			topoRouteService.getTopoShortestPath(srcSwitchPort,
+							     dstSwitchPort);
+		    counter++;
+		}
+		if (dpList.size() > 0) {
+		    shortestPathExecutor.execute(
+			new ShortestPathTask(hint, topoRouteService,
+					     dpList));
+		}
+
+		/*
+		// Wait for all tasks to finish
+		try {
+		    while (shortestPathExecutor.getQueue().size() > 0) {
+			Thread.sleep(100);
+		    }
+		} catch (InterruptedException ex) {
+		    log.debug("MEASUREMENT: Shortest Path Computation interrupted");
+		}
+		*/
+
+		conn.endTx(Transaction.COMMIT);
+		topoRouteService.dropShortestPathTopo();
+
+		long estimatedTime = System.nanoTime() - startTime;
+		double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
+		String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
+		log.debug(logMsg);
+	    }
+	};
+
+    final Runnable measureMapReader = new Runnable() {
+	    public void run() {
+		if (floodlightProvider == null) {
+		    log.debug("FloodlightProvider service not found!");
+		    return;
+		}
+
+		//
+		// Fetch all Flow Entries
+		//
+		int counter = 0;
+		long startTime = System.nanoTime();
+		Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
+		for (IFlowEntry flowEntryObj : allFlowEntries) {
+		    counter++;
+		    FlowEntryId flowEntryId =
+			new FlowEntryId(flowEntryObj.getFlowEntryId());
+		    String userState = flowEntryObj.getUserState();
+		    String switchState = flowEntryObj.getSwitchState();
+		}
+		conn.endTx(Transaction.COMMIT);
+
+		long estimatedTime = System.nanoTime() - startTime;
+		double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
+		String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
+		log.debug(logMsg);
+	    }
+	};
+
+    final Runnable mapReader = new Runnable() {
 	    public void run() {
 		// log.debug("Reading Flow Entries from the Network Map...");
 		if (floodlightProvider == null) {
@@ -101,13 +272,16 @@
 		for (IFlowEntry flowEntryObj : allFlowEntries) {
 		    FlowEntryId flowEntryId =
 			new FlowEntryId(flowEntryObj.getFlowEntryId());
-		    String userState = "User State: " + flowEntryObj.getUserState();
-		    String switchState = "Switch State: " + flowEntryObj.getSwitchState();
+		    String userState = flowEntryObj.getUserState();
+		    String switchState = flowEntryObj.getSwitchState();
 
+		    /**
 		    log.debug("Found Flow Entry {}: {}",
 			      flowEntryId.toString(),
-			      userState + " " + switchState);
-
+			      "User State: " + userState +
+			      " Switch State: " + switchState);
+		     */
+		    
 		    if (! switchState.equals("FE_SWITCH_NOT_UPDATED")) {
 			// Ignore the entry: nothing to do
 			continue;
@@ -125,8 +299,19 @@
 		//
 		// Process my Flow Entries
 		//
+		Boolean processed_measurement_flow = false;
 		for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
 		    IFlowEntry flowEntryObj = entry.getValue();
+		    // Code for measurement purpose
+		    {
+			IFlowPath flowObj =
+			    conn.utils().getFlowPathByFlowEntry(conn,
+								flowEntryObj);
+			if ((flowObj != null) &&
+			    flowObj.getFlowId().equals(measurementFlowIdStr)) {
+			    processed_measurement_flow = true;
+			}
+		    }
 
 		    //
 		    // TODO: Eliminate the re-fetching of flowEntryId,
@@ -160,6 +345,8 @@
 			flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
 		    } else {
 			// Unknown user state. Ignore the entry
+			log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
+				  flowEntryId.toString(), userState);
 			continue;
 		    }
 
@@ -265,10 +452,28 @@
 		    }
 		}
 		conn.endTx(Transaction.COMMIT);
+
+		if (processed_measurement_flow) {
+		    long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
+		    String logMsg = "MEASUREMENT: Pushed Flow delay: " +
+			(double)estimatedTime / 1000000000 + " sec";
+		    log.debug(logMsg);
+		}
 	    }
 	};
-    final ScheduledFuture<?> readerHandle =
-	scheduler.scheduleAtFixedRate(reader, 3, 3, TimeUnit.SECONDS);
+
+    /*
+    final ScheduledFuture<?> measureShortestPathHandle =
+	measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
+    */
+
+    /*
+    final ScheduledFuture<?> measureMapReaderHandle =
+	measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
+    */
+
+    final ScheduledFuture<?> mapReaderHandle =
+	mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
 
     @Override
     public void init(String conf) {
@@ -316,6 +521,7 @@
     @Override
     public void init(FloodlightModuleContext context)
 	throws FloodlightModuleException {
+	this.context = context;
 	floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
 	restApi = context.getServiceImpl(IRestApiService.class);
 	messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
@@ -329,6 +535,19 @@
     @Override
     public void startUp(FloodlightModuleContext context) {
 	restApi.addRestletRoutable(new FlowWebRoutable());
+
+	//
+	// Extract all flow entries and assign the next Flow Entry ID
+	// to be larger than the largest Flow Entry ID
+	//
+	Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
+	for (IFlowEntry flowEntryObj : allFlowEntries) {
+	    FlowEntryId flowEntryId =
+		new FlowEntryId(flowEntryObj.getFlowEntryId());
+	    if (flowEntryId.value() >= nextFlowEntryId)
+		nextFlowEntryId = flowEntryId.value() + 1;
+	}
+	conn.endTx(Transaction.COMMIT);
     }
 
     /**
@@ -343,6 +562,9 @@
      */
     @Override
     public boolean addFlow(FlowPath flowPath, FlowId flowId) {
+	if (flowPath.flowId().value() == measurementFlowId) {
+	    modifiedMeasurementFlowTime = System.nanoTime();
+	}
 
 	//
 	// Assign the FlowEntry IDs
@@ -506,6 +728,10 @@
      */
     @Override
     public boolean deleteFlow(FlowId flowId) {
+	if (flowId.value() == measurementFlowId) {
+	    modifiedMeasurementFlowTime = System.nanoTime();
+	}
+
 	IFlowPath flowObj = null;
 	//
 	// We just mark the entries for deletion,
@@ -733,6 +959,61 @@
     }
 
     /**
+     * Get summary of all installed flows by all installers in a given range
+     *
+     * @param flowId the data path endpoints of the flows to get.
+     * @param maxFlows: the maximum number of flows to be returned
+     * @return the Flow Paths if found, otherwise null.
+     */
+    @Override
+    public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
+		//
+		// TODO: The implementation below is not optimal:
+		// We fetch all flows, and then return only the subset that match
+		// the query conditions.
+		// We should use the appropriate Titan/Gremlin query to filter-out
+		// the flows as appropriate.
+		//
+	    ArrayList<FlowPath> allFlows = getAllFlows();
+	
+		if (allFlows == null) {
+		    log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
+		    return null;
+		}
+	
+		Collections.sort(allFlows);
+		
+		ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
+		for (FlowPath flow : allFlows) {
+			
+			// start from desired flowId
+			if (flow.flowId().value() < flowId.value()) {
+				continue;
+			}
+			
+			// Summarize by making null flow entry fields that are not relevant to report
+			for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
+				flowEntry.setFlowEntryActions(null);
+				flowEntry.setFlowEntryMatch(null);
+			}
+			
+		    flowPaths.add(flow);
+		    if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
+		    	break;
+		    }
+		}
+	
+		if (flowPaths.isEmpty()) {
+		    log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
+		    flowPaths = null;
+		} else {
+		    log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
+		}
+	
+		return flowPaths;
+    }
+    
+    /**
      * Get all installed flows by all installers.
      *
      * @return the Flow Paths if found, otherwise null.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
index 48477f1..41c0f57 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
@@ -68,6 +68,15 @@
     ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints);
 
     /**
+     * Get summary of all installed flows by all installers.
+     *
+     * @param flowId: starting flow Id of the range
+     * @param maxFlows: number of flows to return
+     * @return the Flow Paths if found, otherwise null.
+     */
+    ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows);
+    
+    /**
      * Get all installed flows by all installers.
      *
      * @return the Flow Paths if found, otherwise null.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java b/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
index a40a508..19f9e14 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
@@ -20,6 +20,7 @@
         router.attach("/getall-by-installer-id/{installer-id}/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", GetAllFlowsByInstallerIdResource.class);
         router.attach("/getall-by-endpoints/{src-dpid}/{src-port}/{dst-dpid}/{dst-port}/json", GetAllFlowsByEndpointsResource.class);
         router.attach("/getall/json", GetAllFlowsResource.class);
+        router.attach("/getsummary/{flow-id}/{max-flows}/json", GetSummaryFlowsResource.class);
         return router;
     }
 
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java
new file mode 100644
index 0000000..7a928c9
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/GetSummaryFlowsResource.java
@@ -0,0 +1,44 @@
+package net.floodlightcontroller.flowcache.web;
+
+import java.util.ArrayList;
+
+import net.floodlightcontroller.flowcache.IFlowService;
+import net.floodlightcontroller.util.FlowPath;
+import net.floodlightcontroller.util.FlowId;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GetSummaryFlowsResource extends ServerResource {
+    protected static Logger log = LoggerFactory.getLogger(GetSummaryFlowsResource.class);
+
+    @Get("json")
+    public ArrayList<FlowPath> retrieve() {
+    	ArrayList<FlowPath> result = null;
+    	
+    	FlowId flowId;
+    	int maxFlows = 0;
+    	
+    	IFlowService flowService = (IFlowService)getContext().getAttributes().get(IFlowService.class.getCanonicalName());
+
+        if (flowService == null) {
+        	log.debug("ONOS Flow Service not found");
+        	return result;
+        }
+
+        // Extract the arguments
+    	String flowIdStr = (String) getRequestAttributes().get("flow-id");
+    	String maxFlowStr = (String) getRequestAttributes().get("max-flows");
+    	log.debug("Get Summary Flows starting flow-id: " + flowIdStr + " max-flows: " + maxFlowStr);
+    	
+    	flowId = new FlowId(flowIdStr);
+    	maxFlows = Integer.parseInt(maxFlowStr);
+    	if (maxFlows < 0) maxFlows = 0;
+
+        result = flowService.getAllFlowsSummary(flowId, maxFlows);
+
+        return result;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index b08fd8c..fa75769 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -42,31 +42,30 @@
 import net.floodlightcontroller.core.FloodlightContext;
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IFloodlightProviderService.Role;
-import net.floodlightcontroller.core.INetMapStorage.DM_OPERATION;
 import net.floodlightcontroller.core.IHAListener;
 import net.floodlightcontroller.core.IInfoProvider;
+import net.floodlightcontroller.core.INetMapStorage.DM_OPERATION;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.internal.OFSwitchImpl;
 import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.annotations.LogMessageCategory;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
 import net.floodlightcontroller.core.annotations.LogMessageDocs;
-//import net.floodlightcontroller.core.internal.SwitchStorageImpl;
+import net.floodlightcontroller.core.internal.OFSwitchImpl;
 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.core.util.SingletonTask;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery;
+import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LinkType;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.SwitchType;
-import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.UpdateOperation;
-import net.floodlightcontroller.linkdiscovery.web.LinkDiscoveryWebRoutable;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryListener;
 import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.floodlightcontroller.linkdiscovery.LinkInfo;
+import net.floodlightcontroller.linkdiscovery.web.LinkDiscoveryWebRoutable;
 import net.floodlightcontroller.packet.BSN;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
@@ -75,8 +74,8 @@
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.routing.Link;
 import net.floodlightcontroller.storage.IResultSet;
-import net.floodlightcontroller.storage.IStorageSourceService;
 import net.floodlightcontroller.storage.IStorageSourceListener;
+import net.floodlightcontroller.storage.IStorageSourceService;
 import net.floodlightcontroller.storage.OperatorPredicate;
 import net.floodlightcontroller.storage.StorageException;
 import net.floodlightcontroller.threadpool.IThreadPoolService;
@@ -84,6 +83,10 @@
 import net.floodlightcontroller.util.EventHistory;
 import net.floodlightcontroller.util.EventHistory.EvAction;
 
+import net.onrc.onos.registry.controller.IControllerRegistryService;
+import net.onrc.onos.registry.controller.IControllerRegistryService.ControlChangeCallback;
+import net.onrc.onos.registry.controller.RegistryException;
+
 import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFPacketIn;
 import org.openflow.protocol.OFPacketOut;
@@ -146,7 +149,7 @@
     protected IStorageSourceService storageSource;
     protected IThreadPoolService threadPool;
     protected IRestApiService restApi;
-
+    protected IControllerRegistryService registryService;
 
     // LLDP and BDDP fields
     private static final byte[] LLDP_STANDARD_DST_MAC_STRING = 
@@ -1172,6 +1175,14 @@
      * @param links The List of @LinkTuple to delete.
      */
     protected void deleteLinks(List<Link> links, String reason) {
+    	deleteLinks(links, reason, Boolean.TRUE);
+    }
+    
+    /**
+     * Removes links from memory and storage.
+     * @param links The List of @LinkTuple to delete.
+     */
+    protected void deleteLinks(List<Link> links, String reason, Boolean hasControl) {
         NodePortTuple srcNpt, dstNpt;
 
         lock.writeLock().lock();
@@ -1219,7 +1230,9 @@
                 removeLinkFromStorage(lt);
 
                 // remote link from network map
-                linkStore.update(lt, DM_OPERATION.DELETE);
+                if (hasControl) {
+                	linkStore.update(lt, DM_OPERATION.DELETE);
+                }
                 
                 // TODO  Whenever link is removed, it has to checked if
                 // the switchports must be added to quarantine.
@@ -1244,7 +1257,10 @@
 
         IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
         if (iofSwitch == null) return Command.CONTINUE;
-
+        
+        // If we do not control this switch, then we should not process its port status messages
+        if (!registryService.hasControl(iofSwitch.getId())) return Command.CONTINUE;
+        
         if (log.isTraceEnabled()) {
             log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
                     "config is {} state is {}",
@@ -1418,7 +1434,11 @@
                 }
                 // add all tuples with an endpoint on this switch to erase list
                 eraseList.addAll(switchLinks.get(sw));
-                deleteLinks(eraseList, "Switch Removed");
+                
+                // We can get called to delete links when we lose mastership. To avoid clearing the network map in that case,
+                // figure out if we have control of the switch
+                boolean hasControl = registryService.hasControl(sw);
+                deleteLinks(eraseList, "Switch Removed", hasControl);
 
                 // Send a switch removed update
                 LDUpdate update = new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED);
@@ -1848,6 +1868,7 @@
         l.add(IStorageSourceService.class);
         l.add(IThreadPoolService.class);
         l.add(IRestApiService.class);
+        l.add(IControllerRegistryService.class);
         return l;
     }
 
@@ -1858,6 +1879,7 @@
         storageSource = context.getServiceImpl(IStorageSourceService.class);
         threadPool = context.getServiceImpl(IThreadPoolService.class);
         restApi = context.getServiceImpl(IRestApiService.class);
+        registryService = context.getServiceImpl(IControllerRegistryService.class);
 
         // Set the autoportfast feature to false.
         this.autoPortFastFeature = false;
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
index 503f2f3..83abc8e 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
@@ -47,7 +47,6 @@
 	public void update(Link link, LinkInfo linkinfo, DM_OPERATION op) {
 		switch (op) {
 		case UPDATE:
-			break;
 		case CREATE:
 		case INSERT:
 			addOrUpdateLink(link, linkinfo, op);
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/TopoLinkServiceImpl.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/TopoLinkServiceImpl.java
index c452fcd..c493887 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/TopoLinkServiceImpl.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/TopoLinkServiceImpl.java
@@ -1,33 +1,76 @@
 package net.floodlightcontroller.linkdiscovery.internal;
 
+import java.util.ArrayList;
 import java.util.List;
 
+import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.floodlightcontroller.core.INetMapTopologyService.ITopoLinkService;
+import net.floodlightcontroller.linkdiscovery.internal.LinkStorageImpl.ExtractLink;
 import net.floodlightcontroller.routing.Link;
+import net.onrc.onos.util.GraphDBConnection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
 
 public class TopoLinkServiceImpl implements ITopoLinkService {
 	
-	ThreadLocal<LinkStorageImpl> store = new ThreadLocal<LinkStorageImpl>() {
-		@Override
-		protected LinkStorageImpl initialValue() {
-			LinkStorageImpl inStore = new LinkStorageImpl();
-			//TODO: Get the file path from global properties
-			inStore.init("/tmp/cassandra.titan");
-			return inStore;
-		}
-	};
+	public GraphDBConnection conn;
+	protected static Logger log = LoggerFactory.getLogger(TopoLinkServiceImpl.class);
+
+
+	public void finalize() {
+		close();
+	}
+	
+	@Override
+	public void close() {
+		conn.close();
+	}
  
-	LinkStorageImpl linkStore = store.get();
 	@Override
 	public List<Link> getActiveLinks() {
 		// TODO Auto-generated method stub
-		List<Link> retval = linkStore.getActiveLinks();
-		return retval;
+		conn = GraphDBConnection.getInstance("");
+		Iterable<ISwitchObject> switches = conn.utils().getActiveSwitches(conn);
+		List<Link> links = new ArrayList<Link>(); 
+		for (ISwitchObject sw : switches) {
+			GremlinPipeline<Vertex, Link> pipe = new GremlinPipeline<Vertex, Link>();
+			ExtractLink extractor = new ExtractLink();
+
+			pipe.start(sw.asVertex());
+			pipe.enablePath(true);
+			pipe.out("on").out("link").in("on").path().step(extractor);
+					
+			while (pipe.hasNext() ) {
+				Link l = pipe.next();
+				links.add(l);
+			}
+						
+		}
+		return links;
 	}
 
 	@Override
 	public List<Link> getLinksOnSwitch(String dpid) {
 		// TODO Auto-generated method stub
-		return linkStore.getLinks(dpid);
+		List<Link> links = new ArrayList<Link>(); 
+		ISwitchObject sw = conn.utils().searchSwitch(conn, dpid);
+		GremlinPipeline<Vertex, Link> pipe = new GremlinPipeline<Vertex, Link>();
+		ExtractLink extractor = new ExtractLink();
+
+		pipe.start(sw.asVertex());
+		pipe.enablePath(true);
+		pipe.out("on").out("link").in("on").path().step(extractor);
+			
+		while (pipe.hasNext() ) {
+			Link l = pipe.next();
+			links.add(l);
+		}
+		return links;
+
 	}
+	
 }
diff --git a/src/main/java/net/floodlightcontroller/onoslistener/OnosPublisher.java b/src/main/java/net/floodlightcontroller/onoslistener/OnosPublisher.java
index c6fe108..36cde95 100644
--- a/src/main/java/net/floodlightcontroller/onoslistener/OnosPublisher.java
+++ b/src/main/java/net/floodlightcontroller/onoslistener/OnosPublisher.java
@@ -48,7 +48,7 @@
 	protected static final String CleanupEnabled = "EnableCleanup";
 	protected IThreadPoolService threadPool;
 	
-	protected final int CLEANUP_TASK_INTERVAL = 999; // 999 ms
+	protected final int CLEANUP_TASK_INTERVAL = 10; // 10 sec
 	protected SingletonTask cleanupTask;
 	
 	/**
@@ -65,7 +65,7 @@
                 log.error("Error in cleanup thread", e);
             } finally {
                     cleanupTask.reschedule(CLEANUP_TASK_INTERVAL,
-                                              TimeUnit.MILLISECONDS);
+                                              TimeUnit.SECONDS);
             }
         }
 
@@ -74,30 +74,29 @@
 			// TODO Auto-generated method stub
 			
 			if (hasControl) {
-				log.debug("got control to set inactive sw {}", dpid);
+				log.debug("got control to set inactive sw {}", HexString.toHexString(dpid));
 				swStore.update(HexString.toHexString(dpid),SwitchState.INACTIVE, DM_OPERATION.UPDATE);
 			    registryService.releaseControl(dpid);	
 			}						
 		}
     }
-    
 
-    
     protected void switchCleanup() {
-    	
     	TopoSwitchServiceImpl impl = new TopoSwitchServiceImpl();
     	Iterable<ISwitchObject> switches = impl.getActiveSwitches();
+    	
+    	log.debug("Checking for inactive switches");
     	// For each switch check if a controller exists in controller registry
     	for (ISwitchObject sw: switches) {
-			log.debug("checking if switch is inactive: {}", sw.getDPID());
+			//log.debug("checking if switch is inactive: {}", sw.getDPID());
 			try {
 				long dpid = HexString.toLong(sw.getDPID());
 				String controller = registryService.getControllerForSwitch(dpid);
 				if (controller == null) {
-					log.debug("request Control to set inactive sw {}", dpid);
+					log.debug("request Control to set inactive sw {}", HexString.toHexString(dpid));
 					registryService.requestControl(dpid, new SwitchCleanup());
 				} else {
-					log.debug("sw {} is controlled by controller: {}",dpid,controller);
+					log.debug("sw {} is controlled by controller: {}",HexString.toHexString(dpid),controller);
 				}
 			} catch (NumberFormatException e) {
 				// TODO Auto-generated catch block
@@ -223,10 +222,10 @@
 
 		deviceService.addListener(this);
 	       // Setup the Cleanup task. 
-		if (cleanupNeeded != null &&cleanupNeeded.equals("True")) {
+		if (cleanupNeeded == null || !cleanupNeeded.equals("False")) {
 				ScheduledExecutorService ses = threadPool.getScheduledExecutor();
 				cleanupTask = new SingletonTask(ses, new SwitchCleanup());
-				cleanupTask.reschedule(CLEANUP_TASK_INTERVAL, TimeUnit.MILLISECONDS);
+				cleanupTask.reschedule(CLEANUP_TASK_INTERVAL, TimeUnit.SECONDS);
 		}
 	}
 
diff --git a/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java b/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
index 94e4769..fd7c364 100644
--- a/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
+++ b/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
@@ -2,42 +2,113 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
+import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
 
-import net.floodlightcontroller.core.internal.SwitchStorageImpl;
+import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
 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.core.INetMapTopologyService.ITopoRouteService;
 import net.floodlightcontroller.util.DataPath;
 import net.floodlightcontroller.util.Dpid;
 import net.floodlightcontroller.util.FlowEntry;
 import net.floodlightcontroller.util.Port;
 import net.floodlightcontroller.util.SwitchPort;
+import net.onrc.onos.util.GraphDBConnection;
 
 import org.openflow.util.HexString;
-
-import com.thinkaurelius.titan.core.TitanGraph;
-import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
-import com.tinkerpop.blueprints.Vertex;
-
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
+
+
+/**
+ * A class for storing Node and Link information for fast computation
+ * of shortest paths.
+ */
+class Node {
+    class Link {
+	public Node me;			// The node this link originates from
+	public Node neighbor;		// The neighbor node on the other side
+	public short myPort;		// Local port number for the link
+	public short neighborPort;	// Neighbor port number for the link
+
+	/**
+	 * Link constructor.
+	 *
+	 * @param me the node this link originates from.
+	 * @param the neighbor node on the other side of the link.
+	 * @param myPort local port number for the link.
+	 * @param neighborPort neighrobr port number for the link.
+	 */
+	public Link(Node me, Node neighbor, short myPort, short neighborPort) {
+	    this.me = me;
+	    this.neighbor = neighbor;
+	    this.myPort = myPort;
+	    this.neighborPort = neighborPort;
+	}
+    };
+
+    public long nodeId;			// The node ID
+    public LinkedList<Link> links;	// The links originating from this node
+
+    /**
+     * Node constructor.
+     *
+     * @param nodeId the node ID.
+     */
+    public Node(long nodeId) {
+	this.nodeId = nodeId;
+	links = new LinkedList<Link>();
+    }
+
+    /**
+     * Add a neighbor.
+     *
+     * A new link to the neighbor will be created. 
+     *
+     * @param neighbor the neighbor to add.
+     * @param myPort the local port number for the link to the neighbor.
+     * @param neighborPort the neighbor port number for the link.
+     */
+    public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
+	Link link = new Link(this, neighbor, myPort, neighborPort);
+	links.add(link);
+    }
+};
+
+
 public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
 
     /** The logger. */
     private static Logger log =
 	LoggerFactory.getLogger(TopoRouteService.class);
+    
+    GraphDBConnection conn;
+
+    //
+    // Topology state for storing (on demand) Switch and Ports info for
+    // fast access during the shortest path computation.
+    // It is explicitly populated by method @ref prepareShortestPathTopo().
+    // See the documentation for that method for details.
+    //
+    HashMap<Long, Node> shortestPathTopo;
 
     @Override
     public Collection<Class<? extends IFloodlightService>> getModuleServices() {
@@ -72,6 +143,7 @@
     public void init(FloodlightModuleContext context)
 	throws FloodlightModuleException {
 	// TODO: Add the appropriate initialization
+    	conn = GraphDBConnection.getInstance("");
     }
 
     @Override
@@ -79,18 +151,256 @@
 	// TODO: Add the approprate setup
     }
 
-    ThreadLocal<SwitchStorageImpl> store = new ThreadLocal<SwitchStorageImpl>() {
-	@Override
-	protected SwitchStorageImpl initialValue() {
-	    SwitchStorageImpl swStore = new SwitchStorageImpl();
-	    // NOTE: This is the file path from global properties
-	    swStore.init("/tmp/cassandra.titan");
-	    return swStore;
+
+    static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
+	String dpid;
+	public ShortestPathLoopFunction(String dpid) {
+	    super();
+	    this.dpid = dpid;
 	}
-    };
+	public Boolean compute(LoopBundle<Vertex> bundle) {
+	    Boolean output = false;
+	    if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
+		output = true;
+	    }
+	    return output;
+	}
+    }
 
-    SwitchStorageImpl swStore = store.get();
+    /**
+     * Fetch the Switch and Ports info from the Titan Graph
+     * and store it locally for fast access during the shortest path
+     * computation.
+     *
+     * After fetching the state, method @ref getTopoShortestPath()
+     * can be used for fast shortest path computation.
+     *
+     * Note: There is certain cost to fetch the state, hence it should
+     * be used only when there is a large number of shortest path
+     * computations that need to be done on the same topology.
+     * Typically, a single call to @ref prepareShortestPathTopo()
+     * should be followed by a large number of calls to
+     * method @ref getTopoShortestPath().
+     * After the last @ref getTopoShortestPath() call,
+     * method @ref dropShortestPathTopo() should be used to release
+     * the internal state that is not needed anymore:
+     *
+     *       prepareShortestPathTopo();
+     *       for (int i = 0; i < 10000; i++) {
+     *           dataPath = getTopoShortestPath(...);
+     *           ...
+     *        }
+     *        dropShortestPathTopo();
+     */
+    
+    public void prepareShortestPathTopo() {
+	TitanGraph titanGraph = TitanFactory.open("/tmp/cassandra.titan");
+	TitanTransaction titanTransaction = titanGraph.startTransaction();
+	shortestPathTopo = new HashMap<Long, Node>();
 
+	//
+	// Fetch the relevant info from the Switch and Port vertices
+	// from the Titan Graph.
+	//
+	Iterable<Vertex> nodes = titanTransaction.getVertices("type", "switch");
+	for (Vertex nodeVertex : nodes) {
+	
+	    //
+	    // The Switch info
+	    //
+	    String nodeDpid = nodeVertex.getProperty("dpid").toString();
+	    long nodeId = HexString.toLong(nodeDpid);
+	    Node me = shortestPathTopo.get(nodeId);
+	    if (me == null) {
+		me = new Node(nodeId);
+		shortestPathTopo.put(nodeId, me);
+	    }
+
+	    //
+	    // The local Port info
+	    //
+	    for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
+		short myPort = 0;
+		Object obj = myPortVertex.getProperty("number");
+		if (obj instanceof Short) {
+		    myPort = (Short)obj;
+		} else if (obj instanceof Integer) {
+		    Integer int_nodeId = (Integer)obj;
+		    myPort = int_nodeId.shortValue();
+		}
+
+		//
+		// The neighbor Port info
+		//
+		for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
+		    short neighborPort = 0;
+		    obj = neighborPortVertex.getProperty("number");
+		    if (obj instanceof Short) {
+			neighborPort = (Short)obj;
+		    } else if (obj instanceof Integer) {
+			Integer int_nodeId = (Integer)obj;
+			neighborPort = int_nodeId.shortValue();
+		    }
+		    //
+		    // The neighbor Switch info
+		    //
+		    for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
+			String neighborDpid = neighborVertex.getProperty("dpid").toString();
+			long neighborId = HexString.toLong(neighborDpid);
+			Node neighbor = shortestPathTopo.get(neighborId);
+			if (neighbor == null) {
+			    neighbor = new Node(neighborId);
+			    shortestPathTopo.put(neighborId, neighbor);
+			}
+			me.addNeighbor(neighbor, myPort, neighborPort);
+		    }
+		}
+	    }
+	}
+
+	titanTransaction.stopTransaction(Conclusion.SUCCESS);
+    }
+
+    /**
+     * Release the state that was populated by
+     * method @ref prepareShortestPathTopo().
+     *
+     * See the documentation for method @ref prepareShortestPathTopo()
+     * for additional information and usage.
+     */
+  
+    public void dropShortestPathTopo() {
+	shortestPathTopo = null;
+    }
+
+    /**
+     * Get the shortest path from a source to a destination by
+     * using the pre-populated local topology state prepared
+     * by method @ref prepareShortestPathTopo().
+     *
+     * See the documentation for method @ref prepareShortestPathTopo()
+     * for additional information and usage.
+     *
+     * @param src the source in the shortest path computation.
+     * @param dest the destination in the shortest path computation.
+     * @return the data path with the computed shortest path if
+     * found, otherwise null.
+     */
+  
+    public DataPath getTopoShortestPath(SwitchPort src, SwitchPort dest) {
+	DataPath result_data_path = new DataPath();
+
+	// Initialize the source and destination in the data path to return
+	result_data_path.setSrcPort(src);
+	result_data_path.setDstPort(dest);
+
+	String dpid_src = src.dpid().toString();
+	String dpid_dest = dest.dpid().toString();
+
+	// Get the source vertex
+	Node v_src = shortestPathTopo.get(src.dpid().value());
+	if (v_src == null) {
+	    return null;		// Source vertex not found
+	}
+
+	// Get the destination vertex
+	Node v_dest = shortestPathTopo.get(dest.dpid().value());
+	if (v_dest == null) {
+	    return null;		// Destination vertex not found
+	}
+
+	//
+	// 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.
+	//
+	if (dpid_src.equals(dpid_dest)) {
+	    FlowEntry flowEntry = new FlowEntry();
+	    flowEntry.setDpid(src.dpid());
+	    flowEntry.setInPort(src.port());
+	    flowEntry.setOutPort(dest.port());
+	    result_data_path.flowEntries().add(flowEntry);
+	    return result_data_path;
+	}
+
+	//
+	// Implement the Shortest Path computation by using Breath First Search
+	//
+	Set<Node> visitedSet = new HashSet<Node>();
+	Queue<Node> processingList = new LinkedList<Node>();
+	Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
+	processingList.add(v_src);
+	visitedSet.add(v_src);
+	Boolean path_found = false;
+	while (! processingList.isEmpty()) {
+	    Node nextVertex = processingList.poll();
+	    if (v_dest == nextVertex) {
+		path_found = true;
+		break;
+	    }
+	    for (Node.Link link : nextVertex.links) {
+		Node child = link.neighbor;
+		if (! visitedSet.contains(child)) {
+		    previousVertexMap.put(child, link);
+		    visitedSet.add(child);
+		    processingList.add(child);
+		}
+	    }
+	}
+	if (! path_found)
+	    return null;		// No path found
+
+	// Collect the path as a list of links
+	List<Node.Link> resultPath = new LinkedList<Node.Link>();
+	Node previousVertex = v_dest;
+	while (! v_src.equals(previousVertex)) {
+	    Node.Link currentLink = previousVertexMap.get(previousVertex);
+	    resultPath.add(currentLink);
+	    previousVertex = currentLink.me;
+	}
+	Collections.reverse(resultPath);
+
+	//
+	// Loop through the result and prepare the return result
+	// as a list of Flow Entries.
+	//
+	Port inPort = new Port(src.port().value());
+	Port outPort;
+	for (Node.Link link: resultPath) {
+	    // Setup the outgoing port, and add the Flow Entry
+	    outPort = new Port(link.neighborPort);
+
+	    FlowEntry flowEntry = new FlowEntry();
+	    flowEntry.setDpid(new Dpid(link.me.nodeId));
+	    flowEntry.setInPort(inPort);
+	    flowEntry.setOutPort(outPort);
+	    result_data_path.flowEntries().add(flowEntry);
+
+	    // Setup the next incoming port
+	    inPort = new Port(link.neighborPort);
+	}
+	if (resultPath.size() > 0) {
+	    // Add the last Flow Entry
+	    FlowEntry flowEntry = new FlowEntry();
+	    flowEntry.setDpid(new Dpid(dest.dpid().value()));
+	    flowEntry.setInPort(inPort);
+	    flowEntry.setOutPort(dest.port());
+	    result_data_path.flowEntries().add(flowEntry);
+	}
+
+	if (result_data_path.flowEntries().size() > 0)
+	    return result_data_path;
+
+	return null;
+    }
+
+    /**
+     * Get the shortest path from a source to a destination.
+     *
+     * @param src the source in the shortest path computation.
+     * @param dest the destination in the shortest path computation.
+     * @return the data path with the computed shortest path if
+     * found, otherwise null.
+     */
     @Override
     public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
 	DataPath result_data_path = new DataPath();
@@ -99,43 +409,16 @@
 	result_data_path.setSrcPort(src);
 	result_data_path.setDstPort(dest);
 
-	TitanGraph titanGraph = swStore.graph;
+	TitanGraph titanGraph = TitanFactory.open("/tmp/cassandra.titan");
+	TitanTransaction titanTransaction = titanGraph.startTransaction();
 
 	String dpid_src = src.dpid().toString();
 	String dpid_dest = dest.dpid().toString();
 
-	//
-	// Implement the Shortest Path between two vertices by using
-	// the following Gremlin CLI code:
-	//   v_src.as("x").out("on").out("link").in("on").dedup().loop("x"){it.object.dpid != v_dest.dpid}.path(){it.dpid}{it.number}{it.number}
-	// The equivalent code used here is:
-	//   results = []; v_src.as("x").out("on").out("link").in("on").dedup().loop("x"){it.object.dpid != v_dest.dpid}.path().fill(results)
-	//
-
-	String gremlin = "v_src.as(\"x\").out(\"on\").out(\"link\").in(\"on\").dedup().loop(\"x\"){it.object.dpid != v_dest.dpid}.path().fill(results)";
-
-	// Get the source vertex
-	Iterator<Vertex> iter = titanGraph.getVertices("dpid", dpid_src).iterator();
-	if (! iter.hasNext()) {
-	    // titanGraph.stopTransaction(Conclusion.SUCCESS);
-	    return null;		// Source vertex not found
-	}
-	Vertex v_src = iter.next();
-
-	// Get the destination vertex
-	iter = titanGraph.getVertices("dpid", dpid_dest).iterator();
-	if (! iter.hasNext()) {
-	    // titanGraph.stopTransaction(Conclusion.SUCCESS);
-	    return null;		// Destination vertex not found
-	}
-	Vertex v_dest = iter.next();
 
 	//
 	// 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.
-	// NOTE: The return value will change in the future to return
-	// a single hop/entry instead of two. Currently, we need
-	// both entries to capture the source and destination ports.
 	//
 	if (dpid_src.equals(dpid_dest)) {
 	    FlowEntry flowEntry = new FlowEntry();
@@ -143,106 +426,151 @@
 	    flowEntry.setInPort(src.port());
 	    flowEntry.setOutPort(dest.port());
 	    result_data_path.flowEntries().add(flowEntry);
-	    // titanGraph.stopTransaction(Conclusion.SUCCESS);
+	    titanTransaction.stopTransaction(Conclusion.SUCCESS);
+	    // titanTransaction.shutdown();
 	    return result_data_path;
 	}
 
-	//
-	// Implement the Gremlin script and run it
-	//
-	ScriptEngine engine = new GremlinGroovyScriptEngine();
 
-	ArrayList<ArrayList<Vertex>> results = new ArrayList<ArrayList<Vertex>>();
-	engine.getBindings(ScriptContext.ENGINE_SCOPE).put("g", titanGraph);
-	engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_src", v_src);
-	engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_dest", v_dest);
-	engine.getBindings(ScriptContext.ENGINE_SCOPE).put("results", results);
+	// Get the source vertex
 
-	try {
-	    engine.eval(gremlin);
-	} catch (ScriptException e) {
-	    System.err.println("Caught ScriptException running Gremlin script: " + e.getMessage());
-	    // titanGraph.stopTransaction(Conclusion.SUCCESS);
-	    return null;
+	ISwitchObject srcSwitch = conn.utils().searchSwitch(conn, dpid_src);
+	ISwitchObject destSwitch = conn.utils().searchSwitch(conn, dpid_dest);
+
+	if (srcSwitch == null || destSwitch == null) {
+		return null;
 	}
 
+
+	Vertex v_src = srcSwitch.asVertex();	
+	Vertex v_dest = destSwitch.asVertex();
+
 	//
-	// Loop through the result and collect the list
-	// of <dpid, port> tuples.
+	// Implement the Shortest Path computation by using Breath First Search
+	//
+	Set<Vertex> visitedSet = new HashSet<Vertex>();
+	Queue<Vertex> processingList = new LinkedList<Vertex>();
+	Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
+
+	processingList.add(v_src);
+	visitedSet.add(v_src);
+	Boolean path_found = false;
+	while (! processingList.isEmpty()) {
+	    Vertex nextVertex = processingList.poll();
+	    if (v_dest.equals(nextVertex)) {
+		path_found = true;
+		break;
+	    }
+	    for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
+		for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
+		    for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
+			if (! visitedSet.contains(child)) {
+			    previousVertexMap.put(parentPort, nextVertex);
+			    previousVertexMap.put(childPort, parentPort);
+			    previousVertexMap.put(child, childPort);
+			    visitedSet.add(child);
+			    processingList.add(child);
+			}
+		    }
+		}
+	    }
+	}
+	if (! path_found)
+	    return null;		// No path found
+
+	List<Vertex> resultPath = new LinkedList<Vertex>();
+	Vertex previousVertex = v_dest;
+	resultPath.add(v_dest);
+	while (! v_src.equals(previousVertex)) {
+	    Vertex currentVertex = previousVertexMap.get(previousVertex);
+	    resultPath.add(currentVertex);
+	    previousVertex = currentVertex;
+	}
+	Collections.reverse(resultPath);
+
+
+
+	//
+	// Loop through the result and prepare the return result
+	// as a list of Flow Entries.
 	//
 	long nodeId = 0;
 	short portId = 0;
 	Port inPort = new Port(src.port().value());
 	Port outPort = new Port();
-	for (ArrayList<Vertex> lv : results) {
-	    int idx = 0;
-	    for (Vertex v: lv) {
-		String type = v.getProperty("type").toString();
-		System.out.println("type: " + type);
-		if (type.equals("port")) {
-		    String number = v.getProperty("number").toString();
-		    System.out.println("number: " + number);
+	int idx = 0;
+	for (Vertex v: resultPath) {
+	    String type = v.getProperty("type").toString();
+	    // System.out.println("type: " + type);
+	    if (type.equals("port")) {
+		String number = v.getProperty("number").toString();
+		// System.out.println("number: " + number);
 
-		    Object obj = v.getProperty("number");
-		    // String class_str = obj.getClass().toString();
-		    if (obj instanceof Short) {
-			portId = (Short)obj;
-		    } else if (obj instanceof Integer) {
-			Integer int_nodeId = (Integer)obj;
-			portId = int_nodeId.shortValue();
-			// int int_nodeId = (Integer)obj;
-			// portId = (short)int_nodeId.;
-		    }
-		} else if (type.equals("switch")) {
-		    String dpid = v.getProperty("dpid").toString();
-		    nodeId = HexString.toLong(dpid);
+		Object obj = v.getProperty("number");
+		// String class_str = obj.getClass().toString();
+		if (obj instanceof Short) {
+		    portId = (Short)obj;
+		} else if (obj instanceof Integer) {
+		    Integer int_nodeId = (Integer)obj;
+		    portId = int_nodeId.shortValue();
+		    // int int_nodeId = (Integer)obj;
+		    // portId = (short)int_nodeId.;
+		}
+	    } else if (type.equals("switch")) {
+		String dpid = v.getProperty("dpid").toString();
+		nodeId = HexString.toLong(dpid);
 
-		    System.out.println("dpid: " + dpid);
-		}
-		idx++;
-		if (idx == 1) {
-		    continue;
-		}
-		int mod = idx % 3;
-		if (mod == 0) {
-		    // Setup the incoming port
-		    inPort = new Port(portId);
-		    continue;
-		}
-		if (mod == 2) {
-		    // Setup the outgoing port, and add the Flow Entry
-		    outPort = new Port(portId);
-
-		    FlowEntry flowEntry = new FlowEntry();
-		    flowEntry.setDpid(new Dpid(nodeId));
-		    flowEntry.setInPort(inPort);
-		    flowEntry.setOutPort(outPort);
-		    result_data_path.flowEntries().add(flowEntry);
-		    continue;
-		}
+		// System.out.println("dpid: " + dpid);
 	    }
+	    idx++;
+	    if (idx == 1) {
+		continue;
+	    }
+	    int mod = idx % 3;
+	    if (mod == 0) {
+		// Setup the incoming port
+		inPort = new Port(portId);
+		continue;
+	    }
+	    if (mod == 2) {
+		// Setup the outgoing port, and add the Flow Entry
+		outPort = new Port(portId);
 
-	    if (idx > 0) {
-		// Add the last Flow Entry
 		FlowEntry flowEntry = new FlowEntry();
 		flowEntry.setDpid(new Dpid(nodeId));
 		flowEntry.setInPort(inPort);
-		flowEntry.setOutPort(dest.port());
+		flowEntry.setOutPort(outPort);
 		result_data_path.flowEntries().add(flowEntry);
+		continue;
 	    }
 	}
-	// titanGraph.stopTransaction(Conclusion.SUCCESS);
+	if (idx > 0) {
+	    // Add the last Flow Entry
+	    FlowEntry flowEntry = new FlowEntry();
+	    flowEntry.setDpid(new Dpid(nodeId));
+	    flowEntry.setInPort(inPort);
+	    flowEntry.setOutPort(dest.port());
+	    result_data_path.flowEntries().add(flowEntry);
+	}
+
+	titanTransaction.stopTransaction(Conclusion.SUCCESS);
+	// titanTransaction.shutdown();
 	if (result_data_path.flowEntries().size() > 0)
 	    return result_data_path;
 
 	return null;
     }
 
+    /**
+     * Test whether a route exists from a source to a destination.
+     *
+     * @param src the source node for the test.
+     * @param dest the destination node for the test.
+     * @return true if a route exists, otherwise false.
+     */
     @Override
     public Boolean routeExists(SwitchPort src, SwitchPort dest) {
 	DataPath dataPath = getShortestPath(src, dest);
-	if (dataPath != null)
-	    return true;
-	return false;
+	return (dataPath != null);
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/util/FlowEntry.java b/src/main/java/net/floodlightcontroller/util/FlowEntry.java
index 64c32b4..717be4e 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowEntry.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowEntry.java
@@ -26,8 +26,12 @@
     private FlowEntryMatch flowEntryMatch;	// The Flow Entry Match
     private ArrayList<FlowEntryAction> flowEntryActions; // The Flow Entry Actions
     private Dpid dpid;				// The Switch DPID
-    private Port inPort;			// The Switch incoming port
-    private Port outPort;			// The Switch outgoing port
+    private Port inPort;		// The Switch incoming port. Used only
+					// when the entry is used to return
+					// Shortest Path computation.
+    private Port outPort;		// The Switch outgoing port. Used only
+					// when the entry is used to return
+					// Shortest Path computation.
     private FlowEntryUserState flowEntryUserState; // The Flow Entry User state
     private FlowEntrySwitchState flowEntrySwitchState; // The Flow Entry Switch state
     // The Flow Entry Error state (if FlowEntrySwitchState is FE_SWITCH_FAILED)
diff --git a/src/main/java/net/floodlightcontroller/util/FlowPath.java b/src/main/java/net/floodlightcontroller/util/FlowPath.java
index 11f23fe..7fcb2e6 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowPath.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowPath.java
@@ -9,7 +9,7 @@
 /**
  * The class representing the Flow Path.
  */
-public class FlowPath {
+public class FlowPath implements Comparable<FlowPath> {
     private FlowId flowId;		// The Flow ID
     private CallerId installerId;	// The Caller ID of the path installer
     private DataPath dataPath;		// The data path
@@ -91,4 +91,13 @@
 	ret += "]";
 	return ret;
     }
+    
+    /**
+     * CompareTo method to order flowPath by Id
+     */
+    @Override
+    public int compareTo(FlowPath f) {
+    	return (int) (this.flowId.value() - f.flowId.value());
+    }
+
 }
diff --git a/src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java b/src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java
index d6f3dee..0a7ac5d 100644
--- a/src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java
+++ b/src/main/java/net/onrc/onos/registry/controller/SwitchRegistryResource.java
@@ -26,11 +26,11 @@
 			switches = new HashMap<String, List<ControllerRegistryEntry>>();
 		}
 		
-		for (List<ControllerRegistryEntry> list: switches.values()){
+		/*for (List<ControllerRegistryEntry> list: switches.values()){
 			for (ControllerRegistryEntry en : list) {
 				log.debug("Controller id {}", en.getControllerId());
 			}
-		}
+		}*/
 		
 		return switches;
 	}
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 5f6ef78..b666db7 100644
--- a/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java
+++ b/src/main/java/net/onrc/onos/registry/controller/ZookeeperRegistry.java
@@ -111,7 +111,7 @@
 		@Override
 		public void childEvent(CuratorFramework client,
 				PathChildrenCacheEvent event) throws Exception {
-			log.debug("Root switch path cache got {} event", event.getType());
+			//log.debug("Root switch path cache got {} event", event.getType());
 			
 			String strSwitch = null;
 			if (event.getData() != null){
@@ -158,7 +158,7 @@
 		
 		if (switches.get(dpidStr) != null){
 			log.debug("Already contesting {}, returning", HexString.toHexString(dpid));
-			return;
+			throw new RegistryException("Already contesting control for " + dpidStr);
 		}
 		
 		LeaderLatch latch = new LeaderLatch(client, latchPath, controllerId);
@@ -355,7 +355,8 @@
 					 new ArrayList<ControllerRegistryEntry>(); 
 			
 			if (entry.getValue().getCurrentData().size() < 1){
-				log.info("Switch entry with no leader elections: {}", entry.getKey());
+				//TODO prevent even having the PathChildrenCache in this case
+				//log.info("Switch entry with no leader elections: {}", entry.getKey());
 				continue;
 			}
 			
diff --git a/src/main/java/net/onrc/onos/util/GraphDBConnection.java b/src/main/java/net/onrc/onos/util/GraphDBConnection.java
index 724095b..ee50cd0 100644
--- a/src/main/java/net/onrc/onos/util/GraphDBConnection.java
+++ b/src/main/java/net/onrc/onos/util/GraphDBConnection.java
@@ -85,7 +85,7 @@
 	   }
 	   
 	   public void close() {
-		   
+		   graph.stopTransaction(Conclusion.SUCCESS);
 	   }
 	   
 }
diff --git a/src/main/java/net/onrc/onos/util/GraphDBUtils.java b/src/main/java/net/onrc/onos/util/GraphDBUtils.java
index 097cfa0..ba48103 100644
--- a/src/main/java/net/onrc/onos/util/GraphDBUtils.java
+++ b/src/main/java/net/onrc/onos/util/GraphDBUtils.java
@@ -1,5 +1,8 @@
 package net.onrc.onos.util;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import com.thinkaurelius.titan.core.TitanGraph;
 import com.tinkerpop.blueprints.Vertex;
 import com.tinkerpop.frames.FramedGraph;
@@ -11,12 +14,26 @@
 import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
 import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
+import net.floodlightcontroller.core.ISwitchStorage.SwitchState;
 import net.floodlightcontroller.util.FlowEntryId;
 import net.floodlightcontroller.util.FlowId;
 
 public class GraphDBUtils implements IDBUtils {
+	
+	@Override
+	public ISwitchObject newSwitch(GraphDBConnection conn) {
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		ISwitchObject obj = fg.addVertex(null,ISwitchObject.class);
+		return obj;
+	}
 
 	@Override
+	public void removeSwitch(GraphDBConnection conn, ISwitchObject sw) {
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		fg.removeVertex(sw.asVertex());		
+	}
+	
+	@Override
 	public ISwitchObject searchSwitch(GraphDBConnection conn, String dpid) {
 		// TODO Auto-generated method stub
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
@@ -46,11 +63,24 @@
 	}
 
 	@Override
+	public IPortObject newPort(GraphDBConnection conn) {
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		IPortObject obj = fg.addVertex(null,IPortObject.class);
+		return obj;
+	}
+	
+	@Override
 	public IDeviceObject newDevice(GraphDBConnection conn) {
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
 		IDeviceObject obj = fg.addVertex(null,IDeviceObject.class);
 		return obj;
 	}
+	
+	@Override
+	public void removePort(GraphDBConnection conn, IPortObject port) {
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
+		fg.removeVertex(port.asVertex());		
+	}
 
 	@Override
 	public void removeDevice(GraphDBConnection conn, IDeviceObject dev) {
@@ -136,4 +166,39 @@
 		
 		return fg.getVertices("type", "flow_entry", IFlowEntry.class);
 	}
+
+	@Override
+	public Iterable<ISwitchObject> getActiveSwitches(GraphDBConnection conn) {
+		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);
+			}
+		}
+		return activeSwitches;
+	}
+
+	@Override
+	public Iterable<ISwitchObject> getAllSwitches(GraphDBConnection conn) {
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+		Iterable<ISwitchObject> switches =  fg.getVertices("type","switch",ISwitchObject.class);
+		return switches;
+	}
+
+	@Override
+	public Iterable<ISwitchObject> getInactiveSwitches(GraphDBConnection conn) {
+		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);
+			}
+		}
+		return inactiveSwitches;
+	}
 }
diff --git a/src/main/java/net/onrc/onos/util/IDBUtils.java b/src/main/java/net/onrc/onos/util/IDBUtils.java
index 48d5946..864e227 100644
--- a/src/main/java/net/onrc/onos/util/IDBUtils.java
+++ b/src/main/java/net/onrc/onos/util/IDBUtils.java
@@ -10,6 +10,11 @@
 
 public interface IDBUtils {	
 	public ISwitchObject searchSwitch(GraphDBConnection conn, String dpid);
+	public Iterable<ISwitchObject> getActiveSwitches(GraphDBConnection conn);
+	public Iterable<ISwitchObject> getAllSwitches(GraphDBConnection conn);
+	public Iterable<ISwitchObject> getInactiveSwitches(GraphDBConnection conn);
+	
+
 	public IDeviceObject searchDevice(GraphDBConnection conn, String macAddr);
 	public IDeviceObject newDevice(GraphDBConnection conn);
 	public void removeDevice(GraphDBConnection conn, IDeviceObject dev);
@@ -27,4 +32,8 @@
 	public void removeFlowEntry(GraphDBConnection conn,
 				    IFlowEntry flowEntry);
 	public Iterable<IFlowEntry> getAllFlowEntries(GraphDBConnection conn);
+	public IPortObject newPort(GraphDBConnection conn);
+	ISwitchObject newSwitch(GraphDBConnection conn);
+	void removePort(GraphDBConnection conn, IPortObject port);
+	void removeSwitch(GraphDBConnection conn, ISwitchObject sw);
 }
diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties
index 498fce5..9e4fc02 100644
--- a/src/main/resources/floodlightdefault.properties
+++ b/src/main/resources/floodlightdefault.properties
@@ -2,9 +2,6 @@
 net.floodlightcontroller.core.FloodlightProvider,\
 net.floodlightcontroller.threadpool.ThreadPool,\
 net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl,\
-net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher,\
-net.floodlightcontroller.firewall.Firewall,\
-net.floodlightcontroller.forwarding.Forwarding,\
 net.floodlightcontroller.jython.JythonDebugInterface,\
 net.floodlightcontroller.counter.CounterStore,\
 net.floodlightcontroller.perfmon.PktInProcessingTime,\
@@ -17,3 +14,4 @@
 net.floodlightcontroller.forwarding.Forwarding.idletimeout = 5
 net.floodlightcontroller.forwarding.Forwarding.hardtimeout = 0
 net.floodlightcontroller.onoslistener.OnosPublisher.dbconf = /tmp/cassandra.titan
+net.floodlightcontroller.onoslistener.OnosPublisher.EnableCleanup = True
diff --git a/src/test/java/net/floodlightcontroller/core/internal/SwitchStorageImplTest.java b/src/test/java/net/floodlightcontroller/core/internal/SwitchStorageImplTest.java
index b4a044f..a187d4c 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/SwitchStorageImplTest.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/SwitchStorageImplTest.java
@@ -5,6 +5,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.util.Collection;
+import java.util.List;
 import java.util.ArrayList;
 import java.util.Iterator;
 
@@ -39,7 +41,7 @@
 		titanGraph = TestDatabaseManager.getTestDatabase();
 		TestDatabaseManager.populateTestData(titanGraph);
 		
-		switchStorage = new TestableSwitchStorageImpl(titanGraph);
+		switchStorage = new TestableSwitchStorageImpl();
 	}
 
 	@After
@@ -161,7 +163,7 @@
 	    }
 	    public Boolean compute(LoopBundle<Vertex> bundle) {
 		Boolean output = false;
-		if (bundle.getObject().getProperty("dpid") != dpid) {
+		if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
 		    output = true;
 		}
 		return output;
@@ -181,10 +183,6 @@
 	    //   results = []; v_src.as("x").out("on").out("link").in("on").dedup().loop("x"){it.object.dpid != v_dest.dpid}.path().fill(results)
 	    //
 
-	    String gremlin = "v_src.as(\"x\").out(\"on\").out(\"link\").in(\"on\").dedup().loop(\"x\"){it.object.dpid != v_dest.dpid}.path().fill(results)";
-
-	    String gremlin_nopath = "v_src.as(\"x\").out(\"on\").out(\"link\").in(\"on\").dedup().loop(\"x\"){it.object.dpid != \"NO-SUCH-DPID\"}.path().fill(results)";
-
 	    // Get the source vertex
 	    Iterator<Vertex> iter = titanGraph.getVertices("dpid", dpid_src).iterator();
 	    if (! iter.hasNext())
@@ -196,12 +194,19 @@
 	    if (! iter.hasNext())
 		return;			// Destination vertex not found
 	    Vertex v_dest = iter.next();
-	
+
 	    //
 	    // Implement the Gremlin script and run it
 	    //
-	    ScriptEngine engine = new GremlinGroovyScriptEngine();
+	    // NOTE: This mechanism is slower. The code is kept here
+	    // for future reference.
+	    //
+	    /*
+	    String gremlin = "v_src.as(\"x\").out(\"on\").out(\"link\").in(\"on\").dedup().loop(\"x\"){it.object.dpid != v_dest.dpid}.path().fill(results)";
 
+	    String gremlin_nopath = "v_src.as(\"x\").out(\"on\").out(\"link\").in(\"on\").dedup().loop(\"x\"){it.object.dpid != \"NO-SUCH-DPID\"}.path().fill(results)";
+
+	    ScriptEngine engine = new GremlinGroovyScriptEngine();
 	    ArrayList<ArrayList<Vertex>> results = new ArrayList<ArrayList<Vertex>>();
 	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("g", titanGraph);
 	    engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_src", v_src);
@@ -215,14 +220,26 @@
 		return;
 	    }
 
+	    for (ArrayList<Vertex> lv : results) {
+		...
+	    }
+	    */
+
+	    MyLoopFunction whileFunction = new MyLoopFunction(dpid_dest);
+	    GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
+	    Collection<List> results = new ArrayList<List>();
+	    GremlinPipeline<Vertex, List> path;
+	    path = pipe.start(v_src).as("x").out("on").out("link").in("on").dedup().loop("x", whileFunction).path();
+	    path.fill(results);
+
 	    //
 	    // Extract the result and compose it into a string
 	    //
 	    String results_str = "";
 	    // System.out.println("BEGIN " + results.size());
-	    for (ArrayList<Vertex> lv : results) {
-		// System.out.println(lv);
-		for (Vertex v: lv) {
+	    for (List l : results) {
+		for (Object o: l) {
+		    Vertex v = (Vertex)(o);
 		    // System.out.println(v);
 		    String type = v.getProperty("type").toString();
 		    results_str += "[type: " + type;
@@ -241,35 +258,21 @@
 	    }
 	    // System.out.println("END\n");
 	    System.out.println(results_str);
-	    
+
+	    //
+	    // Check the result
+	    //
 	    String expected_result = "[type: switch dpid: 00:00:00:00:00:00:0a:01][type: port number: 2][type: port number: 1][type: switch dpid: 00:00:00:00:00:00:0a:03][type: port number: 2][type: port number: 2][type: switch dpid: 00:00:00:00:00:00:0a:04][type: port number: 3][type: port number: 1][type: switch dpid: 00:00:00:00:00:00:0a:06]";
 
-
-	    // Pipe<Vertex, Vertex> pipe = Gremlin.compile(gremlin);
-	    // pipe.setStarts(new SingleIterator<Vertex>(v1));
-
-	    //
-	    // XXX: An alternative (faster?) solution that fails to compile
-	    //
-	    // MyLoopFunction whileFunction = new MyLoopFunction(dpid_dest);
-	    // GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
-	    // ArrayList<ArrayList<Vertex>> results2 = new ArrayList<ArrayList<Vertex>>();
-	    // TODO: The statement below doesn't compile
-	    // pipe.start(v_src).as("x").out("on").out("link").in("on").dedup().loop("x", whileFunction).path().fill(results2);
-
-	    // Check the result
 	    assertEquals(results_str, expected_result);
 
 	    //
 	    // Test Shortest-Path computation to non-existing destination
 	    //
 	    results.clear();
-	    try {
-		engine.eval(gremlin_nopath);
-	    } catch (ScriptException e) {
-		System.err.println("Caught ScriptException running Gremlin script: " + e.getMessage());
-		return;
-	    }
+	    MyLoopFunction noDestWhileFunction = new MyLoopFunction("NO-SUCH-DPID");
+	    path = pipe.start(v_src).as("x").out("on").out("link").in("on").dedup().loop("x", noDestWhileFunction).path();
+	    path.fill(results);
 	    assertTrue(results.size() == 0);
 	}
 }
diff --git a/src/test/java/net/floodlightcontroller/core/internal/TestableSwitchStorageImpl.java b/src/test/java/net/floodlightcontroller/core/internal/TestableSwitchStorageImpl.java
index 0d429e6..73d517f 100644
--- a/src/test/java/net/floodlightcontroller/core/internal/TestableSwitchStorageImpl.java
+++ b/src/test/java/net/floodlightcontroller/core/internal/TestableSwitchStorageImpl.java
@@ -18,21 +18,13 @@
 
 public class TestableSwitchStorageImpl extends SwitchStorageImpl {
 	
-	public TestableSwitchStorageImpl(TitanGraph graph){
-		this.graph = graph;
+	public TestableSwitchStorageImpl(){
 	}
 	
 	@Override
 	public void init(String conf){
-        Set<String> s = graph.getIndexedKeys(Vertex.class);
-        if (!s.contains("dpid")) {
-           graph.createKeyIndex("dpid", Vertex.class);
-           graph.stopTransaction(Conclusion.SUCCESS);
-        }
-        if (!s.contains("type")) {
-        	graph.createKeyIndex("type", Vertex.class);
-        	graph.stopTransaction(Conclusion.SUCCESS);
-        }
+        
+		super.init(conf);
 		
 	}
 }
diff --git a/start-onos.sh b/start-onos.sh
index 166ce74..b8e89e2 100755
--- a/start-onos.sh
+++ b/start-onos.sh
@@ -3,6 +3,7 @@
 # Set paths
 FL_HOME=`dirname $0`
 FL_JAR="${FL_HOME}/target/floodlight.jar"
+FL_ONLY_JAR="${FL_HOME}/target/floodlight-only.jar"
 FL_LOGBACK="${FL_HOME}/logback.xml"
 LOGDIR=${FL_HOME}/onos-logs
 FL_LOG="${LOGDIR}/onos.`hostname`.log"
@@ -19,33 +20,9 @@
 #JVM_OPTS="$JVM_OPTS -Dpython.security.respectJavaAccessibility=false"
 
 # Set classpath to include titan libs
-CLASSPATH=`echo ${FL_HOME}/lib/*.jar ${FL_HOME}/lib/titan/*.jar | sed 's/ /:/g'`
-
-# Create a logback file if required
-cat <<EOF_LOGBACK >${FL_LOGBACK}
-<configuration scan="true" debug="true">
-<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
-<encoder>
-<pattern>%level [%logger:%thread] %msg%n</pattern>
-</encoder>
-</appender>
-
-<appender name="FILE" class="ch.qos.logback.core.FileAppender">
-<file>${FL_LOG}</file>
-<encoder>
-<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
-</encoder>
-</appender>
-
-<logger name="org" level="WARN"/>
-<logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
-<logger name="net.floodlightcontroller.logging" level="WARN"/>
-
-<root level="DEBUG">
-<appender-ref ref="FILE" />
-</root>
-</configuration>
-EOF_LOGBACK
+#CLASSPATH=`echo ${FL_HOME}/lib/*.jar ${FL_HOME}/lib/titan/*.jar | sed 's/ /:/g'`
+CLASSPATH="${FL_ONLY_JAR}:${FL_HOME}/lib/*:${FL_HOME}/lib/titan/*"
+MAIN_CLASS="net.floodlightcontroller.core.Main"
 
 #<logger name="net.floodlightcontroller.linkdiscovery.internal" level="TRACE"/>
 #<appender-ref ref="STDOUT" />
@@ -75,10 +52,39 @@
     fi
   done
 
+# Create a logback file if required
+  cat <<EOF_LOGBACK >${FL_LOGBACK}
+<configuration scan="true" debug="true">
+<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+<encoder>
+<pattern>%level [%logger:%thread] %msg%n</pattern>
+</encoder>
+</appender>
+
+<appender name="FILE" class="ch.qos.logback.core.FileAppender">
+<file>${FL_LOG}</file>
+<encoder>
+<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
+</encoder>
+</appender>
+
+<logger name="org" level="WARN"/>
+<logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
+<logger name="net.floodlightcontroller.logging" level="WARN"/>
+
+<root level="DEBUG">
+<appender-ref ref="FILE" />
+</root>
+</configuration>
+EOF_LOGBACK
+
   # Run floodlight
   echo "Starting ONOS controller ..."
   echo 
-  java ${JVM_OPTS} -Dlogback.configurationFile=${FL_LOGBACK} -jar ${FL_JAR} -cf ${FL_HOME}/onos.properties > /dev/null 2>&1 &
+  #java ${JVM_OPTS} -Dlogback.configurationFile=${FL_LOGBACK} -jar ${FL_JAR} -cf ${FL_HOME}/onos.properties > /dev/null 2>&1 &
+  java ${JVM_OPTS} -Dlogback.configurationFile=${FL_LOGBACK} -cp ${CLASSPATH} ${MAIN_CLASS} -cf ${FL_HOME}/onos.properties > /dev/null 2>&1 &
+
+
 #  echo "java ${JVM_OPTS} -Dlogback.configurationFile=${FL_LOGBACK} -jar ${FL_JAR} -cf ./onos.properties > /dev/null 2>&1 &"
 #  sudo -b /usr/sbin/tcpdump -n -i eth0 -s0 -w ${PCAP_LOG} 'tcp port 6633' > /dev/null  2>&1
 }
diff --git a/start-rest.sh b/start-rest.sh
index 1f801fe..3006e5e 100755
--- a/start-rest.sh
+++ b/start-rest.sh
@@ -52,6 +52,7 @@
 case "$1" in
   start)
     stop
+    sleep 2
     start 
     ;;
   stop)
diff --git a/web/clear_flow.py b/web/clear_flow.py
index 2646498..df6302e 100755
--- a/web/clear_flow.py
+++ b/web/clear_flow.py
@@ -45,7 +45,7 @@
 
 if __name__ == "__main__":
   usage_msg = "Clear flow state from the ONOS Network Map\n"
-  usage_msg = usage_msg + "Usage: %s <flow_id>\n" % (sys.argv[0])
+  usage_msg = usage_msg + "Usage: %s <begin-flow-id> [<end-flow-id>]\n" % (sys.argv[0])
 
   # app.debug = False;
 
@@ -58,7 +58,14 @@
   if len(sys.argv) < 2:
     log_error(usage_msg)
     exit(1)
+  begin_flow_id = int(sys.argv[1], 0)
+  if len(sys.argv) >= 3:
+    end_flow_id = int(sys.argv[2], 0)
+  else:
+    end_flow_id = begin_flow_id
 
   # Do the work
-  flow_id_arg = int(sys.argv[1], 0)
-  clear_flow_path(flow_id_arg);
+  flow_id = begin_flow_id
+  while flow_id <= end_flow_id:
+    clear_flow_path(flow_id)
+    flow_id = flow_id + 1
diff --git a/web/delete_flow.py b/web/delete_flow.py
index f8e037f..6d26548 100755
--- a/web/delete_flow.py
+++ b/web/delete_flow.py
@@ -45,7 +45,7 @@
 
 if __name__ == "__main__":
   usage_msg = "Delete flow state from the ONOS Network Map and the switches\n"
-  usage_msg = usage_msg + "Usage: %s <flow_id>\n" % (sys.argv[0])
+  usage_msg = usage_msg + "Usage: %s <begin-flow-id> [<end-flow-id>]\n" % (sys.argv[0])
 
   # app.debug = False;
 
@@ -58,7 +58,14 @@
   if len(sys.argv) < 2:
     log_error(usage_msg)
     exit(1)
+  begin_flow_id = int(sys.argv[1], 0)
+  if len(sys.argv) >= 3:
+    end_flow_id = int(sys.argv[2], 0)
+  else:
+    end_flow_id = begin_flow_id
 
   # Do the work
-  flow_id_arg = int(sys.argv[1], 0)
-  delete_flow_path(flow_id_arg);
+  flow_id = begin_flow_id
+  while flow_id <= end_flow_id:
+    delete_flow_path(flow_id)
+    flow_id = flow_id + 1
diff --git a/web/generate_flows.py b/web/generate_flows.py
new file mode 100755
index 0000000..953fc03
--- /dev/null
+++ b/web/generate_flows.py
@@ -0,0 +1,81 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+#
+# A script for generating a number of flows.
+#
+# The output of the script should be saved to a file, and the flows from
+# that file should be added by the following command:
+#
+#   web/add_flow.py -f filename
+# 
+# NOTE: Currently, some of the parameters fo the flows are hard-coded,
+# and all flows are between same source and destination DPID and ports
+# (differentiated by different matchSrcMac and matchDstMac).
+#
+
+import copy
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+## Global Var ##
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+
+if __name__ == "__main__":
+  usage_msg = "Usage: %s <begin-flow-id> <end-flow-id>\n" % (sys.argv[0])
+
+  # app.debug = False;
+
+  # Usage info
+  if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
+    print(usage_msg)
+    exit(0)
+
+  # Check arguments
+  if len(sys.argv) < 3:
+    log_error(usage_msg)
+    exit(1)
+
+  # Extract the arguments
+  begin_flow_id = int(sys.argv[1], 0)
+  end_flow_id = int(sys.argv[2], 0)
+  if begin_flow_id > end_flow_id:
+    log_error(usage_msg)
+    exit(1)
+
+  #
+  # Do the work
+  #
+  # NOTE: Currently, up to 65536 flows are supported.
+  # More flows can be supported by iterating by, say, iterating over some of
+  # the other bytes of the autogenereated source/destination MAC addresses.
+  #
+  flow_id = begin_flow_id
+  idx = 0
+  while flow_id <= end_flow_id:
+    mac3 = idx / 255
+    mac4 = idx % 255
+    str_mac3 = "%0.2x" % mac3
+    str_mac4 = "%0.2x" % mac4
+    src_mac = "00:00:" + str_mac3 + ":" + str_mac4 + ":00:00";
+    dst_mac = "00:01:" + str_mac3 + ":" + str_mac4 + ":00:00";
+    print "%s FOOBAR 00:00:00:00:00:00:01:01 1 00:00:00:00:00:00:01:0b 1 matchSrcMac %s matchDstMac %s" % (flow_id, src_mac, dst_mac)
+    flow_id = flow_id + 1
+    idx = idx + 1
diff --git a/web/js/onos-topology.js b/web/js/onos-topology.js
index 6905c3a..cea8f1a 100644
--- a/web/js/onos-topology.js
+++ b/web/js/onos-topology.js
@@ -250,7 +250,7 @@
 	    .attr("y", ".31em")
 	    .text(function(d) { 
 		l=d.name.split(":").length
-		return d.name.split(":")[l-3] + ":" + d.name.split(":")[l-2] + ":" + d.name.split(":")[l-1]
+		return d.name.split(":")[l-2] + ":" + d.name.split(":")[l-1]
 	    });
 
         circle.append("title")
diff --git a/web/rest-test.sh b/web/rest-test.sh
index 241915a..2551f12 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/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"
 
 for url in $urls; do
   echo "---REST CALL---" >> rest.json