Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS

Conflicts:
	start-onos.sh
diff --git a/cluster-mgmt/bin/func.sh b/cluster-mgmt/bin/func.sh
index 05c2adb..9785e66 100755
--- a/cluster-mgmt/bin/func.sh
+++ b/cluster-mgmt/bin/func.sh
@@ -83,6 +83,10 @@
       echo "Removing all data in db"
       dsh -w ${basename}1 "cd $ONOS_DIR; ./scripts/cleanup-cassandra.sh"
       ;;
+    checkdb)
+      echo "Check DB Status"
+      dsh -w ${basename}1 "cd $ONOS_DIR; ./scripts/check-db-status.sh"
+      ;;
     status)
       echo "Checking Cassandra Status"
       dsh -w ${basename}1 "cd $ONOS_DIR; ./start-cassandra.sh status"
diff --git a/cluster-mgmt/bin/start.sh b/cluster-mgmt/bin/start.sh
index dac6bb1..23fcde7 100755
--- a/cluster-mgmt/bin/start.sh
+++ b/cluster-mgmt/bin/start.sh
@@ -9,5 +9,11 @@
 zk start
 cassandra start
 cassandra cleandb
+db_status=`cassandra checkdb |grep OK | wc -l`
+if [ $db_status != 1 ];then
+  echo $db_status
+  echo "Cassandra DB was screwed up. Need DB key drop"
+  exit
+fi
 onos start
 dsh -g $basename 'cd ONOS; ./ctrl-local.sh'
diff --git a/cluster-mgmt/bin/test-link-failure.sh b/cluster-mgmt/bin/test-link-failure.sh
new file mode 100755
index 0000000..6c5f128
--- /dev/null
+++ b/cluster-mgmt/bin/test-link-failure.sh
@@ -0,0 +1,55 @@
+#! /bin/sh
+basename=$ONOS_CLUSTER_BASENAME
+wait=10
+
+fdef="flowdef_8node_42.txt"
+
+function log()
+{
+    date > error.$1.$2.log
+    check_status.py >> error.$1.$2.log
+    dsh -w ${basename}1 "cd ONOS/web; ./get_flow.py all" >> error.$1.$2.log
+    dsh "cd ONOS/scripts; ./showflow.sh"             >> error.$1.$2.log
+}
+
+echo "all links up"
+dsh -w ${basename}1 "cd ONOS/scripts; ./all-linkup.sh"
+echo "clean up flow"
+dsh -w ${basename}1 "cd ONOS/web; ./delete_flow.py 1 100"
+dsh -w ${basename}1 "cd ONOS/web; ./clear_flow.py 1 100"
+sleep 1
+dsh -w ${basename}1 "cd ONOS/web; ./get_flow.py all"
+dsh "cd ONOS/scripts; ./delflow.sh"
+echo "checkup status"
+check_status.py
+read -p "hit anykey> "
+
+echo "install pre-set flows"
+dsh -w ${basename}1 "cd ONOS/web; ./add_flow.py -m onos -f $fdef"
+sleep 6
+echo "check"
+dsh -w ${basename}1 "cd ONOS/web; ./pingall.py $fdef"
+
+#ports=`dsh -w ${basename}1 "cd ONOS/scripts; ./listports.sh" | awk '{print $2}' |grep -v tap`
+operation=("sw3-eth3 down" "sw4-eth4 down" "sw4-eth3 down" "sw3-eth3 up" "sw1-eth2 down" "sw4-eth4 up" "sw4-eth3 up" "sw1-eth2 up")
+
+((n=0))
+while [ 1 ] ; do
+  for (( i = 0; i< ${#operation[@]}; i ++)); do
+    echo "Test $n-$i"
+    p=`echo ${operation[$i]}`
+    echo "operation: $p"
+#  read -p "hit anykey> "
+    dsh -w ${basename}1 "sudo ifconfig $p"
+    echo "wait $wait sec"
+    sleep $wait 
+    result=`dsh -w ${basename}1 "cd ONOS/web; ./pingall.py $fdef"`
+    echo $result
+    nr_fail=`echo $result |grep fail | wc -l`
+    if [ $nr_fail -gt 0 ]; then
+      log $n $i
+    fi
+  done
+  ((n++))
+done
+
diff --git a/cluster-mgmt/template/onsdemo_core.py b/cluster-mgmt/template/onsdemo_core.py
index b9da603..61d2dcc 100755
--- a/cluster-mgmt/template/onsdemo_core.py
+++ b/cluster-mgmt/template/onsdemo_core.py
@@ -51,12 +51,12 @@
 
     def __init__( self, *args, **kwargs ):
         Topo.__init__( self, *args, **kwargs )
-        sw1 = self.addSwitch('sw1', dpid='0000001697089a46')
-        sw2 = self.addSwitch('sw2', dpid='00000000ba5eba11')
-        sw3 = self.addSwitch('sw3', dpid='00000008a208f901')
-        sw4 = self.addSwitch('sw4', dpid='000000000000ba12')
-        sw5 = self.addSwitch('sw5', dpid='00000000ba5eba13')
-        sw6 = self.addSwitch('sw6', dpid='0000204e7f518a35')
+        sw1 = self.addSwitch('sw1', dpid='0000000000000101')
+        sw2 = self.addSwitch('sw2', dpid='0000000000000102')
+        sw3 = self.addSwitch('sw3', dpid='0000000000000103')
+        sw4 = self.addSwitch('sw4', dpid='0000000000000104')
+        sw5 = self.addSwitch('sw5', dpid='0000000000000105')
+        sw6 = self.addSwitch('sw6', dpid='0000000000000106')
 
         host1 = self.addHost( 'host1' )
         host2 = self.addHost( 'host2' )
diff --git a/scripts/all-linkup.sh b/scripts/all-linkup.sh
new file mode 100755
index 0000000..9067012
--- /dev/null
+++ b/scripts/all-linkup.sh
@@ -0,0 +1,16 @@
+#! /bin/bash
+
+controller=`hostname`
+switches=`sudo ovs-vsctl list-br`
+
+function host2ip (){
+   ip=`grep $1 /etc/hosts |grep -v "ip6"|  awk '{print $1}'`
+   echo $ip
+}
+
+for s in $switches; do
+  ports=`sudo ovs-vsctl --pretty list-ports $s`
+  for p in $ports; do
+    sudo ifconfig $p up 
+  done
+done
diff --git a/scripts/check-db-clean b/scripts/check-db-clean
new file mode 100644
index 0000000..e49d267
--- /dev/null
+++ b/scripts/check-db-clean
@@ -0,0 +1,6 @@
+g = TitanFactory.open('cassandra.local')
+g.stopTransaction(SUCCESS);
+g.V('type', 'port').each{println it.type};
+g.V('type', 'switch').each{println it.type};
+g.V('type', 'flow').each{println it.type};
+g.V('type', 'flow_entry').each{println it.type};
diff --git a/scripts/check-db-status.sh b/scripts/check-db-status.sh
new file mode 100755
index 0000000..b81e02d
--- /dev/null
+++ b/scripts/check-db-status.sh
@@ -0,0 +1,8 @@
+#! /bin/bash
+DIR=~/ONOS
+status=`~/titan-0.2.0/bin/gremlin.sh -e $DIR/scripts/check-db-clean | grep null | wc -l`
+if [ $status == 0 ]; then
+  echo "OK"
+else
+  echo "BAD"
+fi
diff --git a/scripts/listports.sh b/scripts/listports.sh
new file mode 100755
index 0000000..792ea37
--- /dev/null
+++ b/scripts/listports.sh
@@ -0,0 +1,13 @@
+#! /bin/bash
+
+controller=`hostname`
+switches=`sudo ovs-vsctl list-br`
+
+function host2ip (){
+   ip=`grep $1 /etc/hosts |grep -v "ip6"|  awk '{print $1}'`
+   echo $ip
+}
+
+for s in $switches; do
+  sudo ovs-vsctl --pretty list-ports $s
+done
diff --git a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
index e72baf7..5264648 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
@@ -42,7 +42,8 @@
 		@Adjacency(label="on")
 		public Iterable<IPortObject> getPorts();
 		
-		@Adjacency(label="on")
+		@JsonIgnore
+		@GremlinGroovy("_().out('on').has('number',portnum)")
 		public IPortObject getPort(final short port_num);
 		
 		@Adjacency(label="on")
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index 098e02f..e84a3e8 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -102,169 +102,17 @@
     private static Logger log = LoggerFactory.getLogger(FlowManager.class);
 
     // The periodic task(s)
-    private final ScheduledExecutorService measureShortestPathScheduler =
-	Executors.newScheduledThreadPool(1);
-    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;
-		}
-
-		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() {
+		long startTime = System.nanoTime();
+		int counterAllFlowEntries = 0;
+		int counterMyNotUpdatedFlowEntries = 0;
+		int counterAllFlowPaths = 0;
+		int counterMyFlowPaths = 0;
+
 		if (floodlightProvider == null) {
 		    log.debug("FloodlightProvider service not found!");
 		    return;
@@ -284,6 +132,7 @@
 		Iterable<IFlowEntry> allFlowEntries =
 		    conn.utils().getAllFlowEntries(conn);
 		for (IFlowEntry flowEntryObj : allFlowEntries) {
+		    counterAllFlowEntries++;
 		    String flowEntryIdStr = flowEntryObj.getFlowEntryId();
 		    String userState = flowEntryObj.getUserState();
 		    String switchState = flowEntryObj.getSwitchState();
@@ -298,14 +147,6 @@
 		    FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
 		    Dpid dpid = new Dpid(dpidStr);
 
-		    /*
-		    log.debug("Found Flow Entry Id = {} {}",
-			      flowEntryId.toString(),
-			      "DPID = " + dpid.toString() +
-			      " User State: " + userState +
-			      " Switch State: " + switchState);
-		    */
-
 		    if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
 			continue;	// Ignore the entry: nothing to do
 
@@ -316,11 +157,15 @@
 		    myFlowEntries.put(flowEntryId.value(), flowEntryObj);
 		}
 
+		log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
+			  myFlowEntries.size());
+
 		//
 		// Process my Flow Entries
 		//
 		boolean processed_measurement_flow = false;
 		for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
+		    counterMyNotUpdatedFlowEntries++;
 		    IFlowEntry flowEntryObj = entry.getValue();
 		    IFlowPath flowObj =
 			conn.utils().getFlowPathByFlowEntry(conn,
@@ -329,11 +174,14 @@
 			continue;		// Should NOT happen
 
 		    // Code for measurement purpose
+		    // TODO: Commented-out for now
+		    /*
 		    {
 			if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
 			    processed_measurement_flow = true;
 			}
 		    }
+		    */
 
 		    //
 		    // TODO: Eliminate the re-fetching of flowEntryId,
@@ -477,6 +325,9 @@
 		    }
 		}
 
+		log.debug("MEASUREMENT: Found {} Flow Entries to delete",
+			  deleteFlowEntries.size());
+
 		//
 		// Delete all entries marked for deletion
 		//
@@ -514,15 +365,11 @@
 		// Fetch and recompute the Shortest Path for those
 		// Flow Paths this controller is responsible for.
 		//
-
-		/*
-		 * TODO: For now, the computation of the reconciliation is
-		 * commented-out.
-		 */
 		topoRouteService.prepareShortestPathTopo();
 		Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
 		HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
 		for (IFlowPath flowPathObj : allFlowPaths) {
+		    counterAllFlowPaths++;
 		    if (flowPathObj == null)
 			continue;
 		    String dataPathSummaryStr = flowPathObj.getDataPathSummary();
@@ -553,6 +400,21 @@
 		    Port dstPort = new Port(dstPortShort);
 		    SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
 		    SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
+
+		    //
+		    // Use the source DPID as a heuristic to decide
+		    // which controller is responsible for maintaining the
+		    // shortest path.
+		    // NOTE: This heuristic is error-prone: if the switch
+		    // goes away and no controller is responsible for that
+		    // switch, then the original Flow Path is not cleaned-up
+		    //
+		    IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
+		    if (mySwitch == null)
+			continue;	// Ignore: not my responsibility
+
+		    counterMyFlowPaths++;
+
 		    //
 		    // NOTE: Using here the regular getShortestPath() method
 		    // won't work here, because that method calls internally
@@ -576,22 +438,12 @@
 		    if (dataPathSummaryStr.equals(newDataPathSummaryStr))
 			continue;	// Nothing changed
 
-		    //
-		    // Use the source DPID as a heuristic to decide
-		    // which controller is responsible for maintaining the
-		    // shortest path.
-		    // NOTE: This heuristic is error-prone: if the switch
-		    // goes away and no controller is responsible for that
-		    // switch, then the original Flow Path is not cleaned-up
-		    //
-		    IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
-		    if (mySwitch == null)
-			continue;	// Ignore: not my responsibility
-
 		    log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
 			      flowId.toString());
 		    flowObjSet.add(flowPathObj);
 		}
+		log.debug("MEASUREMENT: Found {} Flows to reconcile",
+			  flowObjSet.size());
 		reconcileFlows(flowObjSet);
 		topoRouteService.dropShortestPathTopo();
 
@@ -604,19 +456,14 @@
 			(double)estimatedTime / 1000000000 + " sec";
 		    log.debug(logMsg);
 		}
+
+		long estimatedTime = System.nanoTime() - startTime;
+		double rate = (estimatedTime > 0)? ((double)counterAllFlowPaths * 1000000000) / estimatedTime: 0.0;
+		String logMsg = "MEASUREMENT: Processed AllFlowEntries: " + counterAllFlowEntries + " MyNotUpdatedFlowEntries: " + counterMyNotUpdatedFlowEntries + " AllFlowPaths: " + counterAllFlowPaths + " MyFlowPaths: " + counterMyFlowPaths + " in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " paths/s";
+		log.debug(logMsg);
 	    }
 	};
 
-    /*
-    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);
 
@@ -720,9 +567,12 @@
     @Override
     public boolean addFlow(FlowPath flowPath, FlowId flowId,
 			   String dataPathSummaryStr) {
+	/*
+	 * TODO: Commented-out for now
 	if (flowPath.flowId().value() == measurementFlowId) {
 	    modifiedMeasurementFlowTime = System.nanoTime();
 	}
+	*/
 
 	//
 	// Assign the FlowEntry IDs
@@ -937,9 +787,12 @@
      */
     @Override
     public boolean deleteFlow(FlowId flowId) {
+	/*
+	 * TODO: Commented-out for now
 	if (flowId.value() == measurementFlowId) {
 	    modifiedMeasurementFlowTime = System.nanoTime();
 	}
+	*/
 
 	IFlowPath flowObj = null;
 	//
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index 11643fa..634f7eb 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -82,10 +82,7 @@
 import net.floodlightcontroller.topology.NodePortTuple;
 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;
@@ -130,6 +127,12 @@
 IStorageSourceListener, ILinkDiscoveryService,
 IFloodlightModule, IInfoProvider, IHAListener {
     protected static Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
+    
+    protected enum NetworkMapOperation {
+    	NONE,
+    	INSERT,
+    	UPDATE
+    }
 
     // Names of table/fields for links in the storage API
     private static final String LINK_TABLE_NAME = "controller_link";
@@ -183,13 +186,13 @@
     // Link discovery task details.
     protected SingletonTask discoveryTask;
     protected final int DISCOVERY_TASK_INTERVAL = 1; 
-    protected final int LINK_TIMEOUT = 5; // decreased timeout as part of LLDP process from 35 secs
-    protected final int LLDP_TO_ALL_INTERVAL = 2 ; //decreased from 15 seconds.
+    protected final int LINK_TIMEOUT = 35; // original 35 secs, aggressive 5 secs
+    protected final int LLDP_TO_ALL_INTERVAL = 15 ; //original 15 seconds, aggressive 2 secs.
     protected long lldpClock = 0;
     // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL.
     // If we want to identify link failures faster, we could decrease this
     // value to a small number, say 1 or 2 sec.
-    protected final int LLDP_TO_KNOWN_INTERVAL= 2; // LLDP frequency for known links from 20 secs
+    protected final int LLDP_TO_KNOWN_INTERVAL= 20; // LLDP frequency for known links
 
     protected LLDPTLV controllerTLV;
     protected ReentrantReadWriteLock lock;
@@ -1025,6 +1028,7 @@
 
         NodePortTuple srcNpt, dstNpt;
         boolean linkChanged = false;
+        NetworkMapOperation operation = NetworkMapOperation.NONE;
 
         lock.writeLock().lock();
         try {
@@ -1073,7 +1077,8 @@
                 writeLinkToStorage(lt, newInfo);
                 
                 // Write link to network map
-                linkStore.update(lt, newInfo, DM_OPERATION.INSERT);
+                operation = NetworkMapOperation.INSERT;
+                //linkStore.update(lt, newInfo, DM_OPERATION.INSERT);
                 
                 updateOperation = UpdateOperation.LINK_UPDATED;
                 linkChanged = true;
@@ -1132,7 +1137,8 @@
                 writeLinkToStorage(lt, newInfo);
 
                 // Write link to network map
-                linkStore.update(lt, newInfo, DM_OPERATION.UPDATE);
+                operation = NetworkMapOperation.UPDATE;
+                //linkStore.update(lt, newInfo, DM_OPERATION.UPDATE);
                 
                 if (linkChanged) {
                     updateOperation = getUpdateOperation(newInfo.getSrcPortState(),
@@ -1162,6 +1168,18 @@
         } finally {
             lock.writeLock().unlock();
         }
+        
+        switch (operation){
+        case INSERT:
+        	linkStore.update(lt, newInfo, DM_OPERATION.INSERT);
+        	break;
+        case UPDATE:
+        	linkStore.update(lt, newInfo, DM_OPERATION.UPDATE);
+        	break;
+        case NONE:
+        default:
+        	break;
+        }
 
         return linkChanged;
     }
diff --git a/src/main/java/net/onrc/onos/util/GraphDBUtils.java b/src/main/java/net/onrc/onos/util/GraphDBUtils.java
index a3d106c..b0ca23b 100644
--- a/src/main/java/net/onrc/onos/util/GraphDBUtils.java
+++ b/src/main/java/net/onrc/onos/util/GraphDBUtils.java
@@ -57,11 +57,12 @@
 	@Override
 	public IPortObject searchPort(GraphDBConnection conn, String dpid, short number) {
 		ISwitchObject sw = searchSwitch(conn, dpid);
-		GremlinPipeline<Vertex, IPortObject> pipe = new GremlinPipeline<Vertex, IPortObject>();
+		return sw != null ? sw.getPort(number): null;
+	/*	GremlinPipeline<Vertex, IPortObject> pipe = new GremlinPipeline<Vertex, IPortObject>();
 		pipe.start(sw.asVertex());
 	    pipe.out("on").has("number", number);
 	    FramedVertexIterable<IPortObject> r = new FramedVertexIterable<IPortObject>(conn.getFramedGraph(), (Iterable) pipe, IPortObject.class);
-	    return r.iterator().hasNext() ? r.iterator().next() : null;		
+	    return r.iterator().hasNext() ? r.iterator().next() : null;		*/
 	}
 
 	@Override
diff --git a/start-onos.sh b/start-onos.sh
index 3f2213d..1263b8a 100755
--- a/start-onos.sh
+++ b/start-onos.sh
@@ -17,7 +17,7 @@
 JVM_OPTS="$JVM_OPTS -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods"
 JVM_OPTS="$JVM_OPTS -XX:MaxInlineSize=8192 -XX:FreqInlineSize=8192"
 JVM_OPTS="$JVM_OPTS -XX:CompileThreshold=1500 -XX:PreBlockSpin=8"
-JVM_OPTS="$JVM_OPTS -Dpython.security.respectJavaAccessibility=false"
+#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'`
diff --git a/web/ons-demo/RELEASE_NOTES.txt b/web/ons-demo/RELEASE_NOTES.txt
index 8649e9b..916a965 100644
--- a/web/ons-demo/RELEASE_NOTES.txt
+++ b/web/ons-demo/RELEASE_NOTES.txt
@@ -1,3 +1,11 @@
+** April 4, 2013 **
+Fix issues:
+	305 - "close x" now unselects flow. double click to delete a flow
+	323 - gui now recovers on timeout errors and polls again
+	324 - fixed problem with added flows not displaying
+	325 - fixed logic displaying flows in topology view
+
+
 ** March 28, 2013 **
 - add and delete flow implemented
 - to add flow
diff --git a/web/ons-demo/css/skin.default.css b/web/ons-demo/css/skin.default.css
index d88814e..1ce4897 100644
--- a/web/ons-demo/css/skin.default.css
+++ b/web/ons-demo/css/skin.default.css
@@ -366,6 +366,6 @@
 	-webkit-animation-duration: .5s;
 	-webkit-animation-direction: alternate;
 	-webkit-animation-timing-function: ease-in-out;
-	-webkit-animation-iteration-count: 24;
+	-webkit-animation-iteration-count: 70;
 }
 
diff --git a/web/ons-demo/data/configuration.json.dev b/web/ons-demo/data/configuration.json.dev
index 90cad6a..5968375 100644
--- a/web/ons-demo/data/configuration.json.dev
+++ b/web/ons-demo/data/configuration.json.dev
@@ -8,6 +8,7 @@
 		"00:00:00:00:00:00:01:06"
 	],
 	"aggregation": [
+		"00:00:00:00:00:00:01:01",
 		"00:00:00:00:00:00:02:01",
 		"00:00:00:00:00:00:03:01",
 		"00:00:00:00:00:00:04:01",
@@ -18,13 +19,13 @@
 	],
 	"association": {
 		"00:00:00:00:00:00:01:01": [
-			"00:00:00:00:00:00:03:01"
+			"00:00:00:00:00:00:08:01"
 		],
 		"00:00:00:00:00:00:01:02": [
 			"00:00:00:00:00:00:02:01"
 		],
 		"00:00:00:00:00:00:01:03": [
-			"00:00:00:00:00:00:07:01"
+			"00:00:00:00:00:00:03:01"
 		],
 		"00:00:00:00:00:00:01:04": [
 			"00:00:00:00:00:00:04:01",
@@ -34,7 +35,7 @@
 			"00:00:00:00:00:00:06:01"
 		],
 		"00:00:00:00:00:00:01:06": [
-			"00:00:00:00:00:00:08:01"
+			"00:00:00:00:00:00:07:01"
 		]
 	}
 }
\ No newline at end of file
diff --git a/web/ons-demo/js/app.js b/web/ons-demo/js/app.js
index e342213..695e4bb 100644
--- a/web/ons-demo/js/app.js
+++ b/web/ons-demo/js/app.js
@@ -20,7 +20,7 @@
 var pendingLinks = {};
 var selectedFlows = [];
 
-var pendingTimeout = 10000;
+var pendingTimeout = 30000;
 
 var colors = [
 	'color1',
@@ -70,7 +70,14 @@
 
 function updateSelectedFlowsTopology() {
 	// DRAW THE FLOWS
-	var flows = d3.select('svg').selectAll('.flow').data(selectedFlows);
+	var topologyFlows = [];
+	selectedFlows.forEach(function (flow) {
+		if (flow) {
+			topologyFlows.push(flow);
+		}
+	});
+
+	var flows = d3.select('svg').selectAll('.flow').data(topologyFlows);
 
 	flows.enter().append("svg:path").attr('class', 'flow')
 		.attr('stroke-dasharray', '4, 10')
@@ -82,13 +89,14 @@
 		.attr('dur', '20s')
 		.attr('repeatCount', 'indefinite');
 
+	flows.exit().remove();
 
 	flows.attr('d', function (d) {
 			if (!d) {
 				return;
 			}
 			var pts = [];
-			if (!d.dataPath.flowEntries) {
+			if (!d.dataPath.flowEntries || !d.dataPath.flowEntries.length) {
 				// create a temporary vector to indicate the pending flow
 				var s1 = d3.select(document.getElementById(d.dataPath.srcPort.dpid.value));
 				var s2 = d3.select(document.getElementById(d.dataPath.dstPort.dpid.value));
@@ -162,6 +170,10 @@
 	function rowUpdate(d) {
 		var row = d3.select(this);
 		row.select('.deleteFlow').on('click', function () {
+			selectedFlows[selectedFlows.indexOf(d)] = null;
+			updateSelectedFlows();
+		});
+		row.on('dblclick', function () {
 			if (d) {
 				var prompt = 'Delete flow ' + d.flowId.value + '?';
 				if (confirm(prompt)) {
@@ -187,7 +199,9 @@
 					}
 				}
 			})
-			.classed('pending', d && (d.deletePending || d.createPending));
+			.classed('pending', function (d) {
+				return d && (d.createPending || d.deletePending);
+			});
 
 		row.select('.srcDPID')
 			.text(function (d) {
@@ -238,8 +252,6 @@
 				} else if (flow.createPending) {
 					newSelectedFlows.push(flow);
 				}
-			} else {
-				newSelectedFlows.push(null);
 			}
 		});
 		selectedFlows = newSelectedFlows;
@@ -1059,21 +1071,23 @@
 	updateModel(function (newModel) {
 //		console.log('Update time: ' + (Date.now() - d)/1000 + 's');
 
-		var modelChanged = false;
-		if (!model || JSON.stringify(model) != JSON.stringify(newModel)) {
-			modelChanged = true;
-			model = newModel;
-		} else {
-//			console.log('no change');
-		}
+		if (newModel) {
+			var modelChanged = false;
+			if (!model || JSON.stringify(model) != JSON.stringify(newModel)) {
+				modelChanged = true;
+				model = newModel;
+			} else {
+	//			console.log('no change');
+			}
 
-		if (modelChanged) {
-			updateControllers();
-			updateSelectedFlows();
-			updateTopology();
-		}
+			if (modelChanged) {
+				updateControllers();
+				updateSelectedFlows();
+				updateTopology();
+			}
 
-		updateHeader(newModel);
+			updateHeader(newModel);
+		}
 
 		// do it again in 1s
 		setTimeout(function () {
diff --git a/web/ons-demo/js/model.js b/web/ons-demo/js/model.js
index 29859a6..5026bd4 100644
--- a/web/ons-demo/js/model.js
+++ b/web/ons-demo/js/model.js
@@ -126,7 +126,8 @@
 			var model = toD3(results);
 			cb(model);
 		} else {
-			alert(JSON.stringify(err));
+			console.log(JSON.stringify(err));
+			cb(null);
 		}
 	});
 }
diff --git a/web/topology_rest.py b/web/topology_rest.py
index 89a074a..3238656 100755
--- a/web/topology_rest.py
+++ b/web/topology_rest.py
@@ -192,15 +192,15 @@
   resp = Response(result, status=200, mimetype='application/json')
   return resp
 
-@app.route("/wm/flow/getsummary/0/0/json")
-def flows():
+@app.route("/wm/flow/getsummary/<start>/<range>/json")
+def flows(start, range):
   if request.args.get('proxy') == None:
     host = ONOS_LOCAL_HOST
   else:
     host = ONOS_GUI3_HOST
 
   try:
-    command = "curl -s %s/wm/flow/getsummary/0/0/json" % (host)
+    command = "curl -s %s/wm/flow/getsummary/%s/%s/json" % (host, start, range)
 #    print command
     result = os.popen(command).read()
   except:
@@ -813,9 +813,11 @@
 
   flow_nr += 1
   command = "/home/ubuntu/ONOS/web/add_flow.py -m onos %d %s %s %s %s %s matchSrcMac %s matchDstMac %s" % (flow_nr, "dummy", src_dpid, src_port, dst_dpid, dst_port, srcMAC, dstMAC)
+  command1 = "/home/ubuntu/ONOS/web/add_flow.py -m onos %d %s %s %s %s %s matchSrcMac %s matchDstMac %s" % (flow_nr, "dummy", dst_dpid, dst_port, src_dpid, src_port, dstMAC, srcMAC)
   print command
   errcode = os.popen(command).read()
-  return errcode
+  errcode1 = os.popen(command1).read()
+  return errcode+" "+errcode1
 
 #* Delete Flow
 #http://localhost:9000/gui/delflow/<flow_id>
@@ -861,7 +863,7 @@
   print cmd_string
   os.popen(cmd_string)
 
-  return 
+  return cmd_string
 
 #* Get Iperf Throughput
 #http://localhost:9000/gui/iperf/rate/<flow_id>